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 * 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 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 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 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* 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 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 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 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 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 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 * 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 * 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 * 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 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