10Sstevel@tonic-gate /* 20Sstevel@tonic-gate * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved. 30Sstevel@tonic-gate * 40Sstevel@tonic-gate * Redistribution and use in source and binary forms, with or without 50Sstevel@tonic-gate * modification, are permitted provided that the following conditions 60Sstevel@tonic-gate * are met: 70Sstevel@tonic-gate * 1. Redistributions of source code must retain the above copyright 80Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer. 90Sstevel@tonic-gate * 2. Redistributions in binary form must reproduce the above copyright 100Sstevel@tonic-gate * notice, this list of conditions and the following disclaimer in the 110Sstevel@tonic-gate * documentation and/or other materials provided with the distribution. 120Sstevel@tonic-gate * 130Sstevel@tonic-gate * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR 140Sstevel@tonic-gate * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 150Sstevel@tonic-gate * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 160Sstevel@tonic-gate * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 170Sstevel@tonic-gate * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 180Sstevel@tonic-gate * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 190Sstevel@tonic-gate * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 200Sstevel@tonic-gate * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 210Sstevel@tonic-gate * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 220Sstevel@tonic-gate * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 230Sstevel@tonic-gate */ 240Sstevel@tonic-gate /* 254279Sgm149974 * Copyright 2007 Sun Microsystems, Inc. All rights reserved. 260Sstevel@tonic-gate * Use is subject to license terms. 270Sstevel@tonic-gate */ 280Sstevel@tonic-gate 290Sstevel@tonic-gate #include "includes.h" 300Sstevel@tonic-gate 310Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 320Sstevel@tonic-gate 330Sstevel@tonic-gate #ifdef GSSAPI 340Sstevel@tonic-gate #include "auth.h" 350Sstevel@tonic-gate #include "ssh2.h" 360Sstevel@tonic-gate #include "xmalloc.h" 370Sstevel@tonic-gate #include "log.h" 380Sstevel@tonic-gate #include "dispatch.h" 390Sstevel@tonic-gate #include "servconf.h" 400Sstevel@tonic-gate #include "compat.h" 410Sstevel@tonic-gate #include "buffer.h" 420Sstevel@tonic-gate #include "bufaux.h" 430Sstevel@tonic-gate #include "packet.h" 440Sstevel@tonic-gate 450Sstevel@tonic-gate #include <gssapi/gssapi.h> 460Sstevel@tonic-gate #include "ssh-gss.h" 470Sstevel@tonic-gate 480Sstevel@tonic-gate extern ServerOptions options; 490Sstevel@tonic-gate extern u_char *session_id2; 500Sstevel@tonic-gate extern int session_id2_len; 510Sstevel@tonic-gate extern Gssctxt *xxx_gssctxt; 520Sstevel@tonic-gate 530Sstevel@tonic-gate static void userauth_gssapi_finish(Authctxt *authctxt, Gssctxt *gssctxt); 540Sstevel@tonic-gate 550Sstevel@tonic-gate static void 560Sstevel@tonic-gate userauth_gssapi_keyex(Authctxt *authctxt) 570Sstevel@tonic-gate { 580Sstevel@tonic-gate gss_buffer_desc g_mic_data, mic_tok; 590Sstevel@tonic-gate Buffer mic_data; 600Sstevel@tonic-gate OM_uint32 maj_status, min_status; 610Sstevel@tonic-gate 620Sstevel@tonic-gate if (authctxt == NULL || authctxt->method == NULL) 630Sstevel@tonic-gate fatal("No authentication context during gssapi-keyex userauth"); 640Sstevel@tonic-gate 650Sstevel@tonic-gate if (xxx_gssctxt == NULL || xxx_gssctxt->context == GSS_C_NO_CONTEXT) { 660Sstevel@tonic-gate /* fatal()? or return? */ 670Sstevel@tonic-gate debug("No GSS-API context during gssapi-keyex userauth"); 680Sstevel@tonic-gate return; 690Sstevel@tonic-gate } 700Sstevel@tonic-gate 710Sstevel@tonic-gate /* Make data buffer to verify MIC with */ 720Sstevel@tonic-gate buffer_init(&mic_data); 730Sstevel@tonic-gate buffer_put_string(&mic_data, session_id2, session_id2_len); 740Sstevel@tonic-gate buffer_put_char(&mic_data, SSH2_MSG_USERAUTH_REQUEST); 750Sstevel@tonic-gate buffer_put_cstring(&mic_data, authctxt->user); 760Sstevel@tonic-gate buffer_put_cstring(&mic_data, authctxt->service); 770Sstevel@tonic-gate buffer_put_cstring(&mic_data, authctxt->method->name); 780Sstevel@tonic-gate 790Sstevel@tonic-gate g_mic_data.value = buffer_ptr(&mic_data); 800Sstevel@tonic-gate g_mic_data.length = buffer_len(&mic_data); 810Sstevel@tonic-gate 820Sstevel@tonic-gate mic_tok.value=packet_get_string(&mic_tok.length); 830Sstevel@tonic-gate 840Sstevel@tonic-gate maj_status = gss_verify_mic(&min_status, xxx_gssctxt->context, 850Sstevel@tonic-gate &g_mic_data, &mic_tok, NULL); 860Sstevel@tonic-gate 870Sstevel@tonic-gate packet_check_eom(); 880Sstevel@tonic-gate buffer_clear(&mic_data); 890Sstevel@tonic-gate 900Sstevel@tonic-gate if (maj_status != GSS_S_COMPLETE) 910Sstevel@tonic-gate debug2("MIC verification failed, GSSAPI userauth failed"); 920Sstevel@tonic-gate else 930Sstevel@tonic-gate userauth_gssapi_finish(authctxt, xxx_gssctxt); 940Sstevel@tonic-gate 950Sstevel@tonic-gate /* Leave Gssctxt around for ssh_gssapi_cleanup/storecreds() */ 960Sstevel@tonic-gate if (xxx_gssctxt->deleg_creds == GSS_C_NO_CREDENTIAL) 970Sstevel@tonic-gate ssh_gssapi_delete_ctx(&xxx_gssctxt); 980Sstevel@tonic-gate 990Sstevel@tonic-gate return; 1000Sstevel@tonic-gate } 1010Sstevel@tonic-gate 1020Sstevel@tonic-gate static void ssh_gssapi_userauth_error(Gssctxt *ctxt); 1030Sstevel@tonic-gate static void input_gssapi_token(int type, u_int32_t plen, void *ctxt); 1040Sstevel@tonic-gate static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt); 1050Sstevel@tonic-gate static void input_gssapi_errtok(int, u_int32_t, void *); 1060Sstevel@tonic-gate static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt); 1070Sstevel@tonic-gate 1080Sstevel@tonic-gate static void 1090Sstevel@tonic-gate userauth_gssapi_abandon(Authctxt *authctxt, Authmethod *method) 1100Sstevel@tonic-gate { 1110Sstevel@tonic-gate ssh_gssapi_delete_ctx((Gssctxt **)&method->method_data); 1120Sstevel@tonic-gate xxx_gssctxt = NULL; 1130Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL); 1140Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); 1150Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 1160Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); 1170Sstevel@tonic-gate } 1180Sstevel@tonic-gate 1190Sstevel@tonic-gate static void 1200Sstevel@tonic-gate userauth_gssapi(Authctxt *authctxt) 1210Sstevel@tonic-gate { 1220Sstevel@tonic-gate gss_OID_set supported_mechs; 1230Sstevel@tonic-gate int mechs; 1240Sstevel@tonic-gate int present = 0; 1250Sstevel@tonic-gate OM_uint32 min_status; 1260Sstevel@tonic-gate u_int len; 1270Sstevel@tonic-gate char *doid = NULL; 1280Sstevel@tonic-gate gss_OID oid = GSS_C_NULL_OID; 1290Sstevel@tonic-gate 1300Sstevel@tonic-gate if (datafellows & SSH_OLD_GSSAPI) { 1310Sstevel@tonic-gate debug("Early drafts of GSSAPI userauth not supported"); 1320Sstevel@tonic-gate return; 1330Sstevel@tonic-gate } 1340Sstevel@tonic-gate 1350Sstevel@tonic-gate mechs=packet_get_int(); 1360Sstevel@tonic-gate if (mechs==0) { 1370Sstevel@tonic-gate packet_check_eom(); 1380Sstevel@tonic-gate debug("Mechanism negotiation is not supported"); 1390Sstevel@tonic-gate return; 1400Sstevel@tonic-gate } 1410Sstevel@tonic-gate 1420Sstevel@tonic-gate ssh_gssapi_server_mechs(&supported_mechs); 1430Sstevel@tonic-gate 1440Sstevel@tonic-gate do { 1450Sstevel@tonic-gate mechs--; 1460Sstevel@tonic-gate 1470Sstevel@tonic-gate if (oid != GSS_C_NULL_OID) 1480Sstevel@tonic-gate ssh_gssapi_release_oid(&oid); 1490Sstevel@tonic-gate 1500Sstevel@tonic-gate doid = packet_get_string(&len); 1510Sstevel@tonic-gate 1520Sstevel@tonic-gate /* ick */ 1530Sstevel@tonic-gate if (doid[0]!=0x06 || (len > 2 && doid[1]!=len-2)) { 1540Sstevel@tonic-gate log("Mechanism OID received using the old encoding form"); 1550Sstevel@tonic-gate oid = ssh_gssapi_make_oid(len, doid); 1560Sstevel@tonic-gate } else { 1570Sstevel@tonic-gate oid = ssh_gssapi_make_oid(len - 2, doid + 2); 1580Sstevel@tonic-gate } 1590Sstevel@tonic-gate (void) gss_test_oid_set_member(&min_status, oid, 1600Sstevel@tonic-gate supported_mechs, &present); 1610Sstevel@tonic-gate debug("Client offered gssapi userauth with %s (%s)", 1620Sstevel@tonic-gate ssh_gssapi_oid_to_str(oid), 1630Sstevel@tonic-gate present ? "supported" : "unsupported"); 1640Sstevel@tonic-gate } while (!present && (mechs > 0)); 1650Sstevel@tonic-gate 1660Sstevel@tonic-gate if (!present) { 1670Sstevel@tonic-gate /* userauth_finish() will send SSH2_MSG_USERAUTH_FAILURE */ 1680Sstevel@tonic-gate debug2("No mechanism offered by the client is available"); 1690Sstevel@tonic-gate ssh_gssapi_release_oid(&oid); 1700Sstevel@tonic-gate return; 1710Sstevel@tonic-gate } 1720Sstevel@tonic-gate 1730Sstevel@tonic-gate ssh_gssapi_build_ctx((Gssctxt **)&authctxt->method->method_data, 0, oid); 1740Sstevel@tonic-gate ssh_gssapi_release_oid(&oid); 1750Sstevel@tonic-gate /* Send SSH_MSG_USERAUTH_GSSAPI_RESPONSE */ 1760Sstevel@tonic-gate 1770Sstevel@tonic-gate packet_start(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE); 1780Sstevel@tonic-gate 1790Sstevel@tonic-gate /* Just return whatever we found -- the matched mech does us no good */ 1800Sstevel@tonic-gate packet_put_string(doid, len); 1810Sstevel@tonic-gate xfree(doid); 1820Sstevel@tonic-gate 1830Sstevel@tonic-gate packet_send(); 1840Sstevel@tonic-gate packet_write_wait(); 1850Sstevel@tonic-gate 1860Sstevel@tonic-gate /* Setup rest of gssapi userauth conversation */ 1870Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token); 1880Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok); 1890Sstevel@tonic-gate authctxt->method->postponed = 1; 1900Sstevel@tonic-gate 1910Sstevel@tonic-gate return; 1920Sstevel@tonic-gate } 1930Sstevel@tonic-gate 1940Sstevel@tonic-gate static void 1950Sstevel@tonic-gate input_gssapi_token(int type, u_int32_t plen, void *ctxt) 1960Sstevel@tonic-gate { 1970Sstevel@tonic-gate Authctxt *authctxt = ctxt; 1980Sstevel@tonic-gate Gssctxt *gssctxt; 1990Sstevel@tonic-gate gss_buffer_desc send_tok,recv_tok; 2000Sstevel@tonic-gate OM_uint32 maj_status, min_status; 2010Sstevel@tonic-gate u_int len; 2020Sstevel@tonic-gate 2030Sstevel@tonic-gate if (authctxt == NULL || authctxt->method == NULL || 204*5562Sjp161948 (authctxt->method->method_data == NULL)) 2050Sstevel@tonic-gate fatal("No authentication or GSSAPI context during gssapi-with-mic userauth"); 2060Sstevel@tonic-gate 2070Sstevel@tonic-gate gssctxt=authctxt->method->method_data; 2080Sstevel@tonic-gate recv_tok.value=packet_get_string(&len); 2090Sstevel@tonic-gate recv_tok.length=len; /* u_int vs. size_t */ 2100Sstevel@tonic-gate 211*5562Sjp161948 maj_status = ssh_gssapi_accept_ctx(gssctxt, &recv_tok, &send_tok); 2120Sstevel@tonic-gate packet_check_eom(); 2130Sstevel@tonic-gate 2140Sstevel@tonic-gate if (GSS_ERROR(maj_status)) { 2150Sstevel@tonic-gate ssh_gssapi_userauth_error(gssctxt); 2160Sstevel@tonic-gate if (send_tok.length != 0) { 2170Sstevel@tonic-gate packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK); 2180Sstevel@tonic-gate packet_put_string(send_tok.value,send_tok.length); 2190Sstevel@tonic-gate packet_send(); 2200Sstevel@tonic-gate packet_write_wait(); 2210Sstevel@tonic-gate } 2220Sstevel@tonic-gate authctxt->method->postponed = 0; 2230Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 2240Sstevel@tonic-gate userauth_finish(authctxt, authctxt->method->name); 2250Sstevel@tonic-gate } else { 2260Sstevel@tonic-gate if (send_tok.length != 0) { 2270Sstevel@tonic-gate packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN); 2280Sstevel@tonic-gate packet_put_string(send_tok.value,send_tok.length); 2290Sstevel@tonic-gate packet_send(); 2300Sstevel@tonic-gate packet_write_wait(); 2310Sstevel@tonic-gate } 2320Sstevel@tonic-gate if (maj_status == GSS_S_COMPLETE) { 2330Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,NULL); 2340Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, 2350Sstevel@tonic-gate &input_gssapi_mic); 2360Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, 2370Sstevel@tonic-gate &input_gssapi_exchange_complete); 2380Sstevel@tonic-gate } 2390Sstevel@tonic-gate } 2400Sstevel@tonic-gate 2410Sstevel@tonic-gate gss_release_buffer(&min_status, &send_tok); 2420Sstevel@tonic-gate } 2430Sstevel@tonic-gate 2440Sstevel@tonic-gate static void 2450Sstevel@tonic-gate input_gssapi_errtok(int type, u_int32_t plen, void *ctxt) 2460Sstevel@tonic-gate { 2470Sstevel@tonic-gate Authctxt *authctxt = ctxt; 2480Sstevel@tonic-gate Gssctxt *gssctxt; 2490Sstevel@tonic-gate gss_buffer_desc send_tok,recv_tok; 2500Sstevel@tonic-gate 2510Sstevel@tonic-gate if (authctxt == NULL || authctxt->method == NULL || 252*5562Sjp161948 (authctxt->method->method_data == NULL)) 2530Sstevel@tonic-gate fatal("No authentication or GSSAPI context during gssapi-with-mic userauth"); 2540Sstevel@tonic-gate 2550Sstevel@tonic-gate gssctxt=authctxt->method->method_data; 2560Sstevel@tonic-gate recv_tok.value=packet_get_string(&recv_tok.length); 2570Sstevel@tonic-gate packet_check_eom(); 2580Sstevel@tonic-gate 2590Sstevel@tonic-gate /* Push the error token into GSSAPI to see what it says */ 260*5562Sjp161948 (void) ssh_gssapi_accept_ctx(gssctxt, &recv_tok, &send_tok); 2610Sstevel@tonic-gate 2620Sstevel@tonic-gate debug("Client sent GSS-API error token during GSS userauth-- %s", 2630Sstevel@tonic-gate ssh_gssapi_last_error(gssctxt, NULL, NULL)); 2640Sstevel@tonic-gate 2650Sstevel@tonic-gate /* We can't return anything to the client, even if we wanted to */ 2660Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 2670Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK,NULL); 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate 2700Sstevel@tonic-gate /* 2710Sstevel@tonic-gate * The client will have already moved on to the next auth and 2720Sstevel@tonic-gate * will send a new userauth request. The spec says that the 2730Sstevel@tonic-gate * server MUST NOT send a SSH_MSG_USERAUTH_FAILURE packet in 2740Sstevel@tonic-gate * response to this. 2750Sstevel@tonic-gate * 2760Sstevel@tonic-gate * We leave authctxt->method->postponed == 1 here so that a call 2770Sstevel@tonic-gate * to input_userauth_request() will detect this failure (as 2780Sstevel@tonic-gate * userauth abandonment) and act accordingly. 2790Sstevel@tonic-gate */ 2800Sstevel@tonic-gate } 2810Sstevel@tonic-gate 2820Sstevel@tonic-gate static void 2830Sstevel@tonic-gate input_gssapi_mic(int type, u_int32_t plen, void *ctxt) 2840Sstevel@tonic-gate { 2850Sstevel@tonic-gate Authctxt *authctxt = ctxt; 2860Sstevel@tonic-gate Gssctxt *gssctxt; 2870Sstevel@tonic-gate gss_buffer_desc g_mic_data, mic_tok; 2880Sstevel@tonic-gate Buffer mic_data; 2890Sstevel@tonic-gate OM_uint32 maj_status, min_status; 2900Sstevel@tonic-gate 2910Sstevel@tonic-gate if (authctxt == NULL || authctxt->method == NULL || 2920Sstevel@tonic-gate (authctxt->method->method_data == NULL)) { 2930Sstevel@tonic-gate debug3("No authentication or GSSAPI context during gssapi-with-mic userauth"); 2940Sstevel@tonic-gate return; 2950Sstevel@tonic-gate } 2960Sstevel@tonic-gate 2970Sstevel@tonic-gate gssctxt=authctxt->method->method_data; 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate /* Make data buffer to verify MIC with */ 3000Sstevel@tonic-gate buffer_init(&mic_data); 3010Sstevel@tonic-gate buffer_put_string(&mic_data, session_id2, session_id2_len); 3020Sstevel@tonic-gate buffer_put_char(&mic_data, SSH2_MSG_USERAUTH_REQUEST); 3030Sstevel@tonic-gate buffer_put_cstring(&mic_data, authctxt->user); 3040Sstevel@tonic-gate buffer_put_cstring(&mic_data, authctxt->service); 3050Sstevel@tonic-gate buffer_put_cstring(&mic_data, authctxt->method->name); 3060Sstevel@tonic-gate 3070Sstevel@tonic-gate g_mic_data.value = buffer_ptr(&mic_data); 3080Sstevel@tonic-gate g_mic_data.length = buffer_len(&mic_data); 3090Sstevel@tonic-gate 3100Sstevel@tonic-gate mic_tok.value=packet_get_string(&mic_tok.length); 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate maj_status = gss_verify_mic(&min_status, gssctxt->context, 3130Sstevel@tonic-gate &g_mic_data, &mic_tok, NULL); 3140Sstevel@tonic-gate 3150Sstevel@tonic-gate packet_check_eom(); 3160Sstevel@tonic-gate buffer_free(&mic_data); 3170Sstevel@tonic-gate 3180Sstevel@tonic-gate if (maj_status != GSS_S_COMPLETE) 3190Sstevel@tonic-gate debug2("MIC verification failed, GSSAPI userauth failed"); 3200Sstevel@tonic-gate else 3210Sstevel@tonic-gate userauth_gssapi_finish(authctxt, gssctxt); 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate /* Delete context from keyex */ 3240Sstevel@tonic-gate if (xxx_gssctxt != gssctxt) 3250Sstevel@tonic-gate ssh_gssapi_delete_ctx(&xxx_gssctxt); 3260Sstevel@tonic-gate 3270Sstevel@tonic-gate /* Leave Gssctxt around for ssh_gssapi_cleanup/storecreds() */ 3280Sstevel@tonic-gate if (gssctxt->deleg_creds == GSS_C_NO_CREDENTIAL) 3290Sstevel@tonic-gate ssh_gssapi_delete_ctx(&gssctxt); 3300Sstevel@tonic-gate 3310Sstevel@tonic-gate xxx_gssctxt = gssctxt; 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate authctxt->method->postponed = 0; 3340Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 3350Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); 3360Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL); 3370Sstevel@tonic-gate userauth_finish(authctxt, authctxt->method->name); 3380Sstevel@tonic-gate } 3390Sstevel@tonic-gate 3400Sstevel@tonic-gate /* This is called when the client thinks we've completed authentication. 3410Sstevel@tonic-gate * It should only be enabled in the dispatch handler by the function above, 3420Sstevel@tonic-gate * which only enables it once the GSSAPI exchange is complete. 3430Sstevel@tonic-gate */ 3440Sstevel@tonic-gate static void 3450Sstevel@tonic-gate input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt) 3460Sstevel@tonic-gate { 3470Sstevel@tonic-gate Authctxt *authctxt = ctxt; 3480Sstevel@tonic-gate Gssctxt *gssctxt; 3490Sstevel@tonic-gate 3500Sstevel@tonic-gate packet_check_eom(); 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate if (authctxt == NULL || authctxt->method == NULL || 353*5562Sjp161948 (authctxt->method->method_data == NULL)) 3540Sstevel@tonic-gate fatal("No authentication or GSSAPI context"); 3550Sstevel@tonic-gate 3560Sstevel@tonic-gate gssctxt=authctxt->method->method_data; 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate /* 3590Sstevel@tonic-gate * SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE -> gssapi userauth 3600Sstevel@tonic-gate * failure, the client should use SSH2_MSG_USERAUTH_GSSAPI_MIC 3610Sstevel@tonic-gate * instead. 3620Sstevel@tonic-gate * 3630Sstevel@tonic-gate * There's two reasons for this: 3640Sstevel@tonic-gate * 3650Sstevel@tonic-gate * 1) we don't have GSS mechs that don't support integrity 3660Sstevel@tonic-gate * protection, and even if we did we'd not want to use them with 3670Sstevel@tonic-gate * SSHv2, and, 3680Sstevel@tonic-gate * 3690Sstevel@tonic-gate * 2) we currently have no way to dynamically detect whether a 3700Sstevel@tonic-gate * given mechanism does or does not support integrity 3710Sstevel@tonic-gate * protection, so when a context's flags do not indicate 3720Sstevel@tonic-gate * integrity protection we can't know if the client simply 3730Sstevel@tonic-gate * didn't request it, so we assume it didn't and reject the 3740Sstevel@tonic-gate * userauth. 3750Sstevel@tonic-gate * 3760Sstevel@tonic-gate * We could fail partially (i.e., force the use of other 3770Sstevel@tonic-gate * userauth methods without counting this one as failed). But 3780Sstevel@tonic-gate * this will do for now. 3790Sstevel@tonic-gate */ 3800Sstevel@tonic-gate #if 0 381*5562Sjp161948 authctxt->method->authenticated = ssh_gssapi_userok(gssctxt, authctxt->user); 3820Sstevel@tonic-gate #endif 3830Sstevel@tonic-gate 3840Sstevel@tonic-gate if (xxx_gssctxt != gssctxt) 3850Sstevel@tonic-gate ssh_gssapi_delete_ctx(&gssctxt); 3860Sstevel@tonic-gate ssh_gssapi_delete_ctx(&gssctxt); 3870Sstevel@tonic-gate authctxt->method->postponed = 0; 3880Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 3890Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); 3900Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL); 3910Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); 3920Sstevel@tonic-gate userauth_finish(authctxt, authctxt->method->name); 3930Sstevel@tonic-gate } 3940Sstevel@tonic-gate 3950Sstevel@tonic-gate static void ssh_gssapi_userauth_error(Gssctxt *ctxt) { 3960Sstevel@tonic-gate char *errstr; 3970Sstevel@tonic-gate OM_uint32 maj,min; 3980Sstevel@tonic-gate 3990Sstevel@tonic-gate errstr=ssh_gssapi_last_error(ctxt,&maj,&min); 4000Sstevel@tonic-gate if (errstr) { 4010Sstevel@tonic-gate packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERROR); 4020Sstevel@tonic-gate packet_put_int(maj); 4030Sstevel@tonic-gate packet_put_int(min); 4040Sstevel@tonic-gate packet_put_cstring(errstr); 4050Sstevel@tonic-gate packet_put_cstring(""); 4060Sstevel@tonic-gate packet_send(); 4070Sstevel@tonic-gate packet_write_wait(); 4080Sstevel@tonic-gate xfree(errstr); 4090Sstevel@tonic-gate } 4100Sstevel@tonic-gate } 4110Sstevel@tonic-gate 4120Sstevel@tonic-gate /* 4130Sstevel@tonic-gate * Code common to gssapi-keyex and gssapi-with-mic userauth. 4140Sstevel@tonic-gate * 4150Sstevel@tonic-gate * Does authorization, figures out how to store delegated creds. 4160Sstevel@tonic-gate */ 4170Sstevel@tonic-gate static 4180Sstevel@tonic-gate void 4190Sstevel@tonic-gate userauth_gssapi_finish(Authctxt *authctxt, Gssctxt *gssctxt) 4200Sstevel@tonic-gate { 4210Sstevel@tonic-gate char *local_user = NULL; 4224279Sgm149974 gss_buffer_desc dispname; 4234279Sgm149974 OM_uint32 major; 4240Sstevel@tonic-gate 4250Sstevel@tonic-gate if (*authctxt->user != '\0' && 426*5562Sjp161948 ssh_gssapi_userok(gssctxt, authctxt->user)) { 4270Sstevel@tonic-gate 4280Sstevel@tonic-gate /* 4290Sstevel@tonic-gate * If the client princ did not map to the requested 4300Sstevel@tonic-gate * username then we don't want to clobber existing creds 4310Sstevel@tonic-gate * for the user with the delegated creds. 4320Sstevel@tonic-gate */ 4330Sstevel@tonic-gate local_user = ssh_gssapi_localname(gssctxt); 4340Sstevel@tonic-gate if (local_user == NULL || 4350Sstevel@tonic-gate strcmp(local_user, authctxt->user) == 0) 4360Sstevel@tonic-gate gssctxt->default_creds = 1; /* store creds as default */ 4370Sstevel@tonic-gate 4380Sstevel@tonic-gate authctxt->method->authenticated = 4390Sstevel@tonic-gate do_pam_non_initial_userauth(authctxt); 4400Sstevel@tonic-gate 4410Sstevel@tonic-gate } else if (*authctxt->user == '\0') { 4420Sstevel@tonic-gate /* Requested username == ""; derive username from princ name */ 4430Sstevel@tonic-gate if ((local_user = ssh_gssapi_localname(gssctxt)) == NULL) 4440Sstevel@tonic-gate return; 4450Sstevel@tonic-gate 4460Sstevel@tonic-gate /* Changed username (from implicit, '') */ 4470Sstevel@tonic-gate userauth_user_svc_change(authctxt, local_user, NULL); 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate gssctxt->default_creds = 1; /* store creds as default */ 4500Sstevel@tonic-gate 4510Sstevel@tonic-gate authctxt->method->authenticated = 4520Sstevel@tonic-gate do_pam_non_initial_userauth(authctxt); 4530Sstevel@tonic-gate } 4540Sstevel@tonic-gate 4550Sstevel@tonic-gate if (local_user != NULL) 4560Sstevel@tonic-gate xfree(local_user); 4574279Sgm149974 4584279Sgm149974 if (*authctxt->user != '\0' && authctxt->method->authenticated != 0) { 4594279Sgm149974 major = gss_display_name(&gssctxt->minor, gssctxt->src_name, 4604279Sgm149974 &dispname, NULL); 4614279Sgm149974 if (major == GSS_S_COMPLETE) { 4624279Sgm149974 log("Authorized principal %.*s, authenticated with " 4634279Sgm149974 "GSS mechanism %s, to: %s", 4644279Sgm149974 dispname.length, (char *)dispname.value, 4654279Sgm149974 ssh_gssapi_oid_to_name(gssctxt->actual_mech), 4664279Sgm149974 authctxt->user); 4674279Sgm149974 } 4684279Sgm149974 (void) gss_release_buffer(&gssctxt->minor, &dispname); 4694279Sgm149974 } 4700Sstevel@tonic-gate } 4710Sstevel@tonic-gate 4720Sstevel@tonic-gate #if 0 4730Sstevel@tonic-gate /* Deprecated userauths -- should not be enabled */ 4740Sstevel@tonic-gate Authmethod method_external = { 4750Sstevel@tonic-gate "external-keyx", 4760Sstevel@tonic-gate &options.gss_authentication, 4770Sstevel@tonic-gate userauth_gssapi_keyex, 4780Sstevel@tonic-gate NULL, /* no abandon function */ 4790Sstevel@tonic-gate NULL, 4800Sstevel@tonic-gate NULL, 4810Sstevel@tonic-gate /* State counters */ 4820Sstevel@tonic-gate 0, 0, 0, 0, 4830Sstevel@tonic-gate /* State flags */ 4840Sstevel@tonic-gate 0, 0, 0, 0, 0, 0 4850Sstevel@tonic-gate }; 4860Sstevel@tonic-gate 4870Sstevel@tonic-gate Authmethod method_gssapi = { 4880Sstevel@tonic-gate "gssapi", 4890Sstevel@tonic-gate &options.gss_authentication, 4900Sstevel@tonic-gate userauth_gssapi, 4910Sstevel@tonic-gate userauth_gssapi_abandon, 4920Sstevel@tonic-gate NULL, 4930Sstevel@tonic-gate NULL, 4940Sstevel@tonic-gate /* State counters */ 4950Sstevel@tonic-gate 0, 0, 0, 0, 4960Sstevel@tonic-gate /* State flags */ 4970Sstevel@tonic-gate 0, 0, 0, 0, 0, 0 4980Sstevel@tonic-gate }; 4990Sstevel@tonic-gate #endif 5000Sstevel@tonic-gate 5010Sstevel@tonic-gate Authmethod method_external = { 5020Sstevel@tonic-gate "gssapi-keyex", 5030Sstevel@tonic-gate &options.gss_authentication, 5040Sstevel@tonic-gate userauth_gssapi_keyex, 5050Sstevel@tonic-gate NULL, /* no abandon function */ 5060Sstevel@tonic-gate NULL, 5070Sstevel@tonic-gate NULL, 5080Sstevel@tonic-gate /* State counters */ 5090Sstevel@tonic-gate 0, 0, 0, 0, 5100Sstevel@tonic-gate /* State flags */ 5110Sstevel@tonic-gate 0, 0, 0, 0, 0, 0 5120Sstevel@tonic-gate }; 5130Sstevel@tonic-gate 5140Sstevel@tonic-gate Authmethod method_gssapi = { 5150Sstevel@tonic-gate "gssapi-with-mic", 5160Sstevel@tonic-gate &options.gss_authentication, 5170Sstevel@tonic-gate userauth_gssapi, 5180Sstevel@tonic-gate userauth_gssapi_abandon, 5190Sstevel@tonic-gate NULL, 5200Sstevel@tonic-gate NULL, 5210Sstevel@tonic-gate /* State counters */ 5220Sstevel@tonic-gate 0, 0, 0, 0, 5230Sstevel@tonic-gate /* State flags */ 5240Sstevel@tonic-gate 0, 0, 0, 0, 0, 0 5250Sstevel@tonic-gate }; 5260Sstevel@tonic-gate 5270Sstevel@tonic-gate #endif /* GSSAPI */ 528