xref: /titanic_44/usr/src/cmd/ssh/sshd/auth2-gss.c (revision d29f5a711240f866521445b1656d114da090335e)
1 /*
2  * Copyright (c) 2001-2003 Simon Wilkinson. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
7  * 1. Redistributions of source code must retain the above copyright
8  *    notice, this list of conditions and the following disclaimer.
9  * 2. Redistributions in binary form must reproduce the above copyright
10  *    notice, this list of conditions and the following disclaimer in the
11  *    documentation and/or other materials provided with the distribution.
12  *
13  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AS IS'' AND ANY EXPRESS OR
14  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
15  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
16  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
17  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
18  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
19  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
20  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
21  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
22  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
23  */
24 /*
25  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
26  * Use is subject to license terms.
27  */
28 
29 #include "includes.h"
30 
31 #pragma ident	"%Z%%M%	%I%	%E% SMI"
32 
33 #ifdef GSSAPI
34 #include "auth.h"
35 #include "ssh2.h"
36 #include "xmalloc.h"
37 #include "log.h"
38 #include "dispatch.h"
39 #include "servconf.h"
40 #include "compat.h"
41 #include "buffer.h"
42 #include "bufaux.h"
43 #include "packet.h"
44 
45 #include <gssapi/gssapi.h>
46 #include "ssh-gss.h"
47 
48 extern ServerOptions options;
49 extern uchar_t *session_id2;
50 extern int session_id2_len;
51 extern Gssctxt *xxx_gssctxt;
52 
53 static void userauth_gssapi_finish(Authctxt *authctxt, Gssctxt *gssctxt);
54 
55 static void
56 userauth_gssapi_keyex(Authctxt *authctxt)
57 {
58 	gss_buffer_desc g_mic_data, mic_tok;
59 	Buffer mic_data;
60 	OM_uint32 maj_status, min_status;
61 
62 	if (authctxt == NULL || authctxt->method == NULL)
63 		fatal("No authentication context during gssapi-keyex userauth");
64 
65 	if (xxx_gssctxt == NULL || xxx_gssctxt->context == GSS_C_NO_CONTEXT) {
66 		/* fatal()?  or return? */
67 		debug("No GSS-API context during gssapi-keyex userauth");
68 		return;
69 	}
70 
71 	/* Make data buffer to verify MIC with */
72 	buffer_init(&mic_data);
73 	buffer_put_string(&mic_data, session_id2, session_id2_len);
74 	buffer_put_char(&mic_data, SSH2_MSG_USERAUTH_REQUEST);
75 	buffer_put_cstring(&mic_data, authctxt->user);
76 	buffer_put_cstring(&mic_data, authctxt->service);
77 	buffer_put_cstring(&mic_data, authctxt->method->name);
78 
79 	g_mic_data.value  = buffer_ptr(&mic_data);
80 	g_mic_data.length = buffer_len(&mic_data);
81 
82 	mic_tok.value = packet_get_string(&mic_tok.length);
83 
84 	maj_status = gss_verify_mic(&min_status, xxx_gssctxt->context,
85 	    &g_mic_data, &mic_tok, NULL);
86 
87 	packet_check_eom();
88 	buffer_clear(&mic_data);
89 
90 	if (maj_status != GSS_S_COMPLETE)
91 		debug2("MIC verification failed, GSSAPI userauth failed");
92 	else
93 		userauth_gssapi_finish(authctxt, xxx_gssctxt);
94 
95 	/* Leave Gssctxt around for ssh_gssapi_cleanup/storecreds() */
96 	if (xxx_gssctxt->deleg_creds == GSS_C_NO_CREDENTIAL)
97 		ssh_gssapi_delete_ctx(&xxx_gssctxt);
98 }
99 
100 static void ssh_gssapi_userauth_error(Gssctxt *ctxt);
101 static void input_gssapi_token(int type, u_int32_t plen, void *ctxt);
102 static void input_gssapi_mic(int type, u_int32_t plen, void *ctxt);
103 static void input_gssapi_errtok(int, u_int32_t, void *);
104 static void input_gssapi_exchange_complete(int type, u_int32_t plen,
105     void *ctxt);
106 
107 static void
108 userauth_gssapi_abandon(Authctxt *authctxt, Authmethod *method)
109 {
110 	ssh_gssapi_delete_ctx((Gssctxt **)&method->method_data);
111 	xxx_gssctxt = NULL;
112 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
113 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
114 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
115 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
116 }
117 
118 static void
119 userauth_gssapi(Authctxt *authctxt)
120 {
121 	gss_OID_set supported_mechs;
122 	int mechs, present = 0;
123 	OM_uint32 min_status;
124 	uint_t len;
125 	char *doid = NULL;
126 	gss_OID oid = GSS_C_NULL_OID;
127 
128 	if (datafellows & SSH_OLD_GSSAPI) {
129 		debug("Early drafts of GSSAPI userauth not supported");
130 		return;
131 	}
132 
133 	mechs = packet_get_int();
134 	if (mechs == 0) {
135 		packet_check_eom();
136 		debug("Mechanism negotiation is not supported");
137 		return;
138 	}
139 
140 	ssh_gssapi_server_mechs(&supported_mechs);
141 
142 	do {
143 		mechs--;
144 
145 		if (oid != GSS_C_NULL_OID)
146 			ssh_gssapi_release_oid(&oid);
147 
148 		doid = packet_get_string(&len);
149 
150 		/* ick */
151 		if (doid[0] != 0x06 || (len > 2 && doid[1] != len - 2)) {
152 			log("Mechanism OID received using the old "
153 			    "encoding form");
154 			oid = ssh_gssapi_make_oid(len, doid);
155 		} else {
156 			oid = ssh_gssapi_make_oid(len - 2, doid + 2);
157 		}
158 
159 		(void) gss_test_oid_set_member(&min_status, oid,
160 		    supported_mechs, &present);
161 
162 		debug("Client offered gssapi userauth with %s (%s)",
163 		    ssh_gssapi_oid_to_str(oid),
164 		    present ? "supported" : "unsupported");
165 	} while (!present && (mechs > 0));
166 
167 	if (!present) {
168 		/* userauth_finish() will send SSH2_MSG_USERAUTH_FAILURE */
169 		debug2("No mechanism offered by the client is available");
170 		ssh_gssapi_release_oid(&oid);
171 		return;
172 	}
173 
174 	ssh_gssapi_build_ctx((Gssctxt **)&authctxt->method->method_data,
175 	    0, oid);
176 	ssh_gssapi_release_oid(&oid);
177 	/* Send SSH_MSG_USERAUTH_GSSAPI_RESPONSE */
178 
179 	packet_start(SSH2_MSG_USERAUTH_GSSAPI_RESPONSE);
180 
181 	/* Just return whatever we found -- the matched mech does us no good */
182 	packet_put_string(doid, len);
183 	xfree(doid);
184 
185 	packet_send();
186 	packet_write_wait();
187 
188 	/* Setup rest of gssapi userauth conversation */
189 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, &input_gssapi_token);
190 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, &input_gssapi_errtok);
191 	authctxt->method->postponed = 1;
192 }
193 
194 static void
195 input_gssapi_token(int type, u_int32_t plen, void *ctxt)
196 {
197 	Authctxt *authctxt = ctxt;
198 	Gssctxt *gssctxt;
199 	gss_buffer_desc send_tok, recv_tok;
200 	OM_uint32 maj_status, min_status;
201 	uint_t len;
202 
203 	if (authctxt == NULL || authctxt->method == NULL ||
204 	    (authctxt->method->method_data == NULL)) {
205 		fatal("No authentication or GSSAPI context during "
206 		    "gssapi-with-mic userauth");
207 	}
208 
209 	gssctxt = authctxt->method->method_data;
210 	recv_tok.value = packet_get_string(&len);
211 	recv_tok.length = len; /* u_int vs. size_t */
212 
213 	maj_status = ssh_gssapi_accept_ctx(gssctxt, &recv_tok, &send_tok);
214 	packet_check_eom();
215 
216 	if (GSS_ERROR(maj_status)) {
217 		ssh_gssapi_userauth_error(gssctxt);
218 		if (send_tok.length != 0) {
219 			packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK);
220 			packet_put_string(send_tok.value, send_tok.length);
221 			packet_send();
222 			packet_write_wait();
223 		}
224 		authctxt->method->postponed = 0;
225 		dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
226 		userauth_finish(authctxt, authctxt->method->name);
227 	} else {
228 		if (send_tok.length != 0) {
229 			packet_start(SSH2_MSG_USERAUTH_GSSAPI_TOKEN);
230 			packet_put_string(send_tok.value, send_tok.length);
231 			packet_send();
232 			packet_write_wait();
233 		}
234 		if (maj_status == GSS_S_COMPLETE) {
235 			dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
236 			dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC,
237 			    &input_gssapi_mic);
238 			dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE,
239 			    &input_gssapi_exchange_complete);
240 		}
241 	}
242 
243 	gss_release_buffer(&min_status, &send_tok);
244 }
245 
246 static void
247 input_gssapi_errtok(int type, u_int32_t plen, void *ctxt)
248 {
249 	Authctxt *authctxt = ctxt;
250 	Gssctxt *gssctxt;
251 	gss_buffer_desc send_tok, recv_tok;
252 
253 	if (authctxt == NULL || authctxt->method == NULL ||
254 	    (authctxt->method->method_data == NULL)) {
255 		fatal("No authentication or GSSAPI context during "
256 		    "gssapi-with-mic userauth");
257 	}
258 
259 	gssctxt = authctxt->method->method_data;
260 	recv_tok.value = packet_get_string(&recv_tok.length);
261 	packet_check_eom();
262 
263 	/* Push the error token into GSSAPI to see what it says */
264 	(void) ssh_gssapi_accept_ctx(gssctxt, &recv_tok, &send_tok);
265 
266 	debug("Client sent GSS-API error token during GSS userauth-- %s",
267 	    ssh_gssapi_last_error(gssctxt, NULL, NULL));
268 
269 	/* We can't return anything to the client, even if we wanted to */
270 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
271 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
272 
273 
274 	/*
275 	 * The client will have already moved on to the next auth and
276 	 * will send a new userauth request.  The spec says that the
277 	 * server MUST NOT send a SSH_MSG_USERAUTH_FAILURE packet in
278 	 * response to this.
279 	 *
280 	 * We leave authctxt->method->postponed == 1 here so that a call
281 	 * to input_userauth_request() will detect this failure (as
282 	 * userauth abandonment) and act accordingly.
283 	 */
284 }
285 
286 static void
287 input_gssapi_mic(int type, u_int32_t plen, void *ctxt)
288 {
289 	Authctxt *authctxt = ctxt;
290 	Gssctxt *gssctxt;
291 	gss_buffer_desc g_mic_data, mic_tok;
292 	Buffer mic_data;
293 	OM_uint32 maj_status, min_status;
294 
295 	if (authctxt == NULL || authctxt->method == NULL ||
296 	    (authctxt->method->method_data == NULL)) {
297 		debug3("No authentication or GSSAPI context during "
298 		    "gssapi-with-mic userauth");
299 		return;
300 	}
301 
302 	gssctxt = authctxt->method->method_data;
303 
304 	/* Make data buffer to verify MIC with */
305 	buffer_init(&mic_data);
306 	buffer_put_string(&mic_data, session_id2, session_id2_len);
307 	buffer_put_char(&mic_data, SSH2_MSG_USERAUTH_REQUEST);
308 	buffer_put_cstring(&mic_data, authctxt->user);
309 	buffer_put_cstring(&mic_data, authctxt->service);
310 	buffer_put_cstring(&mic_data, authctxt->method->name);
311 
312 	g_mic_data.value  = buffer_ptr(&mic_data);
313 	g_mic_data.length = buffer_len(&mic_data);
314 
315 	mic_tok.value = packet_get_string(&mic_tok.length);
316 
317 	maj_status = gss_verify_mic(&min_status, gssctxt->context,
318 	    &g_mic_data, &mic_tok, NULL);
319 
320 	packet_check_eom();
321 	buffer_free(&mic_data);
322 
323 	if (maj_status != GSS_S_COMPLETE)
324 		debug2("MIC verification failed, GSSAPI userauth failed");
325 	else
326 		userauth_gssapi_finish(authctxt, gssctxt);
327 
328 	/* Delete context from keyex */
329 	if (xxx_gssctxt != gssctxt)
330 		ssh_gssapi_delete_ctx(&xxx_gssctxt);
331 
332 	/* Leave Gssctxt around for ssh_gssapi_cleanup/storecreds() */
333 	if (gssctxt->deleg_creds == GSS_C_NO_CREDENTIAL)
334 		ssh_gssapi_delete_ctx(&gssctxt);
335 
336 	xxx_gssctxt = gssctxt;
337 
338 	authctxt->method->postponed = 0;
339 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
340 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
341 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
342 	userauth_finish(authctxt, authctxt->method->name);
343 }
344 
345 /*
346  * This is called when the client thinks we've completed authentication.
347  * It should only be enabled in the dispatch handler by the function above,
348  * which only enables it once the GSSAPI exchange is complete.
349  */
350 static void
351 input_gssapi_exchange_complete(int type, u_int32_t plen, void *ctxt)
352 {
353 	Authctxt *authctxt = ctxt;
354 	Gssctxt *gssctxt;
355 
356 	packet_check_eom();
357 
358 	if (authctxt == NULL || authctxt->method == NULL ||
359 	    (authctxt->method->method_data == NULL))
360 		fatal("No authentication or GSSAPI context");
361 
362 	gssctxt = authctxt->method->method_data;
363 
364 	/*
365 	 * SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE -> gssapi userauth
366 	 * failure, the client should use SSH2_MSG_USERAUTH_GSSAPI_MIC
367 	 * instead.
368 	 *
369 	 * There's two reasons for this:
370 	 *
371 	 * 1) we don't have GSS mechs that don't support integrity
372 	 * protection, and even if we did we'd not want to use them with
373 	 * SSHv2, and,
374 	 *
375 	 * 2) we currently have no way to dynamically detect whether a
376 	 * given mechanism does or does not support integrity
377 	 * protection, so when a context's flags do not indicate
378 	 * integrity protection we can't know if the client simply
379 	 * didn't request it, so we assume it didn't and reject the
380 	 * userauth.
381 	 *
382 	 * We could fail partially (i.e., force the use of other
383 	 * userauth methods without counting this one as failed).  But
384 	 * this will do for now.
385 	 */
386 #if 0
387 	authctxt->method->authenticated = ssh_gssapi_userok(gssctxt,
388 	    authctxt->user);
389 #endif
390 
391 	if (xxx_gssctxt != gssctxt)
392 		ssh_gssapi_delete_ctx(&gssctxt);
393 	ssh_gssapi_delete_ctx(&gssctxt);
394 	authctxt->method->postponed = 0;
395 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL);
396 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_ERRTOK, NULL);
397 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_MIC, NULL);
398 	dispatch_set(SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL);
399 	userauth_finish(authctxt, authctxt->method->name);
400 }
401 
402 static void
403 ssh_gssapi_userauth_error(Gssctxt *ctxt)
404 {
405 	char *errstr;
406 	OM_uint32 maj, min;
407 
408 	errstr = ssh_gssapi_last_error(ctxt, &maj, &min);
409 	if (errstr) {
410 		packet_start(SSH2_MSG_USERAUTH_GSSAPI_ERROR);
411 		packet_put_int(maj);
412 		packet_put_int(min);
413 		packet_put_cstring(errstr);
414 		packet_put_cstring("");
415 		packet_send();
416 		packet_write_wait();
417 		xfree(errstr);
418 	}
419 }
420 
421 /*
422  * Code common to gssapi-keyex and gssapi-with-mic userauth.
423  *
424  * Does authorization, figures out how to store delegated creds.
425  */
426 static void
427 userauth_gssapi_finish(Authctxt *authctxt, Gssctxt *gssctxt)
428 {
429 	char *local_user = NULL;
430 	gss_buffer_desc dispname;
431 	OM_uint32 major;
432 
433 	if (*authctxt->user != '\0' &&
434 	    ssh_gssapi_userok(gssctxt, authctxt->user)) {
435 
436 		/*
437 		 * If the client princ did not map to the requested
438 		 * username then we don't want to clobber existing creds
439 		 * for the user with the delegated creds.
440 		 */
441 		local_user = ssh_gssapi_localname(gssctxt);
442 		if (local_user == NULL ||
443 		    strcmp(local_user, authctxt->user) == 0)
444 			gssctxt->default_creds = 1; /* store creds as default */
445 
446 		authctxt->method->authenticated =
447 		    do_pam_non_initial_userauth(authctxt);
448 
449 	} else if (*authctxt->user == '\0') {
450 		/* Requested username == ""; derive username from princ name */
451 		if ((local_user = ssh_gssapi_localname(gssctxt)) == NULL)
452 			return;
453 
454 		/* Changed username (from implicit, '') */
455 		userauth_user_svc_change(authctxt, local_user, NULL);
456 
457 		gssctxt->default_creds = 1; /* store creds as default */
458 
459 		authctxt->method->authenticated =
460 		    do_pam_non_initial_userauth(authctxt);
461 	}
462 
463 	if (local_user != NULL)
464 		xfree(local_user);
465 
466 	if (*authctxt->user != '\0' && authctxt->method->authenticated != 0) {
467 		major = gss_display_name(&gssctxt->minor, gssctxt->src_name,
468 		    &dispname, NULL);
469 		if (major == GSS_S_COMPLETE) {
470 			log("Authorized principal %.*s, authenticated with "
471 			    "GSS mechanism %s, to: %s",
472 			    dispname.length, (char *)dispname.value,
473 			    ssh_gssapi_oid_to_name(gssctxt->actual_mech),
474 			    authctxt->user);
475 		}
476 		(void) gss_release_buffer(&gssctxt->minor, &dispname);
477 	}
478 }
479 
480 #if 0
481 /* Deprecated userauths -- should not be enabled */
482 Authmethod method_external = {
483 	"external-keyx",
484 	&options.gss_authentication,
485 	userauth_gssapi_keyex,
486 	NULL,	/* no abandon function */
487 	NULL,
488 	NULL,
489 	/* State counters */
490 	0, 0, 0, 0,
491 	/* State flags */
492 	0, 0, 0, 0, 0, 0
493 };
494 
495 Authmethod method_gssapi = {
496 	"gssapi",
497 	&options.gss_authentication,
498 	userauth_gssapi,
499 	userauth_gssapi_abandon,
500 	NULL,
501 	NULL,
502 	/* State counters */
503 	0, 0, 0, 0,
504 	/* State flags */
505 	0, 0, 0, 0, 0, 0
506 };
507 #endif
508 
509 Authmethod method_external = {
510 	"gssapi-keyex",
511 	&options.gss_authentication,
512 	userauth_gssapi_keyex,
513 	NULL,	/* no abandon function */
514 	NULL,
515 	NULL,
516 	/* State counters */
517 	0, 0, 0, 0,
518 	/* State flags */
519 	0, 0, 0, 0, 0, 0
520 };
521 
522 Authmethod method_gssapi = {
523 	"gssapi-with-mic",
524 	&options.gss_authentication,
525 	userauth_gssapi,
526 	userauth_gssapi_abandon,
527 	NULL,
528 	NULL,
529 	/* State counters */
530 	0, 0, 0, 0,
531 	/* State flags */
532 	0, 0, 0, 0, 0, 0
533 };
534 
535 #endif /* GSSAPI */
536