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