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