1 /*
2 * Copyright (c) 2000 Markus Friedl. 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 (c) 2001, 2010, Oracle and/or its affiliates. All rights reserved.
26 */
27
28 #include "includes.h"
29 RCSID("$OpenBSD: auth2.c,v 1.95 2002/08/22 21:33:58 markus Exp $");
30
31 #include "ssh2.h"
32 #include "xmalloc.h"
33 #include "packet.h"
34 #include "log.h"
35 #include "servconf.h"
36 #include "compat.h"
37 #include "misc.h"
38 #include "auth.h"
39 #include "dispatch.h"
40 #include "sshlogin.h"
41 #include "pathnames.h"
42
43 #ifdef HAVE_BSM
44 #include "bsmaudit.h"
45 extern adt_session_data_t *ah;
46 #endif /* HAVE_BSM */
47
48 #ifdef GSSAPI
49 #include "ssh-gss.h"
50 #endif
51
52 /* import */
53 extern ServerOptions options;
54 extern u_char *session_id2;
55 extern int session_id2_len;
56
57 Authctxt *x_authctxt = NULL;
58
59 /* methods */
60
61 extern Authmethod method_none;
62 extern Authmethod method_pubkey;
63 extern Authmethod method_passwd;
64 extern Authmethod method_kbdint;
65 extern Authmethod method_hostbased;
66 extern Authmethod method_external;
67 extern Authmethod method_gssapi;
68
69 static Authmethod *authmethods[] = {
70 &method_none,
71 #ifdef GSSAPI
72 &method_external,
73 &method_gssapi,
74 #endif
75 &method_pubkey,
76 &method_passwd,
77 &method_kbdint,
78 &method_hostbased,
79 NULL
80 };
81
82 /* protocol */
83
84 static void input_service_request(int, u_int32_t, void *);
85 static void input_userauth_request(int, u_int32_t, void *);
86
87 /* helper */
88 static Authmethod *authmethod_lookup(const char *);
89 static char *authmethods_get(void);
90 static char *authmethods_check_abandonment(Authctxt *authctxt,
91 Authmethod *method);
92 static void authmethod_count_attempt(Authmethod *method);
93 /*static char *authmethods_get_kbdint(void);*/
94 int user_key_allowed(struct passwd *, Key *);
95 int hostbased_key_allowed(struct passwd *, const char *, char *, Key *);
96 static int userauth_method_can_run(Authmethod *method);
97 static void userauth_reset_methods(void);
98
99 /*
100 * loop until authctxt->success == TRUE
101 */
102
103 Authctxt *
do_authentication2(void)104 do_authentication2(void)
105 {
106 Authctxt *authctxt = authctxt_new();
107
108 x_authctxt = authctxt; /*XXX*/
109
110 #ifdef HAVE_BSM
111 fatal_add_cleanup(audit_failed_login_cleanup, authctxt);
112 #endif /* HAVE_BSM */
113
114 dispatch_init(&dispatch_protocol_error);
115 dispatch_set(SSH2_MSG_SERVICE_REQUEST, &input_service_request);
116 dispatch_run(DISPATCH_BLOCK, &authctxt->success, authctxt);
117
118 return (authctxt);
119 }
120
121 static void
input_service_request(int type,u_int32_t seq,void * ctxt)122 input_service_request(int type, u_int32_t seq, void *ctxt)
123 {
124 Authctxt *authctxt = ctxt;
125 u_int len;
126 int acceptit = 0;
127 char *service = packet_get_string(&len);
128 packet_check_eom();
129
130 if (authctxt == NULL)
131 fatal("input_service_request: no authctxt");
132
133 if (strcmp(service, "ssh-userauth") == 0) {
134 if (!authctxt->success) {
135 acceptit = 1;
136 /* now we can handle user-auth requests */
137 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &input_userauth_request);
138 }
139 }
140 /* XXX all other service requests are denied */
141
142 if (acceptit) {
143 packet_start(SSH2_MSG_SERVICE_ACCEPT);
144 packet_put_cstring(service);
145 packet_send();
146 packet_write_wait();
147 } else {
148 debug("bad service request %s", service);
149 packet_disconnect("bad service request %s", service);
150 }
151 xfree(service);
152 }
153
154 static void
input_userauth_request(int type,u_int32_t seq,void * ctxt)155 input_userauth_request(int type, u_int32_t seq, void *ctxt)
156 {
157 Authctxt *authctxt = ctxt;
158 Authmethod *m = NULL;
159 char *user, *service, *method, *style = NULL;
160 int valid_attempt;
161
162 if (authctxt == NULL)
163 fatal("input_userauth_request: no authctxt");
164
165 user = packet_get_string(NULL);
166 service = packet_get_string(NULL);
167 method = packet_get_string(NULL);
168 debug("userauth-request for user %s service %s method %s", user,
169 service, method);
170 debug("attempt %d initial attempt %d failures %d initial failures %d",
171 authctxt->attempt, authctxt->init_attempt,
172 authctxt->failures, authctxt->init_failures);
173
174 m = authmethod_lookup(method);
175
176 if ((style = strchr(user, ':')) != NULL)
177 *style++ = 0;
178
179 authctxt->attempt++;
180 if (m != NULL && m->is_initial)
181 authctxt->init_attempt++;
182
183 if (options.pre_userauth_hook != NULL &&
184 run_auth_hook(options.pre_userauth_hook, user, m->name) != 0) {
185 valid_attempt = 0;
186 } else {
187 valid_attempt = 1;
188 }
189
190 if (authctxt->attempt == 1) {
191 /* setup auth context */
192 authctxt->pw = getpwnamallow(user);
193 /* May want to abstract SSHv2 services someday */
194 if (authctxt->pw && strcmp(service, "ssh-connection")==0) {
195 /* enforced in userauth_finish() below */
196 if (valid_attempt) {
197 authctxt->valid = 1;
198 }
199 debug2("input_userauth_request: setting up authctxt for %s", user);
200 } else {
201 log("input_userauth_request: illegal user %s", user);
202 }
203 setproctitle("%s", authctxt->pw ? user : "unknown");
204 authctxt->user = xstrdup(user);
205 authctxt->service = xstrdup(service);
206 authctxt->style = style ? xstrdup(style) : NULL;
207 userauth_reset_methods();
208 } else {
209 char *abandoned;
210
211 /*
212 * Check for abandoned [multi-round-trip] userauths
213 * methods (e.g., kbdint). Userauth method abandonment
214 * should be treated as userauth method failure and
215 * counted against max_auth_tries.
216 */
217 abandoned = authmethods_check_abandonment(authctxt, m);
218
219 if (abandoned != NULL &&
220 authctxt->failures > options.max_auth_tries) {
221 /* userauth_finish() will now packet_disconnect() */
222 userauth_finish(authctxt, abandoned);
223 /* NOTREACHED */
224 }
225
226 /* Handle user|service changes, possibly packet_disconnect() */
227 userauth_user_svc_change(authctxt, user, service);
228 }
229
230 authctxt->method = m;
231
232 /* run userauth method, try to authenticate user */
233 if (m != NULL && userauth_method_can_run(m)) {
234 debug2("input_userauth_request: try method %s", method);
235
236 m->postponed = 0;
237 m->abandoned = 0;
238 m->authenticated = 0;
239
240 if (!m->is_initial ||
241 authctxt->init_failures < options.max_init_auth_tries)
242 m->userauth(authctxt);
243
244 authmethod_count_attempt(m);
245
246 if (authctxt->unwind_dispatch_loop) {
247 /*
248 * Method ran nested dispatch loop but was
249 * abandoned. Cleanup and return without doing
250 * anything else; we're just unwinding the stack.
251 */
252 authctxt->unwind_dispatch_loop = 0;
253 goto done;
254 }
255
256 if (m->postponed)
257 goto done; /* multi-round trip userauth not finished */
258
259 if (m->abandoned) {
260 /* multi-round trip userauth abandoned, log failure */
261 auth_log(authctxt, 0, method, " ssh2");
262 goto done;
263 }
264 }
265
266 userauth_finish(authctxt, method);
267
268 done:
269 xfree(service);
270 xfree(user);
271 xfree(method);
272 }
273
274 void
userauth_finish(Authctxt * authctxt,char * method)275 userauth_finish(Authctxt *authctxt, char *method)
276 {
277 int authenticated, partial;
278
279 if (authctxt == NULL)
280 fatal("%s: missing context", __func__);
281
282 /* unknown method handling -- must elicit userauth failure msg */
283 if (authctxt->method == NULL) {
284 authenticated = 0;
285 partial = 0;
286 goto done_checking;
287 }
288
289 #ifndef USE_PAM
290 /* Special handling for root (done elsewhere for PAM) */
291 if (authctxt->method->authenticated &&
292 authctxt->pw != NULL && authctxt->pw->pw_uid == 0 &&
293 !auth_root_allowed(method))
294 authctxt->method->authenticated = 0;
295 #endif /* USE_PAM */
296
297 #ifdef _UNICOS
298 if (authctxt->method->authenticated &&
299 cray_access_denied(authctxt->user)) {
300 authctxt->method->authenticated = 0;
301 fatal("Access denied for user %s.",authctxt->user);
302 }
303 #endif /* _UNICOS */
304
305 partial = userauth_check_partial_failure(authctxt);
306 authenticated = authctxt->method->authenticated;
307
308 #ifdef USE_PAM
309 /*
310 * If the userauth method failed to complete PAM work then force
311 * partial failure.
312 */
313 if (authenticated && !AUTHPAM_DONE(authctxt))
314 partial = 1;
315 #endif /* USE_PAM */
316
317 /*
318 * To properly support invalid userauth method names we set
319 * authenticated=0, partial=0 above and know that
320 * authctxt->method == NULL.
321 *
322 * No unguarded reference to authctxt->method allowed from here.
323 * Checking authenticated != 0 is a valid guard; authctxt->method
324 * MUST NOT be NULL if authenticated.
325 */
326 done_checking:
327 if (!authctxt->valid && authenticated) {
328 /*
329 * We get here if the PreUserauthHook fails but the
330 * user is otherwise valid.
331 * An error in the PAM handling could also get us here
332 * but we need not panic, just treat as a failure.
333 */
334 authctxt->method->authenticated = 0;
335 authenticated = 0;
336 log("Ignoring authenticated invalid user %s",
337 authctxt->user);
338 auth_log(authctxt, 0, method, " ssh2");
339 }
340
341 /* Log before sending the reply */
342 auth_log(authctxt, authenticated, method, " ssh2");
343
344 if (authenticated && !partial) {
345
346 /* turn off userauth */
347 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore);
348 packet_start(SSH2_MSG_USERAUTH_SUCCESS);
349 packet_send();
350 packet_write_wait();
351 /* now we can break out */
352 authctxt->success = 1;
353 } else {
354 char *methods;
355
356 if (authctxt->method && authctxt->method->is_initial)
357 authctxt->init_failures++;
358
359 authctxt->method = NULL;
360
361 #ifdef USE_PAM
362 /*
363 * Keep track of last PAM error (or PERM_DENIED) for BSM
364 * login failure auditing, which may run after the PAM
365 * state has been cleaned up.
366 */
367 authctxt->pam_retval = AUTHPAM_ERROR(authctxt, PAM_PERM_DENIED);
368 #endif /* USE_PAM */
369
370 if (authctxt->failures++ > options.max_auth_tries) {
371 #ifdef HAVE_BSM
372 fatal_remove_cleanup(audit_failed_login_cleanup,
373 authctxt);
374 audit_sshd_login_failure(&ah, PAM_MAXTRIES,
375 authctxt->user);
376 #endif /* HAVE_BSM */
377 packet_disconnect(AUTH_FAIL_MSG, authctxt->user);
378 }
379
380 #ifdef _UNICOS
381 if (strcmp(method, "password") == 0)
382 cray_login_failure(authctxt->user, IA_UDBERR);
383 #endif /* _UNICOS */
384 packet_start(SSH2_MSG_USERAUTH_FAILURE);
385
386 /*
387 * If (partial) then authmethods_get() will return only
388 * required methods, likely only "keyboard-interactive;"
389 * (methods == NULL) implies failure, even if (partial == 1)
390 */
391 methods = authmethods_get();
392 packet_put_cstring(methods);
393 packet_put_char((authenticated && partial && methods) ? 1 : 0);
394 if (methods)
395 xfree(methods);
396 packet_send();
397 packet_write_wait();
398 }
399 }
400
401 /* get current user */
402
403 struct passwd*
auth_get_user(void)404 auth_get_user(void)
405 {
406 return (x_authctxt != NULL && x_authctxt->valid) ? x_authctxt->pw : NULL;
407 }
408
409 #define DELIM ","
410
411 #if 0
412 static char *
413 authmethods_get_kbdint(void)
414 {
415 Buffer b;
416 int i;
417
418 for (i = 0; authmethods[i] != NULL; i++) {
419 if (strcmp(authmethods[i]->name, "keyboard-interactive") != 0)
420 continue;
421 return xstrdup(authmethods[i]->name);
422 }
423 return NULL;
424 }
425 #endif
426
427 void
userauth_user_svc_change(Authctxt * authctxt,char * user,char * service)428 userauth_user_svc_change(Authctxt *authctxt, char *user, char *service)
429 {
430 /*
431 * NOTE:
432 *
433 * SSHv2 services should be abstracted and service changes during
434 * userauth should be supported as per the userauth draft. In the PAM
435 * case, support for multiple SSHv2 services means that we have to
436 * format the PAM service name according to the SSHv2 service *and* the
437 * SSHv2 userauth being attempted ("passwd", "kbdint" and "other").
438 *
439 * We'll cross that bridge when we come to it. For now disallow service
440 * changes during userauth if using PAM, but allow username changes.
441 */
442
443 /* authctxt->service must == ssh-connection here */
444 if (service != NULL && strcmp(service, authctxt->service) != 0) {
445 packet_disconnect("Change of service not "
446 "allowed: %s and %s",
447 authctxt->service, service);
448 }
449 if (user != NULL && authctxt->user != NULL &&
450 strcmp(user, authctxt->user) == 0)
451 return;
452
453 /* All good; update authctxt */
454 xfree(authctxt->user);
455 authctxt->user = xstrdup(user);
456 pwfree(&authctxt->pw);
457 authctxt->pw = getpwnamallow(user);
458 authctxt->valid = (authctxt->pw != NULL);
459
460 /* Forget method state; abandon postponed userauths */
461 userauth_reset_methods();
462 }
463
464 int
userauth_check_partial_failure(Authctxt * authctxt)465 userauth_check_partial_failure(Authctxt *authctxt)
466 {
467 int i;
468 int required = 0;
469 int sufficient = 0;
470
471 /*
472 * v1 does not set authctxt->method
473 * partial userauth failure is a v2 concept
474 */
475 if (authctxt->method == NULL)
476 return 0;
477
478 for (i = 0; authmethods[i] != NULL; i++) {
479 if (authmethods[i]->required)
480 required++;
481 if (authmethods[i]->sufficient)
482 sufficient++;
483 }
484
485 if (required == 0 && sufficient == 0)
486 return !authctxt->method->authenticated;
487
488 if (required == 1 && authctxt->method->required)
489 return !authctxt->method->authenticated;
490
491 if (sufficient && authctxt->method->sufficient)
492 return !authctxt->method->authenticated;
493
494 return 1;
495 }
496
497 int
userauth_method_can_run(Authmethod * method)498 userauth_method_can_run(Authmethod *method)
499 {
500 if (method->not_again)
501 return 0;
502
503 return 1;
504 }
505
506 static
507 void
userauth_reset_methods(void)508 userauth_reset_methods(void)
509 {
510 int i;
511
512 for (i = 0; authmethods[i] != NULL; i++) {
513 /* note: counters not reset */
514 authmethods[i]->required = 0;
515 authmethods[i]->sufficient = 0;
516 authmethods[i]->authenticated = 0;
517 authmethods[i]->not_again = 0;
518 authmethods[i]->postponed = 0;
519 authmethods[i]->abandoned = 0;
520 }
521 }
522
523 void
userauth_force_kbdint(void)524 userauth_force_kbdint(void)
525 {
526 int i;
527
528 for (i = 0; authmethods[i] != NULL; i++) {
529 authmethods[i]->required = 0;
530 authmethods[i]->sufficient = 0;
531 }
532 method_kbdint.required = 1;
533 }
534
535 /*
536 * Check to see if a previously run multi-round trip userauth method has
537 * been abandoned and call its cleanup function.
538 *
539 * Abandoned userauth method invocations are counted as userauth failures.
540 */
541 static
542 char *
authmethods_check_abandonment(Authctxt * authctxt,Authmethod * method)543 authmethods_check_abandonment(Authctxt *authctxt, Authmethod *method)
544 {
545 int i;
546
547 /* optimization: check current method first */
548 if (method && method->postponed) {
549 method->postponed = 0;
550 if (method->abandon)
551 method->abandon(authctxt, method);
552 else
553 method->abandons++;
554 authctxt->failures++; /* abandonment -> failure */
555 if (method->is_initial)
556 authctxt->init_failures++;
557
558 /*
559 * Since we check for abandonment whenever a userauth is
560 * requested we know only one method could have been
561 * in postponed state, so we can return now.
562 */
563 return (method->name);
564 }
565 for (i = 0; authmethods[i] != NULL; i++) {
566 if (!authmethods[i]->postponed)
567 continue;
568
569 /* some method was postponed and a diff one is being started */
570 if (method != authmethods[i]) {
571 authmethods[i]->postponed = 0;
572 if (authmethods[i]->abandon)
573 authmethods[i]->abandon(authctxt,
574 authmethods[i]);
575 else
576 authmethods[i]->abandons++;
577 authctxt->failures++;
578 if (authmethods[i]->is_initial)
579 authctxt->init_failures++;
580 return (authmethods[i]->name); /* see above */
581 }
582 }
583
584 return NULL;
585 }
586
587 static char *
authmethods_get(void)588 authmethods_get(void)
589 {
590 Buffer b;
591 char *list;
592 int i;
593 int sufficient = 0;
594 int required = 0;
595 int authenticated = 0;
596 int partial = 0;
597
598 /*
599 * If at least one method succeeded partially then at least one
600 * authmethod will be required and only required methods should
601 * continue.
602 */
603 for (i = 0; authmethods[i] != NULL; i++) {
604 if (authmethods[i]->authenticated)
605 authenticated++;
606 if (authmethods[i]->required)
607 required++;
608 if (authmethods[i]->sufficient)
609 sufficient++;
610 }
611
612 partial = (required + sufficient) > 0;
613
614 buffer_init(&b);
615 for (i = 0; authmethods[i] != NULL; i++) {
616 if (strcmp(authmethods[i]->name, "none") == 0)
617 continue;
618 if (required && !authmethods[i]->required)
619 continue;
620 if (sufficient && !required && !authmethods[i]->sufficient)
621 continue;
622 if (authmethods[i]->not_again)
623 continue;
624
625 if (authmethods[i]->required) {
626 if (buffer_len(&b) > 0)
627 buffer_append(&b, ",", 1);
628 buffer_append(&b, authmethods[i]->name,
629 strlen(authmethods[i]->name));
630 continue;
631 }
632
633 /*
634 * A method can be enabled (marked sufficient)
635 * dynamically provided that at least one other method
636 * has succeeded partially.
637 */
638 if ((partial && authmethods[i]->sufficient) ||
639 (authmethods[i]->enabled != NULL &&
640 *(authmethods[i]->enabled) != 0)) {
641 if (buffer_len(&b) > 0)
642 buffer_append(&b, ",", 1);
643 buffer_append(&b, authmethods[i]->name,
644 strlen(authmethods[i]->name));
645 }
646 }
647 buffer_append(&b, "\0", 1);
648 list = xstrdup(buffer_ptr(&b));
649 buffer_free(&b);
650 return list;
651 }
652
653 static Authmethod *
authmethod_lookup(const char * name)654 authmethod_lookup(const char *name)
655 {
656 int i;
657
658 /*
659 * Method must be sufficient, required or enabled and must not
660 * be marked as not able to run again
661 */
662 if (name != NULL)
663 for (i = 0; authmethods[i] != NULL; i++)
664 if (((authmethods[i]->sufficient ||
665 authmethods[i]->required) ||
666 (authmethods[i]->enabled != NULL &&
667 *(authmethods[i]->enabled) != 0)) &&
668 !authmethods[i]->not_again &&
669 strcmp(name, authmethods[i]->name) == 0)
670 return authmethods[i];
671 debug2("Unrecognized authentication method name: %s",
672 name ? name : "NULL");
673 return NULL;
674 }
675
676 static void
authmethod_count_attempt(Authmethod * method)677 authmethod_count_attempt(Authmethod *method)
678 {
679 if (!method)
680 fatal("Internal error in authmethod_count_attempt()");
681
682 if (method->postponed)
683 return;
684
685 method->attempts++;
686
687 if (method->abandoned)
688 method->abandons++;
689 else if (method->authenticated)
690 method->successes++;
691 else
692 method->failures++;
693
694 return;
695 }
696