xref: /onnv-gate/usr/src/cmd/ssh/sshd/auth2-gss.c (revision 4279:42d8fd066c8f)
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