xref: /titanic_44/usr/src/cmd/ssh/sshd/auth2-gss.c (revision b07b2f5c1a9b43b43daa3f5087f57ede3d664810)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
57c478bd9Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
67c478bd9Sstevel@tonic-gate  * are met:
77c478bd9Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
87c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
97c478bd9Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
107c478bd9Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
117c478bd9Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR
147c478bd9Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
157c478bd9Sstevel@tonic-gate  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
167c478bd9Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
177c478bd9Sstevel@tonic-gate  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
187c478bd9Sstevel@tonic-gate  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
197c478bd9Sstevel@tonic-gate  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
207c478bd9Sstevel@tonic-gate  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
217c478bd9Sstevel@tonic-gate  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
227c478bd9Sstevel@tonic-gate  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
237c478bd9Sstevel@tonic-gate  */
247c478bd9Sstevel@tonic-gate /*
25*b07b2f5cSHuie-Ying Lee  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
267c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
277c478bd9Sstevel@tonic-gate  */
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate #include "includes.h"
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #ifdef GSSAPI
327c478bd9Sstevel@tonic-gate #include "auth.h"
337c478bd9Sstevel@tonic-gate #include "ssh2.h"
347c478bd9Sstevel@tonic-gate #include "xmalloc.h"
357c478bd9Sstevel@tonic-gate #include "log.h"
367c478bd9Sstevel@tonic-gate #include "dispatch.h"
37*b07b2f5cSHuie-Ying Lee #include "buffer.h"
387c478bd9Sstevel@tonic-gate #include "servconf.h"
397c478bd9Sstevel@tonic-gate #include "compat.h"
407c478bd9Sstevel@tonic-gate #include "bufaux.h"
417c478bd9Sstevel@tonic-gate #include "packet.h"
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate #include <gssapi/gssapi.h>
447c478bd9Sstevel@tonic-gate #include "ssh-gss.h"
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate extern ServerOptions options;
47c15e4e4bSjp161948 extern uchar_t *session_id2;
487c478bd9Sstevel@tonic-gate extern int session_id2_len;
497c478bd9Sstevel@tonic-gate extern Gssctxt *xxx_gssctxt;
507c478bd9Sstevel@tonic-gate 
517c478bd9Sstevel@tonic-gate static void userauth_gssapi_finish(Authctxt *authctxt, Gssctxt *gssctxt);
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate static void
userauth_gssapi_keyex(Authctxt * authctxt)547c478bd9Sstevel@tonic-gate userauth_gssapi_keyex(Authctxt *authctxt)
557c478bd9Sstevel@tonic-gate {
567c478bd9Sstevel@tonic-gate 	gss_buffer_desc g_mic_data, mic_tok;
577c478bd9Sstevel@tonic-gate 	Buffer mic_data;
587c478bd9Sstevel@tonic-gate 	OM_uint32 maj_status, min_status;
597c478bd9Sstevel@tonic-gate 
607c478bd9Sstevel@tonic-gate 	if (authctxt == NULL || authctxt->method == NULL)
617c478bd9Sstevel@tonic-gate 		fatal("No authentication context during gssapi-keyex userauth");
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate 	if (xxx_gssctxt == NULL || xxx_gssctxt->context == GSS_C_NO_CONTEXT) {
647c478bd9Sstevel@tonic-gate 		/* fatal()?  or return? */
657c478bd9Sstevel@tonic-gate 		debug("No GSS-API context during gssapi-keyex userauth");
667c478bd9Sstevel@tonic-gate 		return;
677c478bd9Sstevel@tonic-gate 	}
687c478bd9Sstevel@tonic-gate 
697c478bd9Sstevel@tonic-gate 	/* Make data buffer to verify MIC with */
707c478bd9Sstevel@tonic-gate 	buffer_init(&mic_data);
717c478bd9Sstevel@tonic-gate 	buffer_put_string(&mic_data, session_id2, session_id2_len);
727c478bd9Sstevel@tonic-gate 	buffer_put_char(&mic_data, SSH2_MSG_USERAUTH_REQUEST);
737c478bd9Sstevel@tonic-gate 	buffer_put_cstring(&mic_data, authctxt->user);
747c478bd9Sstevel@tonic-gate 	buffer_put_cstring(&mic_data, authctxt->service);
757c478bd9Sstevel@tonic-gate 	buffer_put_cstring(&mic_data, authctxt->method->name);
767c478bd9Sstevel@tonic-gate 
777c478bd9Sstevel@tonic-gate 	g_mic_data.value  = buffer_ptr(&mic_data);
787c478bd9Sstevel@tonic-gate 	g_mic_data.length = buffer_len(&mic_data);
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate 	mic_tok.value = packet_get_string(&mic_tok.length);
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 	maj_status = gss_verify_mic(&min_status, xxx_gssctxt->context,
837c478bd9Sstevel@tonic-gate 	    &g_mic_data, &mic_tok, NULL);
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate 	packet_check_eom();
867c478bd9Sstevel@tonic-gate 	buffer_clear(&mic_data);
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate 	if (maj_status != GSS_S_COMPLETE)
897c478bd9Sstevel@tonic-gate 		debug2("MIC verification failed, GSSAPI userauth failed");
907c478bd9Sstevel@tonic-gate 	else
917c478bd9Sstevel@tonic-gate 		userauth_gssapi_finish(authctxt, xxx_gssctxt);
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate 	/* Leave Gssctxt around for ssh_gssapi_cleanup/storecreds() */
947c478bd9Sstevel@tonic-gate 	if (xxx_gssctxt->deleg_creds == GSS_C_NO_CREDENTIAL)
957c478bd9Sstevel@tonic-gate 		ssh_gssapi_delete_ctx(&xxx_gssctxt);
967c478bd9Sstevel@tonic-gate }
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate static void ssh_gssapi_userauth_error(Gssctxt *ctxt);
997c478bd9Sstevel@tonic-gate static void input_gssapi_token(int type, u_int32_t plen, void *ctxt);
1007c478bd9Sstevel@tonic-gate static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt);
1017c478bd9Sstevel@tonic-gate static void input_gssapi_errtok(int, u_int32_t, void *);
102c15e4e4bSjp161948 static void input_gssapi_exchange_complete(int type, u_int32_t plen,
103c15e4e4bSjp161948     void *ctxt);
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate static void
userauth_gssapi_abandon(Authctxt * authctxt,Authmethod * method)1067c478bd9Sstevel@tonic-gate userauth_gssapi_abandon(Authctxt *authctxt, Authmethod *method)
1077c478bd9Sstevel@tonic-gate {
1087c478bd9Sstevel@tonic-gate 	ssh_gssapi_delete_ctx((Gssctxt **)&method->method_data);
1097c478bd9Sstevel@tonic-gate 	xxx_gssctxt = NULL;
1107c478bd9Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
1117c478bd9Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
1127c478bd9Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
1137c478bd9Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
1147c478bd9Sstevel@tonic-gate }
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate static void
userauth_gssapi(Authctxt * authctxt)1177c478bd9Sstevel@tonic-gate userauth_gssapi(Authctxt *authctxt)
1187c478bd9Sstevel@tonic-gate {
1197c478bd9Sstevel@tonic-gate 	gss_OID_set supported_mechs;
120c15e4e4bSjp161948 	int mechs, present = 0;
1217c478bd9Sstevel@tonic-gate 	OM_uint32 min_status;
122c15e4e4bSjp161948 	uint_t len;
1237c478bd9Sstevel@tonic-gate 	char *doid = NULL;
1247c478bd9Sstevel@tonic-gate 	gss_OID oid = GSS_C_NULL_OID;
1257c478bd9Sstevel@tonic-gate 
1267c478bd9Sstevel@tonic-gate 	if (datafellows & SSH_OLD_GSSAPI) {
1277c478bd9Sstevel@tonic-gate 		debug("Early drafts of GSSAPI userauth not supported");
1287c478bd9Sstevel@tonic-gate 		return;
1297c478bd9Sstevel@tonic-gate 	}
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate 	mechs = packet_get_int();
1327c478bd9Sstevel@tonic-gate 	if (mechs == 0) {
1337c478bd9Sstevel@tonic-gate 		packet_check_eom();
1347c478bd9Sstevel@tonic-gate 		debug("Mechanism negotiation is not supported");
1357c478bd9Sstevel@tonic-gate 		return;
1367c478bd9Sstevel@tonic-gate 	}
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	ssh_gssapi_server_mechs(&supported_mechs);
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	do {
1417c478bd9Sstevel@tonic-gate 		mechs--;
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate 		if (oid != GSS_C_NULL_OID)
1447c478bd9Sstevel@tonic-gate 			ssh_gssapi_release_oid(&oid);
1457c478bd9Sstevel@tonic-gate 
1467c478bd9Sstevel@tonic-gate 		doid = packet_get_string(&len);
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate 		/* ick */
1497c478bd9Sstevel@tonic-gate 		if (doid[0] != 0x06 || (len > 2 && doid[1] != len - 2)) {
150c15e4e4bSjp161948 			log("Mechanism OID received using the old "
151c15e4e4bSjp161948 			    "encoding form");
1527c478bd9Sstevel@tonic-gate 			oid = ssh_gssapi_make_oid(len, doid);
1537c478bd9Sstevel@tonic-gate 		} else {
1547c478bd9Sstevel@tonic-gate 			oid = ssh_gssapi_make_oid(len - 2, doid + 2);
1557c478bd9Sstevel@tonic-gate 		}
156c15e4e4bSjp161948 
1577c478bd9Sstevel@tonic-gate 		(void) gss_test_oid_set_member(&min_status, oid,
1587c478bd9Sstevel@tonic-gate 		    supported_mechs, &present);
159c15e4e4bSjp161948 
1607c478bd9Sstevel@tonic-gate 		debug("Client offered gssapi userauth with %s (%s)",
1617c478bd9Sstevel@tonic-gate 		    ssh_gssapi_oid_to_str(oid),
1627c478bd9Sstevel@tonic-gate 		    present ? "supported" : "unsupported");
1637c478bd9Sstevel@tonic-gate 	} while (!present && (mechs > 0));
1647c478bd9Sstevel@tonic-gate 
1657c478bd9Sstevel@tonic-gate 	if (!present) {
1667c478bd9Sstevel@tonic-gate 		/* userauth_finish() will send SSH2_MSG_USERAUTH_FAILURE */
1677c478bd9Sstevel@tonic-gate 		debug2("No mechanism offered by the client is available");
1687c478bd9Sstevel@tonic-gate 		ssh_gssapi_release_oid(&oid);
1697c478bd9Sstevel@tonic-gate 		return;
1707c478bd9Sstevel@tonic-gate 	}
1717c478bd9Sstevel@tonic-gate 
172c15e4e4bSjp161948 	ssh_gssapi_build_ctx((Gssctxt **)&authctxt->method->method_data,
173c15e4e4bSjp161948 	    0, oid);
1747c478bd9Sstevel@tonic-gate 	ssh_gssapi_release_oid(&oid);
1757c478bd9Sstevel@tonic-gate 	/* Send SSH_MSG_USERAUTH_GSSAPI_RESPONSE */
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 	packet_start(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE);
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 	/* Just return whatever we found -- the matched mech does us no good */
1807c478bd9Sstevel@tonic-gate 	packet_put_string(doid, len);
1817c478bd9Sstevel@tonic-gate 	xfree(doid);
1827c478bd9Sstevel@tonic-gate 
1837c478bd9Sstevel@tonic-gate 	packet_send();
1847c478bd9Sstevel@tonic-gate 	packet_write_wait();
1857c478bd9Sstevel@tonic-gate 
1867c478bd9Sstevel@tonic-gate 	/* Setup rest of gssapi userauth conversation */
1877c478bd9Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token);
1887c478bd9Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok);
1897c478bd9Sstevel@tonic-gate 	authctxt->method->postponed = 1;
1907c478bd9Sstevel@tonic-gate }
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate static void
input_gssapi_token(int type,u_int32_t plen,void * ctxt)1937c478bd9Sstevel@tonic-gate input_gssapi_token(int type, u_int32_t plen, void *ctxt)
1947c478bd9Sstevel@tonic-gate {
1957c478bd9Sstevel@tonic-gate 	Authctxt *authctxt = ctxt;
1967c478bd9Sstevel@tonic-gate 	Gssctxt *gssctxt;
1977c478bd9Sstevel@tonic-gate 	gss_buffer_desc send_tok, recv_tok;
1987c478bd9Sstevel@tonic-gate 	OM_uint32 maj_status, min_status;
199c15e4e4bSjp161948 	uint_t len;
2007c478bd9Sstevel@tonic-gate 
2017c478bd9Sstevel@tonic-gate 	if (authctxt == NULL || authctxt->method == NULL ||
202c15e4e4bSjp161948 	    (authctxt->method->method_data == NULL)) {
203c15e4e4bSjp161948 		fatal("No authentication or GSSAPI context during "
204c15e4e4bSjp161948 		    "gssapi-with-mic userauth");
205c15e4e4bSjp161948 	}
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	gssctxt = authctxt->method->method_data;
2087c478bd9Sstevel@tonic-gate 	recv_tok.value = packet_get_string(&len);
2097c478bd9Sstevel@tonic-gate 	recv_tok.length = len; /* u_int vs. size_t */
2107c478bd9Sstevel@tonic-gate 
2119a8058b5Sjp161948 	maj_status = ssh_gssapi_accept_ctx(gssctxt, &recv_tok, &send_tok);
2127c478bd9Sstevel@tonic-gate 	packet_check_eom();
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 	if (GSS_ERROR(maj_status)) {
2157c478bd9Sstevel@tonic-gate 		ssh_gssapi_userauth_error(gssctxt);
2167c478bd9Sstevel@tonic-gate 		if (send_tok.length != 0) {
2177c478bd9Sstevel@tonic-gate 			packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
2187c478bd9Sstevel@tonic-gate 			packet_put_string(send_tok.value, send_tok.length);
2197c478bd9Sstevel@tonic-gate 			packet_send();
2207c478bd9Sstevel@tonic-gate 			packet_write_wait();
2217c478bd9Sstevel@tonic-gate 		}
2227c478bd9Sstevel@tonic-gate 		authctxt->method->postponed = 0;
2237c478bd9Sstevel@tonic-gate 		dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
2247c478bd9Sstevel@tonic-gate 		userauth_finish(authctxt, authctxt->method->name);
2257c478bd9Sstevel@tonic-gate 	} else {
2267c478bd9Sstevel@tonic-gate 		if (send_tok.length != 0) {
2277c478bd9Sstevel@tonic-gate 			packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
2287c478bd9Sstevel@tonic-gate 			packet_put_string(send_tok.value, send_tok.length);
2297c478bd9Sstevel@tonic-gate 			packet_send();
2307c478bd9Sstevel@tonic-gate 			packet_write_wait();
2317c478bd9Sstevel@tonic-gate 		}
2327c478bd9Sstevel@tonic-gate 		if (maj_status == GSS_S_COMPLETE) {
2337c478bd9Sstevel@tonic-gate 			dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
2347c478bd9Sstevel@tonic-gate 			dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC,
2357c478bd9Sstevel@tonic-gate 			    &input_gssapi_mic);
2367c478bd9Sstevel@tonic-gate 			dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,
2377c478bd9Sstevel@tonic-gate 			    &input_gssapi_exchange_complete);
2387c478bd9Sstevel@tonic-gate 		}
2397c478bd9Sstevel@tonic-gate 	}
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 	gss_release_buffer(&min_status, &send_tok);
2427c478bd9Sstevel@tonic-gate }
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate static void
input_gssapi_errtok(int type,u_int32_t plen,void * ctxt)2457c478bd9Sstevel@tonic-gate input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
2467c478bd9Sstevel@tonic-gate {
2477c478bd9Sstevel@tonic-gate 	Authctxt *authctxt = ctxt;
2487c478bd9Sstevel@tonic-gate 	Gssctxt *gssctxt;
2497c478bd9Sstevel@tonic-gate 	gss_buffer_desc send_tok, recv_tok;
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate 	if (authctxt == NULL || authctxt->method == NULL ||
252c15e4e4bSjp161948 	    (authctxt->method->method_data == NULL)) {
253c15e4e4bSjp161948 		fatal("No authentication or GSSAPI context during "
254c15e4e4bSjp161948 		    "gssapi-with-mic userauth");
255c15e4e4bSjp161948 	}
2567c478bd9Sstevel@tonic-gate 
2577c478bd9Sstevel@tonic-gate 	gssctxt = authctxt->method->method_data;
2587c478bd9Sstevel@tonic-gate 	recv_tok.value = packet_get_string(&recv_tok.length);
2597c478bd9Sstevel@tonic-gate 	packet_check_eom();
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 	/* Push the error token into GSSAPI to see what it says */
2629a8058b5Sjp161948 	(void) ssh_gssapi_accept_ctx(gssctxt, &recv_tok, &send_tok);
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate 	debug("Client sent GSS-API error token during GSS userauth-- %s",
2657c478bd9Sstevel@tonic-gate 	    ssh_gssapi_last_error(gssctxt, NULL, NULL));
2667c478bd9Sstevel@tonic-gate 
2677c478bd9Sstevel@tonic-gate 	/* We can't return anything to the client, even if we wanted to */
2687c478bd9Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
2697c478bd9Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate 
2727c478bd9Sstevel@tonic-gate 	/*
2737c478bd9Sstevel@tonic-gate 	 * The client will have already moved on to the next auth and
2747c478bd9Sstevel@tonic-gate 	 * will send a new userauth request.  The spec says that the
2757c478bd9Sstevel@tonic-gate 	 * server MUST NOT send a SSH_MSG_USERAUTH_FAILURE packet in
2767c478bd9Sstevel@tonic-gate 	 * response to this.
2777c478bd9Sstevel@tonic-gate 	 *
2787c478bd9Sstevel@tonic-gate 	 * We leave authctxt->method->postponed == 1 here so that a call
2797c478bd9Sstevel@tonic-gate 	 * to input_userauth_request() will detect this failure (as
2807c478bd9Sstevel@tonic-gate 	 * userauth abandonment) and act accordingly.
2817c478bd9Sstevel@tonic-gate 	 */
2827c478bd9Sstevel@tonic-gate }
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate static void
input_gssapi_mic(int type,u_int32_t plen,void * ctxt)2857c478bd9Sstevel@tonic-gate input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
2867c478bd9Sstevel@tonic-gate {
2877c478bd9Sstevel@tonic-gate 	Authctxt *authctxt = ctxt;
2887c478bd9Sstevel@tonic-gate 	Gssctxt *gssctxt;
2897c478bd9Sstevel@tonic-gate 	gss_buffer_desc g_mic_data, mic_tok;
2907c478bd9Sstevel@tonic-gate 	Buffer mic_data;
2917c478bd9Sstevel@tonic-gate 	OM_uint32 maj_status, min_status;
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate 	if (authctxt == NULL || authctxt->method == NULL ||
2947c478bd9Sstevel@tonic-gate 	    (authctxt->method->method_data == NULL)) {
295c15e4e4bSjp161948 		debug3("No authentication or GSSAPI context during "
296c15e4e4bSjp161948 		    "gssapi-with-mic userauth");
2977c478bd9Sstevel@tonic-gate 		return;
2987c478bd9Sstevel@tonic-gate 	}
2997c478bd9Sstevel@tonic-gate 
3007c478bd9Sstevel@tonic-gate 	gssctxt = authctxt->method->method_data;
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate 	/* Make data buffer to verify MIC with */
3037c478bd9Sstevel@tonic-gate 	buffer_init(&mic_data);
3047c478bd9Sstevel@tonic-gate 	buffer_put_string(&mic_data, session_id2, session_id2_len);
3057c478bd9Sstevel@tonic-gate 	buffer_put_char(&mic_data, SSH2_MSG_USERAUTH_REQUEST);
3067c478bd9Sstevel@tonic-gate 	buffer_put_cstring(&mic_data, authctxt->user);
3077c478bd9Sstevel@tonic-gate 	buffer_put_cstring(&mic_data, authctxt->service);
3087c478bd9Sstevel@tonic-gate 	buffer_put_cstring(&mic_data, authctxt->method->name);
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	g_mic_data.value  = buffer_ptr(&mic_data);
3117c478bd9Sstevel@tonic-gate 	g_mic_data.length = buffer_len(&mic_data);
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	mic_tok.value = packet_get_string(&mic_tok.length);
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	maj_status = gss_verify_mic(&min_status, gssctxt->context,
3167c478bd9Sstevel@tonic-gate 	    &g_mic_data, &mic_tok, NULL);
3177c478bd9Sstevel@tonic-gate 
3187c478bd9Sstevel@tonic-gate 	packet_check_eom();
3197c478bd9Sstevel@tonic-gate 	buffer_free(&mic_data);
3207c478bd9Sstevel@tonic-gate 
3217c478bd9Sstevel@tonic-gate 	if (maj_status != GSS_S_COMPLETE)
3227c478bd9Sstevel@tonic-gate 		debug2("MIC verification failed, GSSAPI userauth failed");
3237c478bd9Sstevel@tonic-gate 	else
3247c478bd9Sstevel@tonic-gate 		userauth_gssapi_finish(authctxt, gssctxt);
3257c478bd9Sstevel@tonic-gate 
3267c478bd9Sstevel@tonic-gate 	/* Delete context from keyex */
3277c478bd9Sstevel@tonic-gate 	if (xxx_gssctxt != gssctxt)
3287c478bd9Sstevel@tonic-gate 		ssh_gssapi_delete_ctx(&xxx_gssctxt);
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	/* Leave Gssctxt around for ssh_gssapi_cleanup/storecreds() */
3317c478bd9Sstevel@tonic-gate 	if (gssctxt->deleg_creds == GSS_C_NO_CREDENTIAL)
3327c478bd9Sstevel@tonic-gate 		ssh_gssapi_delete_ctx(&gssctxt);
3337c478bd9Sstevel@tonic-gate 
3347c478bd9Sstevel@tonic-gate 	xxx_gssctxt = gssctxt;
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate 	authctxt->method->postponed = 0;
3377c478bd9Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
3387c478bd9Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
3397c478bd9Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
3407c478bd9Sstevel@tonic-gate 	userauth_finish(authctxt, authctxt->method->name);
3417c478bd9Sstevel@tonic-gate }
3427c478bd9Sstevel@tonic-gate 
343c15e4e4bSjp161948 /*
344c15e4e4bSjp161948  * This is called when the client thinks we've completed authentication.
3457c478bd9Sstevel@tonic-gate  * It should only be enabled in the dispatch handler by the function above,
3467c478bd9Sstevel@tonic-gate  * which only enables it once the GSSAPI exchange is complete.
3477c478bd9Sstevel@tonic-gate  */
3487c478bd9Sstevel@tonic-gate static void
input_gssapi_exchange_complete(int type,u_int32_t plen,void * ctxt)3497c478bd9Sstevel@tonic-gate input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
3507c478bd9Sstevel@tonic-gate {
3517c478bd9Sstevel@tonic-gate 	Authctxt *authctxt = ctxt;
3527c478bd9Sstevel@tonic-gate 	Gssctxt *gssctxt;
3537c478bd9Sstevel@tonic-gate 
3547c478bd9Sstevel@tonic-gate 	packet_check_eom();
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 	if (authctxt == NULL || authctxt->method == NULL ||
3579a8058b5Sjp161948 	    (authctxt->method->method_data == NULL))
3587c478bd9Sstevel@tonic-gate 		fatal("No authentication or GSSAPI context");
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	gssctxt = authctxt->method->method_data;
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate 	/*
3637c478bd9Sstevel@tonic-gate 	 * SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE -> gssapi userauth
3647c478bd9Sstevel@tonic-gate 	 * failure, the client should use SSH2_MSG_USERAUTH_GSSAPI_MIC
3657c478bd9Sstevel@tonic-gate 	 * instead.
3667c478bd9Sstevel@tonic-gate 	 *
3677c478bd9Sstevel@tonic-gate 	 * There's two reasons for this:
3687c478bd9Sstevel@tonic-gate 	 *
3697c478bd9Sstevel@tonic-gate 	 * 1) we don't have GSS mechs that don't support integrity
3707c478bd9Sstevel@tonic-gate 	 * protection, and even if we did we'd not want to use them with
3717c478bd9Sstevel@tonic-gate 	 * SSHv2, and,
3727c478bd9Sstevel@tonic-gate 	 *
3737c478bd9Sstevel@tonic-gate 	 * 2) we currently have no way to dynamically detect whether a
3747c478bd9Sstevel@tonic-gate 	 * given mechanism does or does not support integrity
3757c478bd9Sstevel@tonic-gate 	 * protection, so when a context's flags do not indicate
3767c478bd9Sstevel@tonic-gate 	 * integrity protection we can't know if the client simply
3777c478bd9Sstevel@tonic-gate 	 * didn't request it, so we assume it didn't and reject the
3787c478bd9Sstevel@tonic-gate 	 * userauth.
3797c478bd9Sstevel@tonic-gate 	 *
3807c478bd9Sstevel@tonic-gate 	 * We could fail partially (i.e., force the use of other
3817c478bd9Sstevel@tonic-gate 	 * userauth methods without counting this one as failed).  But
3827c478bd9Sstevel@tonic-gate 	 * this will do for now.
3837c478bd9Sstevel@tonic-gate 	 */
3847c478bd9Sstevel@tonic-gate #if 0
385c15e4e4bSjp161948 	authctxt->method->authenticated = ssh_gssapi_userok(gssctxt,
386c15e4e4bSjp161948 	    authctxt->user);
3877c478bd9Sstevel@tonic-gate #endif
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate 	if (xxx_gssctxt != gssctxt)
3907c478bd9Sstevel@tonic-gate 		ssh_gssapi_delete_ctx(&gssctxt);
3917c478bd9Sstevel@tonic-gate 	ssh_gssapi_delete_ctx(&gssctxt);
3927c478bd9Sstevel@tonic-gate 	authctxt->method->postponed = 0;
3937c478bd9Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
3947c478bd9Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
3957c478bd9Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
3967c478bd9Sstevel@tonic-gate 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
3977c478bd9Sstevel@tonic-gate 	userauth_finish(authctxt, authctxt->method->name);
3987c478bd9Sstevel@tonic-gate }
3997c478bd9Sstevel@tonic-gate 
400c15e4e4bSjp161948 static void
ssh_gssapi_userauth_error(Gssctxt * ctxt)401c15e4e4bSjp161948 ssh_gssapi_userauth_error(Gssctxt *ctxt)
402c15e4e4bSjp161948 {
4037c478bd9Sstevel@tonic-gate 	char *errstr;
4047c478bd9Sstevel@tonic-gate 	OM_uint32 maj, min;
4057c478bd9Sstevel@tonic-gate 
4067c478bd9Sstevel@tonic-gate 	errstr = ssh_gssapi_last_error(ctxt, &maj, &min);
4077c478bd9Sstevel@tonic-gate 	if (errstr) {
4087c478bd9Sstevel@tonic-gate 		packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERROR);
4097c478bd9Sstevel@tonic-gate 		packet_put_int(maj);
4107c478bd9Sstevel@tonic-gate 		packet_put_int(min);
4117c478bd9Sstevel@tonic-gate 		packet_put_cstring(errstr);
4127c478bd9Sstevel@tonic-gate 		packet_put_cstring("");
4137c478bd9Sstevel@tonic-gate 		packet_send();
4147c478bd9Sstevel@tonic-gate 		packet_write_wait();
4157c478bd9Sstevel@tonic-gate 		xfree(errstr);
4167c478bd9Sstevel@tonic-gate 	}
4177c478bd9Sstevel@tonic-gate }
4187c478bd9Sstevel@tonic-gate 
4197c478bd9Sstevel@tonic-gate /*
4207c478bd9Sstevel@tonic-gate  * Code common to gssapi-keyex and gssapi-with-mic userauth.
4217c478bd9Sstevel@tonic-gate  *
4227c478bd9Sstevel@tonic-gate  * Does authorization, figures out how to store delegated creds.
4237c478bd9Sstevel@tonic-gate  */
424c15e4e4bSjp161948 static void
userauth_gssapi_finish(Authctxt * authctxt,Gssctxt * gssctxt)4257c478bd9Sstevel@tonic-gate userauth_gssapi_finish(Authctxt *authctxt, Gssctxt *gssctxt)
4267c478bd9Sstevel@tonic-gate {
4277c478bd9Sstevel@tonic-gate 	char *local_user = NULL;
428127a3018Sgm149974 	gss_buffer_desc dispname;
429127a3018Sgm149974 	OM_uint32 major;
4307c478bd9Sstevel@tonic-gate 
4317c478bd9Sstevel@tonic-gate 	if (*authctxt->user != '\0' &&
4329a8058b5Sjp161948 	    ssh_gssapi_userok(gssctxt, authctxt->user)) {
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 		/*
4357c478bd9Sstevel@tonic-gate 		 * If the client princ did not map to the requested
4367c478bd9Sstevel@tonic-gate 		 * username then we don't want to clobber existing creds
4377c478bd9Sstevel@tonic-gate 		 * for the user with the delegated creds.
4387c478bd9Sstevel@tonic-gate 		 */
4397c478bd9Sstevel@tonic-gate 		local_user = ssh_gssapi_localname(gssctxt);
4407c478bd9Sstevel@tonic-gate 		if (local_user == NULL ||
4417c478bd9Sstevel@tonic-gate 		    strcmp(local_user, authctxt->user) == 0)
4427c478bd9Sstevel@tonic-gate 			gssctxt->default_creds = 1; /* store creds as default */
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 		authctxt->method->authenticated =
4457c478bd9Sstevel@tonic-gate 		    do_pam_non_initial_userauth(authctxt);
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	} else if (*authctxt->user == '\0') {
4487c478bd9Sstevel@tonic-gate 		/* Requested username == ""; derive username from princ name */
4497c478bd9Sstevel@tonic-gate 		if ((local_user = ssh_gssapi_localname(gssctxt)) == NULL)
4507c478bd9Sstevel@tonic-gate 			return;
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 		/* Changed username (from implicit, '') */
4537c478bd9Sstevel@tonic-gate 		userauth_user_svc_change(authctxt, local_user, NULL);
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 		gssctxt->default_creds = 1; /* store creds as default */
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 		authctxt->method->authenticated =
4587c478bd9Sstevel@tonic-gate 		    do_pam_non_initial_userauth(authctxt);
4597c478bd9Sstevel@tonic-gate 	}
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 	if (local_user != NULL)
4627c478bd9Sstevel@tonic-gate 		xfree(local_user);
463127a3018Sgm149974 
464127a3018Sgm149974 	if (*authctxt->user != '\0' && authctxt->method->authenticated != 0) {
465127a3018Sgm149974 		major = gss_display_name(&gssctxt->minor, gssctxt->src_name,
466127a3018Sgm149974 		    &dispname, NULL);
467127a3018Sgm149974 		if (major == GSS_S_COMPLETE) {
468127a3018Sgm149974 			log("Authorized principal %.*s, authenticated with "
469127a3018Sgm149974 			    "GSS mechanism %s, to: %s",
470127a3018Sgm149974 			    dispname.length, (char *)dispname.value,
471127a3018Sgm149974 			    ssh_gssapi_oid_to_name(gssctxt->actual_mech),
472127a3018Sgm149974 			    authctxt->user);
473127a3018Sgm149974 		}
474127a3018Sgm149974 		(void) gss_release_buffer(&gssctxt->minor, &dispname);
475127a3018Sgm149974 	}
4767c478bd9Sstevel@tonic-gate }
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate #if 0
4797c478bd9Sstevel@tonic-gate /* Deprecated userauths -- should not be enabled */
4807c478bd9Sstevel@tonic-gate Authmethod method_external = {
4817c478bd9Sstevel@tonic-gate 	"external-keyx",
4827c478bd9Sstevel@tonic-gate 	&options.gss_authentication,
4837c478bd9Sstevel@tonic-gate 	userauth_gssapi_keyex,
4847c478bd9Sstevel@tonic-gate 	NULL,	/* no abandon function */
4857c478bd9Sstevel@tonic-gate 	NULL,
4867c478bd9Sstevel@tonic-gate 	NULL,
4877c478bd9Sstevel@tonic-gate 	/* State counters */
4887c478bd9Sstevel@tonic-gate 	0, 0, 0, 0,
4897c478bd9Sstevel@tonic-gate 	/* State flags */
4907c478bd9Sstevel@tonic-gate 	0, 0, 0, 0, 0, 0
4917c478bd9Sstevel@tonic-gate };
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate Authmethod method_gssapi = {
4947c478bd9Sstevel@tonic-gate 	"gssapi",
4957c478bd9Sstevel@tonic-gate 	&options.gss_authentication,
4967c478bd9Sstevel@tonic-gate 	userauth_gssapi,
4977c478bd9Sstevel@tonic-gate 	userauth_gssapi_abandon,
4987c478bd9Sstevel@tonic-gate 	NULL,
4997c478bd9Sstevel@tonic-gate 	NULL,
5007c478bd9Sstevel@tonic-gate 	/* State counters */
5017c478bd9Sstevel@tonic-gate 	0, 0, 0, 0,
5027c478bd9Sstevel@tonic-gate 	/* State flags */
5037c478bd9Sstevel@tonic-gate 	0, 0, 0, 0, 0, 0
5047c478bd9Sstevel@tonic-gate };
5057c478bd9Sstevel@tonic-gate #endif
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate Authmethod method_external = {
5087c478bd9Sstevel@tonic-gate 	"gssapi-keyex",
5097c478bd9Sstevel@tonic-gate 	&options.gss_authentication,
5107c478bd9Sstevel@tonic-gate 	userauth_gssapi_keyex,
5117c478bd9Sstevel@tonic-gate 	NULL,	/* no abandon function */
5127c478bd9Sstevel@tonic-gate 	NULL,
5137c478bd9Sstevel@tonic-gate 	NULL,
5147c478bd9Sstevel@tonic-gate 	/* State counters */
5157c478bd9Sstevel@tonic-gate 	0, 0, 0, 0,
5167c478bd9Sstevel@tonic-gate 	/* State flags */
5177c478bd9Sstevel@tonic-gate 	0, 0, 0, 0, 0, 0
5187c478bd9Sstevel@tonic-gate };
5197c478bd9Sstevel@tonic-gate 
5207c478bd9Sstevel@tonic-gate Authmethod method_gssapi = {
5217c478bd9Sstevel@tonic-gate 	"gssapi-with-mic",
5227c478bd9Sstevel@tonic-gate 	&options.gss_authentication,
5237c478bd9Sstevel@tonic-gate 	userauth_gssapi,
5247c478bd9Sstevel@tonic-gate 	userauth_gssapi_abandon,
5257c478bd9Sstevel@tonic-gate 	NULL,
5267c478bd9Sstevel@tonic-gate 	NULL,
5277c478bd9Sstevel@tonic-gate 	/* State counters */
5287c478bd9Sstevel@tonic-gate 	0, 0, 0, 0,
5297c478bd9Sstevel@tonic-gate 	/* State flags */
5307c478bd9Sstevel@tonic-gate 	0, 0, 0, 0, 0, 0
5317c478bd9Sstevel@tonic-gate };
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate #endif /* GSSAPI */
534