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*6080Sjp161948 * Copyright 2008 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; 49*6080Sjp161948 extern uchar_t *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 { 58*6080Sjp161948 gss_buffer_desc g_mic_data, mic_tok; 590Sstevel@tonic-gate Buffer mic_data; 60*6080Sjp161948 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 } 70*6080Sjp161948 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 82*6080Sjp161948 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, 85*6080Sjp161948 &g_mic_data, &mic_tok, NULL); 860Sstevel@tonic-gate 87*6080Sjp161948 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 1000Sstevel@tonic-gate static void ssh_gssapi_userauth_error(Gssctxt *ctxt); 1010Sstevel@tonic-gate static void input_gssapi_token(int type, u_int32_t plen, void *ctxt); 1020Sstevel@tonic-gate static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt); 1030Sstevel@tonic-gate static void input_gssapi_errtok(int, u_int32_t, void *); 104*6080Sjp161948 static void input_gssapi_exchange_complete(int type, u_int32_t plen, 105*6080Sjp161948 void *ctxt); 1060Sstevel@tonic-gate 1070Sstevel@tonic-gate static void 1080Sstevel@tonic-gate userauth_gssapi_abandon(Authctxt *authctxt, Authmethod *method) 1090Sstevel@tonic-gate { 1100Sstevel@tonic-gate ssh_gssapi_delete_ctx((Gssctxt **)&method->method_data); 1110Sstevel@tonic-gate xxx_gssctxt = NULL; 1120Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL); 1130Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); 1140Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 115*6080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); 1160Sstevel@tonic-gate } 1170Sstevel@tonic-gate 1180Sstevel@tonic-gate static void 1190Sstevel@tonic-gate userauth_gssapi(Authctxt *authctxt) 1200Sstevel@tonic-gate { 121*6080Sjp161948 gss_OID_set supported_mechs; 122*6080Sjp161948 int mechs, present = 0; 123*6080Sjp161948 OM_uint32 min_status; 124*6080Sjp161948 uint_t len; 125*6080Sjp161948 char *doid = NULL; 126*6080Sjp161948 gss_OID oid = GSS_C_NULL_OID; 1270Sstevel@tonic-gate 128*6080Sjp161948 if (datafellows & SSH_OLD_GSSAPI) { 129*6080Sjp161948 debug("Early drafts of GSSAPI userauth not supported"); 130*6080Sjp161948 return; 131*6080Sjp161948 } 1320Sstevel@tonic-gate 133*6080Sjp161948 mechs = packet_get_int(); 134*6080Sjp161948 if (mechs == 0) { 1350Sstevel@tonic-gate packet_check_eom(); 136*6080Sjp161948 debug("Mechanism negotiation is not supported"); 137*6080Sjp161948 return; 138*6080Sjp161948 } 1390Sstevel@tonic-gate 1400Sstevel@tonic-gate ssh_gssapi_server_mechs(&supported_mechs); 1410Sstevel@tonic-gate 142*6080Sjp161948 do { 143*6080Sjp161948 mechs--; 1440Sstevel@tonic-gate 1450Sstevel@tonic-gate if (oid != GSS_C_NULL_OID) 1460Sstevel@tonic-gate ssh_gssapi_release_oid(&oid); 1470Sstevel@tonic-gate 148*6080Sjp161948 doid = packet_get_string(&len); 1490Sstevel@tonic-gate 1500Sstevel@tonic-gate /* ick */ 151*6080Sjp161948 if (doid[0] != 0x06 || (len > 2 && doid[1] != len - 2)) { 152*6080Sjp161948 log("Mechanism OID received using the old " 153*6080Sjp161948 "encoding form"); 1540Sstevel@tonic-gate oid = ssh_gssapi_make_oid(len, doid); 155*6080Sjp161948 } else { 1560Sstevel@tonic-gate oid = ssh_gssapi_make_oid(len - 2, doid + 2); 157*6080Sjp161948 } 158*6080Sjp161948 159*6080Sjp161948 (void) gss_test_oid_set_member(&min_status, oid, 160*6080Sjp161948 supported_mechs, &present); 1610Sstevel@tonic-gate 162*6080Sjp161948 debug("Client offered gssapi userauth with %s (%s)", 163*6080Sjp161948 ssh_gssapi_oid_to_str(oid), 164*6080Sjp161948 present ? "supported" : "unsupported"); 165*6080Sjp161948 } while (!present && (mechs > 0)); 166*6080Sjp161948 167*6080Sjp161948 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"); 170*6080Sjp161948 ssh_gssapi_release_oid(&oid); 171*6080Sjp161948 return; 172*6080Sjp161948 } 1730Sstevel@tonic-gate 174*6080Sjp161948 ssh_gssapi_build_ctx((Gssctxt **)&authctxt->method->method_data, 175*6080Sjp161948 0, oid); 176*6080Sjp161948 ssh_gssapi_release_oid(&oid); 177*6080Sjp161948 /* Send SSH_MSG_USERAUTH_GSSAPI_RESPONSE */ 1780Sstevel@tonic-gate 179*6080Sjp161948 packet_start(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE); 1800Sstevel@tonic-gate 1810Sstevel@tonic-gate /* Just return whatever we found -- the matched mech does us no good */ 1820Sstevel@tonic-gate packet_put_string(doid, len); 1830Sstevel@tonic-gate xfree(doid); 1840Sstevel@tonic-gate 185*6080Sjp161948 packet_send(); 186*6080Sjp161948 packet_write_wait(); 1870Sstevel@tonic-gate 1880Sstevel@tonic-gate /* Setup rest of gssapi userauth conversation */ 189*6080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token); 190*6080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok); 191*6080Sjp161948 authctxt->method->postponed = 1; 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 { 197*6080Sjp161948 Authctxt *authctxt = ctxt; 198*6080Sjp161948 Gssctxt *gssctxt; 199*6080Sjp161948 gss_buffer_desc send_tok, recv_tok; 200*6080Sjp161948 OM_uint32 maj_status, min_status; 201*6080Sjp161948 uint_t len; 2020Sstevel@tonic-gate 203*6080Sjp161948 if (authctxt == NULL || authctxt->method == NULL || 204*6080Sjp161948 (authctxt->method->method_data == NULL)) { 205*6080Sjp161948 fatal("No authentication or GSSAPI context during " 206*6080Sjp161948 "gssapi-with-mic userauth"); 207*6080Sjp161948 } 2080Sstevel@tonic-gate 209*6080Sjp161948 gssctxt = authctxt->method->method_data; 210*6080Sjp161948 recv_tok.value = packet_get_string(&len); 211*6080Sjp161948 recv_tok.length = len; /* u_int vs. size_t */ 2120Sstevel@tonic-gate 213*6080Sjp161948 maj_status = ssh_gssapi_accept_ctx(gssctxt, &recv_tok, &send_tok); 214*6080Sjp161948 packet_check_eom(); 215*6080Sjp161948 216*6080Sjp161948 if (GSS_ERROR(maj_status)) { 217*6080Sjp161948 ssh_gssapi_userauth_error(gssctxt); 2180Sstevel@tonic-gate if (send_tok.length != 0) { 2190Sstevel@tonic-gate packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK); 220*6080Sjp161948 packet_put_string(send_tok.value, send_tok.length); 221*6080Sjp161948 packet_send(); 222*6080Sjp161948 packet_write_wait(); 223*6080Sjp161948 } 224*6080Sjp161948 authctxt->method->postponed = 0; 225*6080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 226*6080Sjp161948 userauth_finish(authctxt, authctxt->method->name); 227*6080Sjp161948 } else { 228*6080Sjp161948 if (send_tok.length != 0) { 229*6080Sjp161948 packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN); 230*6080Sjp161948 packet_put_string(send_tok.value, send_tok.length); 231*6080Sjp161948 packet_send(); 232*6080Sjp161948 packet_write_wait(); 233*6080Sjp161948 } 234*6080Sjp161948 if (maj_status == GSS_S_COMPLETE) { 235*6080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 236*6080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, 237*6080Sjp161948 &input_gssapi_mic); 238*6080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, 239*6080Sjp161948 &input_gssapi_exchange_complete); 240*6080Sjp161948 } 241*6080Sjp161948 } 2420Sstevel@tonic-gate 243*6080Sjp161948 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 { 249*6080Sjp161948 Authctxt *authctxt = ctxt; 250*6080Sjp161948 Gssctxt *gssctxt; 251*6080Sjp161948 gss_buffer_desc send_tok, recv_tok; 2520Sstevel@tonic-gate 253*6080Sjp161948 if (authctxt == NULL || authctxt->method == NULL || 254*6080Sjp161948 (authctxt->method->method_data == NULL)) { 255*6080Sjp161948 fatal("No authentication or GSSAPI context during " 256*6080Sjp161948 "gssapi-with-mic userauth"); 257*6080Sjp161948 } 2580Sstevel@tonic-gate 259*6080Sjp161948 gssctxt = authctxt->method->method_data; 260*6080Sjp161948 recv_tok.value = packet_get_string(&recv_tok.length); 261*6080Sjp161948 packet_check_eom(); 2620Sstevel@tonic-gate 263*6080Sjp161948 /* Push the error token into GSSAPI to see what it says */ 264*6080Sjp161948 (void) ssh_gssapi_accept_ctx(gssctxt, &recv_tok, &send_tok); 2650Sstevel@tonic-gate 2660Sstevel@tonic-gate debug("Client sent GSS-API error token during GSS userauth-- %s", 267*6080Sjp161948 ssh_gssapi_last_error(gssctxt, NULL, NULL)); 2680Sstevel@tonic-gate 2690Sstevel@tonic-gate /* We can't return anything to the client, even if we wanted to */ 2700Sstevel@tonic-gate dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 271*6080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); 2720Sstevel@tonic-gate 2730Sstevel@tonic-gate 2740Sstevel@tonic-gate /* 2750Sstevel@tonic-gate * The client will have already moved on to the next auth and 2760Sstevel@tonic-gate * will send a new userauth request. The spec says that the 2770Sstevel@tonic-gate * server MUST NOT send a SSH_MSG_USERAUTH_FAILURE packet in 2780Sstevel@tonic-gate * response to this. 2790Sstevel@tonic-gate * 2800Sstevel@tonic-gate * We leave authctxt->method->postponed == 1 here so that a call 2810Sstevel@tonic-gate * to input_userauth_request() will detect this failure (as 2820Sstevel@tonic-gate * userauth abandonment) and act accordingly. 2830Sstevel@tonic-gate */ 2840Sstevel@tonic-gate } 2850Sstevel@tonic-gate 2860Sstevel@tonic-gate static void 2870Sstevel@tonic-gate input_gssapi_mic(int type, u_int32_t plen, void *ctxt) 2880Sstevel@tonic-gate { 2890Sstevel@tonic-gate Authctxt *authctxt = ctxt; 2900Sstevel@tonic-gate Gssctxt *gssctxt; 291*6080Sjp161948 gss_buffer_desc g_mic_data, mic_tok; 2920Sstevel@tonic-gate Buffer mic_data; 293*6080Sjp161948 OM_uint32 maj_status, min_status; 2940Sstevel@tonic-gate 2950Sstevel@tonic-gate if (authctxt == NULL || authctxt->method == NULL || 2960Sstevel@tonic-gate (authctxt->method->method_data == NULL)) { 297*6080Sjp161948 debug3("No authentication or GSSAPI context during " 298*6080Sjp161948 "gssapi-with-mic userauth"); 2990Sstevel@tonic-gate return; 3000Sstevel@tonic-gate } 3010Sstevel@tonic-gate 302*6080Sjp161948 gssctxt = authctxt->method->method_data; 3030Sstevel@tonic-gate 3040Sstevel@tonic-gate /* Make data buffer to verify MIC with */ 3050Sstevel@tonic-gate buffer_init(&mic_data); 3060Sstevel@tonic-gate buffer_put_string(&mic_data, session_id2, session_id2_len); 3070Sstevel@tonic-gate buffer_put_char(&mic_data, SSH2_MSG_USERAUTH_REQUEST); 3080Sstevel@tonic-gate buffer_put_cstring(&mic_data, authctxt->user); 3090Sstevel@tonic-gate buffer_put_cstring(&mic_data, authctxt->service); 3100Sstevel@tonic-gate buffer_put_cstring(&mic_data, authctxt->method->name); 3110Sstevel@tonic-gate 3120Sstevel@tonic-gate g_mic_data.value = buffer_ptr(&mic_data); 3130Sstevel@tonic-gate g_mic_data.length = buffer_len(&mic_data); 3140Sstevel@tonic-gate 315*6080Sjp161948 mic_tok.value = packet_get_string(&mic_tok.length); 3160Sstevel@tonic-gate 3170Sstevel@tonic-gate maj_status = gss_verify_mic(&min_status, gssctxt->context, 318*6080Sjp161948 &g_mic_data, &mic_tok, NULL); 3190Sstevel@tonic-gate 320*6080Sjp161948 packet_check_eom(); 3210Sstevel@tonic-gate buffer_free(&mic_data); 3220Sstevel@tonic-gate 3230Sstevel@tonic-gate if (maj_status != GSS_S_COMPLETE) 3240Sstevel@tonic-gate debug2("MIC verification failed, GSSAPI userauth failed"); 3250Sstevel@tonic-gate else 3260Sstevel@tonic-gate userauth_gssapi_finish(authctxt, gssctxt); 3270Sstevel@tonic-gate 3280Sstevel@tonic-gate /* Delete context from keyex */ 3290Sstevel@tonic-gate if (xxx_gssctxt != gssctxt) 3300Sstevel@tonic-gate ssh_gssapi_delete_ctx(&xxx_gssctxt); 3310Sstevel@tonic-gate 3320Sstevel@tonic-gate /* Leave Gssctxt around for ssh_gssapi_cleanup/storecreds() */ 3330Sstevel@tonic-gate if (gssctxt->deleg_creds == GSS_C_NO_CREDENTIAL) 3340Sstevel@tonic-gate ssh_gssapi_delete_ctx(&gssctxt); 3350Sstevel@tonic-gate 3360Sstevel@tonic-gate xxx_gssctxt = gssctxt; 3370Sstevel@tonic-gate 338*6080Sjp161948 authctxt->method->postponed = 0; 339*6080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 340*6080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); 341*6080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL); 342*6080Sjp161948 userauth_finish(authctxt, authctxt->method->name); 3430Sstevel@tonic-gate } 3440Sstevel@tonic-gate 345*6080Sjp161948 /* 346*6080Sjp161948 * This is called when the client thinks we've completed authentication. 3470Sstevel@tonic-gate * It should only be enabled in the dispatch handler by the function above, 3480Sstevel@tonic-gate * which only enables it once the GSSAPI exchange is complete. 3490Sstevel@tonic-gate */ 3500Sstevel@tonic-gate static void 3510Sstevel@tonic-gate input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt) 3520Sstevel@tonic-gate { 353*6080Sjp161948 Authctxt *authctxt = ctxt; 354*6080Sjp161948 Gssctxt *gssctxt; 3550Sstevel@tonic-gate 3560Sstevel@tonic-gate packet_check_eom(); 3570Sstevel@tonic-gate 3580Sstevel@tonic-gate if (authctxt == NULL || authctxt->method == NULL || 3595562Sjp161948 (authctxt->method->method_data == NULL)) 360*6080Sjp161948 fatal("No authentication or GSSAPI context"); 3610Sstevel@tonic-gate 362*6080Sjp161948 gssctxt = authctxt->method->method_data; 3630Sstevel@tonic-gate 3640Sstevel@tonic-gate /* 3650Sstevel@tonic-gate * SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE -> gssapi userauth 3660Sstevel@tonic-gate * failure, the client should use SSH2_MSG_USERAUTH_GSSAPI_MIC 3670Sstevel@tonic-gate * instead. 3680Sstevel@tonic-gate * 3690Sstevel@tonic-gate * There's two reasons for this: 3700Sstevel@tonic-gate * 3710Sstevel@tonic-gate * 1) we don't have GSS mechs that don't support integrity 3720Sstevel@tonic-gate * protection, and even if we did we'd not want to use them with 3730Sstevel@tonic-gate * SSHv2, and, 3740Sstevel@tonic-gate * 3750Sstevel@tonic-gate * 2) we currently have no way to dynamically detect whether a 3760Sstevel@tonic-gate * given mechanism does or does not support integrity 3770Sstevel@tonic-gate * protection, so when a context's flags do not indicate 3780Sstevel@tonic-gate * integrity protection we can't know if the client simply 3790Sstevel@tonic-gate * didn't request it, so we assume it didn't and reject the 3800Sstevel@tonic-gate * userauth. 3810Sstevel@tonic-gate * 3820Sstevel@tonic-gate * We could fail partially (i.e., force the use of other 3830Sstevel@tonic-gate * userauth methods without counting this one as failed). But 3840Sstevel@tonic-gate * this will do for now. 3850Sstevel@tonic-gate */ 3860Sstevel@tonic-gate #if 0 387*6080Sjp161948 authctxt->method->authenticated = ssh_gssapi_userok(gssctxt, 388*6080Sjp161948 authctxt->user); 3890Sstevel@tonic-gate #endif 3900Sstevel@tonic-gate 3910Sstevel@tonic-gate if (xxx_gssctxt != gssctxt) 3920Sstevel@tonic-gate ssh_gssapi_delete_ctx(&gssctxt); 3930Sstevel@tonic-gate ssh_gssapi_delete_ctx(&gssctxt); 394*6080Sjp161948 authctxt->method->postponed = 0; 395*6080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 396*6080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL); 397*6080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL); 398*6080Sjp161948 dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); 399*6080Sjp161948 userauth_finish(authctxt, authctxt->method->name); 4000Sstevel@tonic-gate } 4010Sstevel@tonic-gate 402*6080Sjp161948 static void 403*6080Sjp161948 ssh_gssapi_userauth_error(Gssctxt *ctxt) 404*6080Sjp161948 { 4050Sstevel@tonic-gate char *errstr; 406*6080Sjp161948 OM_uint32 maj, min; 4070Sstevel@tonic-gate 408*6080Sjp161948 errstr = ssh_gssapi_last_error(ctxt, &maj, &min); 4090Sstevel@tonic-gate if (errstr) { 4100Sstevel@tonic-gate packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERROR); 4110Sstevel@tonic-gate packet_put_int(maj); 4120Sstevel@tonic-gate packet_put_int(min); 4130Sstevel@tonic-gate packet_put_cstring(errstr); 4140Sstevel@tonic-gate packet_put_cstring(""); 4150Sstevel@tonic-gate packet_send(); 4160Sstevel@tonic-gate packet_write_wait(); 4170Sstevel@tonic-gate xfree(errstr); 4180Sstevel@tonic-gate } 4190Sstevel@tonic-gate } 4200Sstevel@tonic-gate 4210Sstevel@tonic-gate /* 4220Sstevel@tonic-gate * Code common to gssapi-keyex and gssapi-with-mic userauth. 4230Sstevel@tonic-gate * 4240Sstevel@tonic-gate * Does authorization, figures out how to store delegated creds. 4250Sstevel@tonic-gate */ 426*6080Sjp161948 static void 4270Sstevel@tonic-gate userauth_gssapi_finish(Authctxt *authctxt, Gssctxt *gssctxt) 4280Sstevel@tonic-gate { 4290Sstevel@tonic-gate char *local_user = NULL; 4304279Sgm149974 gss_buffer_desc dispname; 4314279Sgm149974 OM_uint32 major; 4320Sstevel@tonic-gate 4330Sstevel@tonic-gate if (*authctxt->user != '\0' && 4345562Sjp161948 ssh_gssapi_userok(gssctxt, authctxt->user)) { 4350Sstevel@tonic-gate 4360Sstevel@tonic-gate /* 4370Sstevel@tonic-gate * If the client princ did not map to the requested 4380Sstevel@tonic-gate * username then we don't want to clobber existing creds 4390Sstevel@tonic-gate * for the user with the delegated creds. 4400Sstevel@tonic-gate */ 4410Sstevel@tonic-gate local_user = ssh_gssapi_localname(gssctxt); 4420Sstevel@tonic-gate if (local_user == NULL || 4430Sstevel@tonic-gate strcmp(local_user, authctxt->user) == 0) 4440Sstevel@tonic-gate gssctxt->default_creds = 1; /* store creds as default */ 4450Sstevel@tonic-gate 446*6080Sjp161948 authctxt->method->authenticated = 447*6080Sjp161948 do_pam_non_initial_userauth(authctxt); 4480Sstevel@tonic-gate 4490Sstevel@tonic-gate } else if (*authctxt->user == '\0') { 4500Sstevel@tonic-gate /* Requested username == ""; derive username from princ name */ 4510Sstevel@tonic-gate if ((local_user = ssh_gssapi_localname(gssctxt)) == NULL) 4520Sstevel@tonic-gate return; 4530Sstevel@tonic-gate 4540Sstevel@tonic-gate /* Changed username (from implicit, '') */ 4550Sstevel@tonic-gate userauth_user_svc_change(authctxt, local_user, NULL); 4560Sstevel@tonic-gate 4570Sstevel@tonic-gate gssctxt->default_creds = 1; /* store creds as default */ 4580Sstevel@tonic-gate 4590Sstevel@tonic-gate authctxt->method->authenticated = 460*6080Sjp161948 do_pam_non_initial_userauth(authctxt); 4610Sstevel@tonic-gate } 4620Sstevel@tonic-gate 4630Sstevel@tonic-gate if (local_user != NULL) 4640Sstevel@tonic-gate xfree(local_user); 4654279Sgm149974 4664279Sgm149974 if (*authctxt->user != '\0' && authctxt->method->authenticated != 0) { 4674279Sgm149974 major = gss_display_name(&gssctxt->minor, gssctxt->src_name, 468*6080Sjp161948 &dispname, NULL); 4694279Sgm149974 if (major == GSS_S_COMPLETE) { 4704279Sgm149974 log("Authorized principal %.*s, authenticated with " 4714279Sgm149974 "GSS mechanism %s, to: %s", 472*6080Sjp161948 dispname.length, (char *)dispname.value, 473*6080Sjp161948 ssh_gssapi_oid_to_name(gssctxt->actual_mech), 474*6080Sjp161948 authctxt->user); 4754279Sgm149974 } 4764279Sgm149974 (void) gss_release_buffer(&gssctxt->minor, &dispname); 4774279Sgm149974 } 4780Sstevel@tonic-gate } 4790Sstevel@tonic-gate 4800Sstevel@tonic-gate #if 0 4810Sstevel@tonic-gate /* Deprecated userauths -- should not be enabled */ 4820Sstevel@tonic-gate Authmethod method_external = { 4830Sstevel@tonic-gate "external-keyx", 4840Sstevel@tonic-gate &options.gss_authentication, 4850Sstevel@tonic-gate userauth_gssapi_keyex, 4860Sstevel@tonic-gate NULL, /* no abandon function */ 4870Sstevel@tonic-gate NULL, 4880Sstevel@tonic-gate NULL, 4890Sstevel@tonic-gate /* State counters */ 4900Sstevel@tonic-gate 0, 0, 0, 0, 4910Sstevel@tonic-gate /* State flags */ 4920Sstevel@tonic-gate 0, 0, 0, 0, 0, 0 4930Sstevel@tonic-gate }; 4940Sstevel@tonic-gate 4950Sstevel@tonic-gate Authmethod method_gssapi = { 496*6080Sjp161948 "gssapi", 497*6080Sjp161948 &options.gss_authentication, 498*6080Sjp161948 userauth_gssapi, 4990Sstevel@tonic-gate userauth_gssapi_abandon, 5000Sstevel@tonic-gate NULL, 5010Sstevel@tonic-gate NULL, 5020Sstevel@tonic-gate /* State counters */ 5030Sstevel@tonic-gate 0, 0, 0, 0, 5040Sstevel@tonic-gate /* State flags */ 5050Sstevel@tonic-gate 0, 0, 0, 0, 0, 0 5060Sstevel@tonic-gate }; 5070Sstevel@tonic-gate #endif 5080Sstevel@tonic-gate 5090Sstevel@tonic-gate Authmethod method_external = { 5100Sstevel@tonic-gate "gssapi-keyex", 5110Sstevel@tonic-gate &options.gss_authentication, 5120Sstevel@tonic-gate userauth_gssapi_keyex, 5130Sstevel@tonic-gate NULL, /* no abandon function */ 5140Sstevel@tonic-gate NULL, 5150Sstevel@tonic-gate NULL, 5160Sstevel@tonic-gate /* State counters */ 5170Sstevel@tonic-gate 0, 0, 0, 0, 5180Sstevel@tonic-gate /* State flags */ 5190Sstevel@tonic-gate 0, 0, 0, 0, 0, 0 5200Sstevel@tonic-gate }; 5210Sstevel@tonic-gate 5220Sstevel@tonic-gate Authmethod method_gssapi = { 523*6080Sjp161948 "gssapi-with-mic", 524*6080Sjp161948 &options.gss_authentication, 525*6080Sjp161948 userauth_gssapi, 5260Sstevel@tonic-gate userauth_gssapi_abandon, 5270Sstevel@tonic-gate NULL, 5280Sstevel@tonic-gate NULL, 5290Sstevel@tonic-gate /* State counters */ 5300Sstevel@tonic-gate 0, 0, 0, 0, 5310Sstevel@tonic-gate /* State flags */ 5320Sstevel@tonic-gate 0, 0, 0, 0, 0, 0 5330Sstevel@tonic-gate }; 5340Sstevel@tonic-gate 5350Sstevel@tonic-gate #endif /* GSSAPI */ 536