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 /* 25*4279Sgm149974 * 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 #include "monitor_wrap.h" 450Sstevel@tonic-gate 460Sstevel@tonic-gate #include <gssapi/gssapi.h> 470Sstevel@tonic-gate #include "ssh-gss.h" 480Sstevel@tonic-gate 490Sstevel@tonic-gate extern ServerOptions options; 500Sstevel@tonic-gate extern u_char *session_id2; 510Sstevel@tonic-gate extern int session_id2_len; 520Sstevel@tonic-gate extern Gssctxt *xxx_gssctxt; 530Sstevel@tonic-gate 540Sstevel@tonic-gate static void userauth_gssapi_finish(Authctxt *authctxt, Gssctxt *gssctxt); 550Sstevel@tonic-gate 560Sstevel@tonic-gate static void 570Sstevel@tonic-gate userauth_gssapi_keyex(Authctxt *authctxt) 580Sstevel@tonic-gate { 590Sstevel@tonic-gate gss_buffer_desc g_mic_data, mic_tok; 600Sstevel@tonic-gate Buffer mic_data; 610Sstevel@tonic-gate OM_uint32 maj_status, min_status; 620Sstevel@tonic-gate 630Sstevel@tonic-gate if (authctxt == NULL || authctxt->method == NULL) 640Sstevel@tonic-gate fatal("No authentication context during gssapi-keyex userauth"); 650Sstevel@tonic-gate 660Sstevel@tonic-gate if (xxx_gssctxt == NULL || xxx_gssctxt->context == GSS_C_NO_CONTEXT) { 670Sstevel@tonic-gate /* fatal()? or return? */ 680Sstevel@tonic-gate debug("No GSS-API context during gssapi-keyex userauth"); 690Sstevel@tonic-gate return; 700Sstevel@tonic-gate } 710Sstevel@tonic-gate 720Sstevel@tonic-gate /* Make data buffer to verify MIC with */ 730Sstevel@tonic-gate buffer_init(&mic_data); 740Sstevel@tonic-gate buffer_put_string(&mic_data, session_id2, session_id2_len); 750Sstevel@tonic-gate buffer_put_char(&mic_data, SSH2_MSG_USERAUTH_REQUEST); 760Sstevel@tonic-gate buffer_put_cstring(&mic_data, authctxt->user); 770Sstevel@tonic-gate buffer_put_cstring(&mic_data, authctxt->service); 780Sstevel@tonic-gate buffer_put_cstring(&mic_data, authctxt->method->name); 790Sstevel@tonic-gate 800Sstevel@tonic-gate g_mic_data.value = buffer_ptr(&mic_data); 810Sstevel@tonic-gate g_mic_data.length = buffer_len(&mic_data); 820Sstevel@tonic-gate 830Sstevel@tonic-gate mic_tok.value=packet_get_string(&mic_tok.length); 840Sstevel@tonic-gate 850Sstevel@tonic-gate maj_status = gss_verify_mic(&min_status, xxx_gssctxt->context, 860Sstevel@tonic-gate &g_mic_data, &mic_tok, NULL); 870Sstevel@tonic-gate 880Sstevel@tonic-gate packet_check_eom(); 890Sstevel@tonic-gate buffer_clear(&mic_data); 900Sstevel@tonic-gate 910Sstevel@tonic-gate if (maj_status != GSS_S_COMPLETE) 920Sstevel@tonic-gate debug2("MIC verification failed, GSSAPI userauth failed"); 930Sstevel@tonic-gate else 940Sstevel@tonic-gate userauth_gssapi_finish(authctxt, xxx_gssctxt); 950Sstevel@tonic-gate 960Sstevel@tonic-gate /* Leave Gssctxt around for ssh_gssapi_cleanup/storecreds() */ 970Sstevel@tonic-gate if (xxx_gssctxt->deleg_creds == GSS_C_NO_CREDENTIAL) 980Sstevel@tonic-gate ssh_gssapi_delete_ctx(&xxx_gssctxt); 990Sstevel@tonic-gate 1000Sstevel@tonic-gate return; 1010Sstevel@tonic-gate } 1020Sstevel@tonic-gate 1030Sstevel@tonic-gate static void ssh_gssapi_userauth_error(Gssctxt *ctxt); 1040Sstevel@tonic-gate static void input_gssapi_token(int type, u_int32_t plen, void *ctxt); 1050Sstevel@tonic-gate static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt); 1060Sstevel@tonic-gate static void input_gssapi_errtok(int, u_int32_t, void *); 1070Sstevel@tonic-gate static void input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt); 1080Sstevel@tonic-gate 1090Sstevel@tonic-gate static void 1100Sstevel@tonic-gate userauth_gssapi_abandon(Authctxt *authctxt, Authmethod *method) 1110Sstevel@tonic-gate { 1120Sstevel@tonic-gate ssh_gssapi_delete_ctx((Gssctxt **)&method->method_data); 1130Sstevel@tonic-gate xxx_gssctxt = NULL; 1140Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL); 1150Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); 1160Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 1170Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); 1180Sstevel@tonic-gate } 1190Sstevel@tonic-gate 1200Sstevel@tonic-gate static void 1210Sstevel@tonic-gate userauth_gssapi(Authctxt *authctxt) 1220Sstevel@tonic-gate { 1230Sstevel@tonic-gate gss_OID_set supported_mechs; 1240Sstevel@tonic-gate int mechs; 1250Sstevel@tonic-gate int present = 0; 1260Sstevel@tonic-gate OM_uint32 min_status; 1270Sstevel@tonic-gate u_int len; 1280Sstevel@tonic-gate char *doid = NULL; 1290Sstevel@tonic-gate gss_OID oid = GSS_C_NULL_OID; 1300Sstevel@tonic-gate 1310Sstevel@tonic-gate if (datafellows & SSH_OLD_GSSAPI) { 1320Sstevel@tonic-gate debug("Early drafts of GSSAPI userauth not supported"); 1330Sstevel@tonic-gate return; 1340Sstevel@tonic-gate } 1350Sstevel@tonic-gate 1360Sstevel@tonic-gate mechs=packet_get_int(); 1370Sstevel@tonic-gate if (mechs==0) { 1380Sstevel@tonic-gate packet_check_eom(); 1390Sstevel@tonic-gate debug("Mechanism negotiation is not supported"); 1400Sstevel@tonic-gate return; 1410Sstevel@tonic-gate } 1420Sstevel@tonic-gate 1430Sstevel@tonic-gate ssh_gssapi_server_mechs(&supported_mechs); 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate do { 1460Sstevel@tonic-gate mechs--; 1470Sstevel@tonic-gate 1480Sstevel@tonic-gate if (oid != GSS_C_NULL_OID) 1490Sstevel@tonic-gate ssh_gssapi_release_oid(&oid); 1500Sstevel@tonic-gate 1510Sstevel@tonic-gate doid = packet_get_string(&len); 1520Sstevel@tonic-gate 1530Sstevel@tonic-gate /* ick */ 1540Sstevel@tonic-gate if (doid[0]!=0x06 || (len > 2 && doid[1]!=len-2)) { 1550Sstevel@tonic-gate log("Mechanism OID received using the old encoding form"); 1560Sstevel@tonic-gate oid = ssh_gssapi_make_oid(len, doid); 1570Sstevel@tonic-gate } else { 1580Sstevel@tonic-gate oid = ssh_gssapi_make_oid(len - 2, doid + 2); 1590Sstevel@tonic-gate } 1600Sstevel@tonic-gate (void) gss_test_oid_set_member(&min_status, oid, 1610Sstevel@tonic-gate supported_mechs, &present); 1620Sstevel@tonic-gate debug("Client offered gssapi userauth with %s (%s)", 1630Sstevel@tonic-gate ssh_gssapi_oid_to_str(oid), 1640Sstevel@tonic-gate present ? "supported" : "unsupported"); 1650Sstevel@tonic-gate } while (!present && (mechs > 0)); 1660Sstevel@tonic-gate 1670Sstevel@tonic-gate if (!present) { 1680Sstevel@tonic-gate /* userauth_finish() will send SSH2_MSG_USERAUTH_FAILURE */ 1690Sstevel@tonic-gate debug2("No mechanism offered by the client is available"); 1700Sstevel@tonic-gate ssh_gssapi_release_oid(&oid); 1710Sstevel@tonic-gate return; 1720Sstevel@tonic-gate } 1730Sstevel@tonic-gate 1740Sstevel@tonic-gate ssh_gssapi_build_ctx((Gssctxt **)&authctxt->method->method_data, 0, oid); 1750Sstevel@tonic-gate ssh_gssapi_release_oid(&oid); 1760Sstevel@tonic-gate /* Send SSH_MSG_USERAUTH_GSSAPI_RESPONSE */ 1770Sstevel@tonic-gate 1780Sstevel@tonic-gate packet_start(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE); 1790Sstevel@tonic-gate 1800Sstevel@tonic-gate /* Just return whatever we found -- the matched mech does us no good */ 1810Sstevel@tonic-gate packet_put_string(doid, len); 1820Sstevel@tonic-gate xfree(doid); 1830Sstevel@tonic-gate 1840Sstevel@tonic-gate packet_send(); 1850Sstevel@tonic-gate packet_write_wait(); 1860Sstevel@tonic-gate 1870Sstevel@tonic-gate /* Setup rest of gssapi userauth conversation */ 1880Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token); 1890Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok); 1900Sstevel@tonic-gate authctxt->method->postponed = 1; 1910Sstevel@tonic-gate 1920Sstevel@tonic-gate return; 1930Sstevel@tonic-gate } 1940Sstevel@tonic-gate 1950Sstevel@tonic-gate static void 1960Sstevel@tonic-gate input_gssapi_token(int type, u_int32_t plen, void *ctxt) 1970Sstevel@tonic-gate { 1980Sstevel@tonic-gate Authctxt *authctxt = ctxt; 1990Sstevel@tonic-gate Gssctxt *gssctxt; 2000Sstevel@tonic-gate gss_buffer_desc send_tok,recv_tok; 2010Sstevel@tonic-gate OM_uint32 maj_status, min_status; 2020Sstevel@tonic-gate u_int len; 2030Sstevel@tonic-gate 2040Sstevel@tonic-gate if (authctxt == NULL || authctxt->method == NULL || 2050Sstevel@tonic-gate (authctxt->method->method_data == NULL && !use_privsep)) 2060Sstevel@tonic-gate fatal("No authentication or GSSAPI context during gssapi-with-mic userauth"); 2070Sstevel@tonic-gate 2080Sstevel@tonic-gate gssctxt=authctxt->method->method_data; 2090Sstevel@tonic-gate recv_tok.value=packet_get_string(&len); 2100Sstevel@tonic-gate recv_tok.length=len; /* u_int vs. size_t */ 2110Sstevel@tonic-gate 2120Sstevel@tonic-gate maj_status=PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok, 2130Sstevel@tonic-gate &send_tok)); 2140Sstevel@tonic-gate packet_check_eom(); 2150Sstevel@tonic-gate 2160Sstevel@tonic-gate if (GSS_ERROR(maj_status)) { 2170Sstevel@tonic-gate ssh_gssapi_userauth_error(gssctxt); 2180Sstevel@tonic-gate if (send_tok.length != 0) { 2190Sstevel@tonic-gate packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK); 2200Sstevel@tonic-gate packet_put_string(send_tok.value,send_tok.length); 2210Sstevel@tonic-gate packet_send(); 2220Sstevel@tonic-gate packet_write_wait(); 2230Sstevel@tonic-gate } 2240Sstevel@tonic-gate authctxt->method->postponed = 0; 2250Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 2260Sstevel@tonic-gate userauth_finish(authctxt, authctxt->method->name); 2270Sstevel@tonic-gate } else { 2280Sstevel@tonic-gate if (send_tok.length != 0) { 2290Sstevel@tonic-gate packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN); 2300Sstevel@tonic-gate packet_put_string(send_tok.value,send_tok.length); 2310Sstevel@tonic-gate packet_send(); 2320Sstevel@tonic-gate packet_write_wait(); 2330Sstevel@tonic-gate } 2340Sstevel@tonic-gate if (maj_status == GSS_S_COMPLETE) { 2350Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN,NULL); 2360Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, 2370Sstevel@tonic-gate &input_gssapi_mic); 2380Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, 2390Sstevel@tonic-gate &input_gssapi_exchange_complete); 2400Sstevel@tonic-gate } 2410Sstevel@tonic-gate } 2420Sstevel@tonic-gate 2430Sstevel@tonic-gate gss_release_buffer(&min_status, &send_tok); 2440Sstevel@tonic-gate } 2450Sstevel@tonic-gate 2460Sstevel@tonic-gate static void 2470Sstevel@tonic-gate input_gssapi_errtok(int type, u_int32_t plen, void *ctxt) 2480Sstevel@tonic-gate { 2490Sstevel@tonic-gate Authctxt *authctxt = ctxt; 2500Sstevel@tonic-gate Gssctxt *gssctxt; 2510Sstevel@tonic-gate gss_buffer_desc send_tok,recv_tok; 2520Sstevel@tonic-gate 2530Sstevel@tonic-gate if (authctxt == NULL || authctxt->method == NULL || 2540Sstevel@tonic-gate (authctxt->method->method_data == NULL && !use_privsep)) 2550Sstevel@tonic-gate fatal("No authentication or GSSAPI context during gssapi-with-mic userauth"); 2560Sstevel@tonic-gate 2570Sstevel@tonic-gate gssctxt=authctxt->method->method_data; 2580Sstevel@tonic-gate recv_tok.value=packet_get_string(&recv_tok.length); 2590Sstevel@tonic-gate packet_check_eom(); 2600Sstevel@tonic-gate 2610Sstevel@tonic-gate /* Push the error token into GSSAPI to see what it says */ 2620Sstevel@tonic-gate (void) PRIVSEP(ssh_gssapi_accept_ctx(gssctxt, &recv_tok, &send_tok)); 2630Sstevel@tonic-gate 2640Sstevel@tonic-gate debug("Client sent GSS-API error token during GSS userauth-- %s", 2650Sstevel@tonic-gate ssh_gssapi_last_error(gssctxt, NULL, NULL)); 2660Sstevel@tonic-gate 2670Sstevel@tonic-gate /* We can't return anything to the client, even if we wanted to */ 2680Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 2690Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK,NULL); 2700Sstevel@tonic-gate 2710Sstevel@tonic-gate 2720Sstevel@tonic-gate /* 2730Sstevel@tonic-gate * The client will have already moved on to the next auth and 2740Sstevel@tonic-gate * will send a new userauth request. The spec says that the 2750Sstevel@tonic-gate * server MUST NOT send a SSH_MSG_USERAUTH_FAILURE packet in 2760Sstevel@tonic-gate * response to this. 2770Sstevel@tonic-gate * 2780Sstevel@tonic-gate * We leave authctxt->method->postponed == 1 here so that a call 2790Sstevel@tonic-gate * to input_userauth_request() will detect this failure (as 2800Sstevel@tonic-gate * userauth abandonment) and act accordingly. 2810Sstevel@tonic-gate */ 2820Sstevel@tonic-gate } 2830Sstevel@tonic-gate 2840Sstevel@tonic-gate static void 2850Sstevel@tonic-gate input_gssapi_mic(int type, u_int32_t plen, void *ctxt) 2860Sstevel@tonic-gate { 2870Sstevel@tonic-gate Authctxt *authctxt = ctxt; 2880Sstevel@tonic-gate Gssctxt *gssctxt; 2890Sstevel@tonic-gate gss_buffer_desc g_mic_data, mic_tok; 2900Sstevel@tonic-gate Buffer mic_data; 2910Sstevel@tonic-gate OM_uint32 maj_status, min_status; 2920Sstevel@tonic-gate 2930Sstevel@tonic-gate if (authctxt == NULL || authctxt->method == NULL || 2940Sstevel@tonic-gate (authctxt->method->method_data == NULL)) { 2950Sstevel@tonic-gate debug3("No authentication or GSSAPI context during gssapi-with-mic userauth"); 2960Sstevel@tonic-gate return; 2970Sstevel@tonic-gate } 2980Sstevel@tonic-gate 2990Sstevel@tonic-gate gssctxt=authctxt->method->method_data; 3000Sstevel@tonic-gate 3010Sstevel@tonic-gate /* Make data buffer to verify MIC with */ 3020Sstevel@tonic-gate buffer_init(&mic_data); 3030Sstevel@tonic-gate buffer_put_string(&mic_data, session_id2, session_id2_len); 3040Sstevel@tonic-gate buffer_put_char(&mic_data, SSH2_MSG_USERAUTH_REQUEST); 3050Sstevel@tonic-gate buffer_put_cstring(&mic_data, authctxt->user); 3060Sstevel@tonic-gate buffer_put_cstring(&mic_data, authctxt->service); 3070Sstevel@tonic-gate buffer_put_cstring(&mic_data, authctxt->method->name); 3080Sstevel@tonic-gate 3090Sstevel@tonic-gate g_mic_data.value = buffer_ptr(&mic_data); 3100Sstevel@tonic-gate g_mic_data.length = buffer_len(&mic_data); 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate mic_tok.value=packet_get_string(&mic_tok.length); 3130Sstevel@tonic-gate 3140Sstevel@tonic-gate maj_status = gss_verify_mic(&min_status, gssctxt->context, 3150Sstevel@tonic-gate &g_mic_data, &mic_tok, NULL); 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate packet_check_eom(); 3180Sstevel@tonic-gate buffer_free(&mic_data); 3190Sstevel@tonic-gate 3200Sstevel@tonic-gate if (maj_status != GSS_S_COMPLETE) 3210Sstevel@tonic-gate debug2("MIC verification failed, GSSAPI userauth failed"); 3220Sstevel@tonic-gate else 3230Sstevel@tonic-gate userauth_gssapi_finish(authctxt, gssctxt); 3240Sstevel@tonic-gate 3250Sstevel@tonic-gate /* Delete context from keyex */ 3260Sstevel@tonic-gate if (xxx_gssctxt != gssctxt) 3270Sstevel@tonic-gate ssh_gssapi_delete_ctx(&xxx_gssctxt); 3280Sstevel@tonic-gate 3290Sstevel@tonic-gate /* Leave Gssctxt around for ssh_gssapi_cleanup/storecreds() */ 3300Sstevel@tonic-gate if (gssctxt->deleg_creds == GSS_C_NO_CREDENTIAL) 3310Sstevel@tonic-gate ssh_gssapi_delete_ctx(&gssctxt); 3320Sstevel@tonic-gate 3330Sstevel@tonic-gate xxx_gssctxt = gssctxt; 3340Sstevel@tonic-gate 3350Sstevel@tonic-gate authctxt->method->postponed = 0; 3360Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 3370Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); 3380Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL); 3390Sstevel@tonic-gate userauth_finish(authctxt, authctxt->method->name); 3400Sstevel@tonic-gate } 3410Sstevel@tonic-gate 3420Sstevel@tonic-gate /* This is called when the client thinks we've completed authentication. 3430Sstevel@tonic-gate * It should only be enabled in the dispatch handler by the function above, 3440Sstevel@tonic-gate * which only enables it once the GSSAPI exchange is complete. 3450Sstevel@tonic-gate */ 3460Sstevel@tonic-gate static void 3470Sstevel@tonic-gate input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt) 3480Sstevel@tonic-gate { 3490Sstevel@tonic-gate Authctxt *authctxt = ctxt; 3500Sstevel@tonic-gate Gssctxt *gssctxt; 3510Sstevel@tonic-gate 3520Sstevel@tonic-gate packet_check_eom(); 3530Sstevel@tonic-gate 3540Sstevel@tonic-gate if (authctxt == NULL || authctxt->method == NULL || 3550Sstevel@tonic-gate (authctxt->method->method_data == NULL && !use_privsep)) 3560Sstevel@tonic-gate fatal("No authentication or GSSAPI context"); 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate gssctxt=authctxt->method->method_data; 3590Sstevel@tonic-gate 3600Sstevel@tonic-gate /* 3610Sstevel@tonic-gate * SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE -> gssapi userauth 3620Sstevel@tonic-gate * failure, the client should use SSH2_MSG_USERAUTH_GSSAPI_MIC 3630Sstevel@tonic-gate * instead. 3640Sstevel@tonic-gate * 3650Sstevel@tonic-gate * There's two reasons for this: 3660Sstevel@tonic-gate * 3670Sstevel@tonic-gate * 1) we don't have GSS mechs that don't support integrity 3680Sstevel@tonic-gate * protection, and even if we did we'd not want to use them with 3690Sstevel@tonic-gate * SSHv2, and, 3700Sstevel@tonic-gate * 3710Sstevel@tonic-gate * 2) we currently have no way to dynamically detect whether a 3720Sstevel@tonic-gate * given mechanism does or does not support integrity 3730Sstevel@tonic-gate * protection, so when a context's flags do not indicate 3740Sstevel@tonic-gate * integrity protection we can't know if the client simply 3750Sstevel@tonic-gate * didn't request it, so we assume it didn't and reject the 3760Sstevel@tonic-gate * userauth. 3770Sstevel@tonic-gate * 3780Sstevel@tonic-gate * We could fail partially (i.e., force the use of other 3790Sstevel@tonic-gate * userauth methods without counting this one as failed). But 3800Sstevel@tonic-gate * this will do for now. 3810Sstevel@tonic-gate */ 3820Sstevel@tonic-gate #if 0 3830Sstevel@tonic-gate authctxt->method->authenticated = PRIVSEP(ssh_gssapi_userok(gssctxt, authctxt->user)); 3840Sstevel@tonic-gate #endif 3850Sstevel@tonic-gate 3860Sstevel@tonic-gate if (xxx_gssctxt != gssctxt) 3870Sstevel@tonic-gate ssh_gssapi_delete_ctx(&gssctxt); 3880Sstevel@tonic-gate ssh_gssapi_delete_ctx(&gssctxt); 3890Sstevel@tonic-gate authctxt->method->postponed = 0; 3900Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 3910Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); 3920Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL); 3930Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); 3940Sstevel@tonic-gate userauth_finish(authctxt, authctxt->method->name); 3950Sstevel@tonic-gate } 3960Sstevel@tonic-gate 3970Sstevel@tonic-gate static void ssh_gssapi_userauth_error(Gssctxt *ctxt) { 3980Sstevel@tonic-gate char *errstr; 3990Sstevel@tonic-gate OM_uint32 maj,min; 4000Sstevel@tonic-gate 4010Sstevel@tonic-gate errstr=ssh_gssapi_last_error(ctxt,&maj,&min); 4020Sstevel@tonic-gate if (errstr) { 4030Sstevel@tonic-gate packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERROR); 4040Sstevel@tonic-gate packet_put_int(maj); 4050Sstevel@tonic-gate packet_put_int(min); 4060Sstevel@tonic-gate packet_put_cstring(errstr); 4070Sstevel@tonic-gate packet_put_cstring(""); 4080Sstevel@tonic-gate packet_send(); 4090Sstevel@tonic-gate packet_write_wait(); 4100Sstevel@tonic-gate xfree(errstr); 4110Sstevel@tonic-gate } 4120Sstevel@tonic-gate } 4130Sstevel@tonic-gate 4140Sstevel@tonic-gate /* 4150Sstevel@tonic-gate * Code common to gssapi-keyex and gssapi-with-mic userauth. 4160Sstevel@tonic-gate * 4170Sstevel@tonic-gate * Does authorization, figures out how to store delegated creds. 4180Sstevel@tonic-gate */ 4190Sstevel@tonic-gate static 4200Sstevel@tonic-gate void 4210Sstevel@tonic-gate userauth_gssapi_finish(Authctxt *authctxt, Gssctxt *gssctxt) 4220Sstevel@tonic-gate { 4230Sstevel@tonic-gate char *local_user = NULL; 424*4279Sgm149974 gss_buffer_desc dispname; 425*4279Sgm149974 OM_uint32 major; 4260Sstevel@tonic-gate 4270Sstevel@tonic-gate if (*authctxt->user != '\0' && 4280Sstevel@tonic-gate PRIVSEP(ssh_gssapi_userok(gssctxt, authctxt->user))) { 4290Sstevel@tonic-gate 4300Sstevel@tonic-gate /* 4310Sstevel@tonic-gate * If the client princ did not map to the requested 4320Sstevel@tonic-gate * username then we don't want to clobber existing creds 4330Sstevel@tonic-gate * for the user with the delegated creds. 4340Sstevel@tonic-gate */ 4350Sstevel@tonic-gate local_user = ssh_gssapi_localname(gssctxt); 4360Sstevel@tonic-gate if (local_user == NULL || 4370Sstevel@tonic-gate strcmp(local_user, authctxt->user) == 0) 4380Sstevel@tonic-gate gssctxt->default_creds = 1; /* store creds as default */ 4390Sstevel@tonic-gate 4400Sstevel@tonic-gate authctxt->method->authenticated = 4410Sstevel@tonic-gate do_pam_non_initial_userauth(authctxt); 4420Sstevel@tonic-gate 4430Sstevel@tonic-gate } else if (*authctxt->user == '\0') { 4440Sstevel@tonic-gate /* Requested username == ""; derive username from princ name */ 4450Sstevel@tonic-gate if ((local_user = ssh_gssapi_localname(gssctxt)) == NULL) 4460Sstevel@tonic-gate return; 4470Sstevel@tonic-gate 4480Sstevel@tonic-gate /* Changed username (from implicit, '') */ 4490Sstevel@tonic-gate userauth_user_svc_change(authctxt, local_user, NULL); 4500Sstevel@tonic-gate 4510Sstevel@tonic-gate gssctxt->default_creds = 1; /* store creds as default */ 4520Sstevel@tonic-gate 4530Sstevel@tonic-gate authctxt->method->authenticated = 4540Sstevel@tonic-gate do_pam_non_initial_userauth(authctxt); 4550Sstevel@tonic-gate } 4560Sstevel@tonic-gate 4570Sstevel@tonic-gate if (local_user != NULL) 4580Sstevel@tonic-gate xfree(local_user); 459*4279Sgm149974 460*4279Sgm149974 if (*authctxt->user != '\0' && authctxt->method->authenticated != 0) { 461*4279Sgm149974 major = gss_display_name(&gssctxt->minor, gssctxt->src_name, 462*4279Sgm149974 &dispname, NULL); 463*4279Sgm149974 if (major == GSS_S_COMPLETE) { 464*4279Sgm149974 log("Authorized principal %.*s, authenticated with " 465*4279Sgm149974 "GSS mechanism %s, to: %s", 466*4279Sgm149974 dispname.length, (char *)dispname.value, 467*4279Sgm149974 ssh_gssapi_oid_to_name(gssctxt->actual_mech), 468*4279Sgm149974 authctxt->user); 469*4279Sgm149974 } 470*4279Sgm149974 (void) gss_release_buffer(&gssctxt->minor, &dispname); 471*4279Sgm149974 } 4720Sstevel@tonic-gate } 4730Sstevel@tonic-gate 4740Sstevel@tonic-gate #if 0 4750Sstevel@tonic-gate /* Deprecated userauths -- should not be enabled */ 4760Sstevel@tonic-gate Authmethod method_external = { 4770Sstevel@tonic-gate "external-keyx", 4780Sstevel@tonic-gate &options.gss_authentication, 4790Sstevel@tonic-gate userauth_gssapi_keyex, 4800Sstevel@tonic-gate NULL, /* no abandon function */ 4810Sstevel@tonic-gate NULL, 4820Sstevel@tonic-gate NULL, 4830Sstevel@tonic-gate /* State counters */ 4840Sstevel@tonic-gate 0, 0, 0, 0, 4850Sstevel@tonic-gate /* State flags */ 4860Sstevel@tonic-gate 0, 0, 0, 0, 0, 0 4870Sstevel@tonic-gate }; 4880Sstevel@tonic-gate 4890Sstevel@tonic-gate Authmethod method_gssapi = { 4900Sstevel@tonic-gate "gssapi", 4910Sstevel@tonic-gate &options.gss_authentication, 4920Sstevel@tonic-gate userauth_gssapi, 4930Sstevel@tonic-gate userauth_gssapi_abandon, 4940Sstevel@tonic-gate NULL, 4950Sstevel@tonic-gate NULL, 4960Sstevel@tonic-gate /* State counters */ 4970Sstevel@tonic-gate 0, 0, 0, 0, 4980Sstevel@tonic-gate /* State flags */ 4990Sstevel@tonic-gate 0, 0, 0, 0, 0, 0 5000Sstevel@tonic-gate }; 5010Sstevel@tonic-gate #endif 5020Sstevel@tonic-gate 5030Sstevel@tonic-gate Authmethod method_external = { 5040Sstevel@tonic-gate "gssapi-keyex", 5050Sstevel@tonic-gate &options.gss_authentication, 5060Sstevel@tonic-gate userauth_gssapi_keyex, 5070Sstevel@tonic-gate NULL, /* no abandon function */ 5080Sstevel@tonic-gate NULL, 5090Sstevel@tonic-gate NULL, 5100Sstevel@tonic-gate /* State counters */ 5110Sstevel@tonic-gate 0, 0, 0, 0, 5120Sstevel@tonic-gate /* State flags */ 5130Sstevel@tonic-gate 0, 0, 0, 0, 0, 0 5140Sstevel@tonic-gate }; 5150Sstevel@tonic-gate 5160Sstevel@tonic-gate Authmethod method_gssapi = { 5170Sstevel@tonic-gate "gssapi-with-mic", 5180Sstevel@tonic-gate &options.gss_authentication, 5190Sstevel@tonic-gate userauth_gssapi, 5200Sstevel@tonic-gate userauth_gssapi_abandon, 5210Sstevel@tonic-gate NULL, 5220Sstevel@tonic-gate NULL, 5230Sstevel@tonic-gate /* State counters */ 5240Sstevel@tonic-gate 0, 0, 0, 0, 5250Sstevel@tonic-gate /* State flags */ 5260Sstevel@tonic-gate 0, 0, 0, 0, 0, 0 5270Sstevel@tonic-gate }; 5280Sstevel@tonic-gate 5290Sstevel@tonic-gate #endif /* GSSAPI */ 530