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