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