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 2008 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 168 if (authctxt == NULL) 169 fatal("input_userauth_request: no authctxt"); 170 171 user = packet_get_string(NULL); 172 service = packet_get_string(NULL); 173 method = packet_get_string(NULL); 174 debug("userauth-request for user %s service %s method %s", user, 175 service, method); 176 debug("attempt %d initial attempt %d failures %d initial failures %d", 177 authctxt->attempt, authctxt->init_attempt, 178 authctxt->failures, authctxt->init_failures); 179 180 m = authmethod_lookup(method); 181 182 if ((style = strchr(user, ':')) != NULL) 183 *style++ = 0; 184 185 authctxt->attempt++; 186 if (m != NULL && m->is_initial) 187 authctxt->init_attempt++; 188 189 if (authctxt->attempt == 1) { 190 /* setup auth context */ 191 authctxt->pw = getpwnamallow(user); 192 /* May want to abstract SSHv2 services someday */ 193 if (authctxt->pw && strcmp(service, "ssh-connection")==0) { 194 /* enforced in userauth_finish() below */ 195 authctxt->valid = 1; 196 debug2("input_userauth_request: setting up authctxt for %s", user); 197 } else { 198 log("input_userauth_request: illegal user %s", user); 199 } 200 setproctitle("%s", authctxt->pw ? user : "unknown"); 201 authctxt->user = xstrdup(user); 202 authctxt->service = xstrdup(service); 203 authctxt->style = style ? xstrdup(style) : NULL; 204 userauth_reset_methods(); 205 } else { 206 char *abandoned; 207 208 /* 209 * Check for abandoned [multi-round-trip] userauths 210 * methods (e.g., kbdint). Userauth method abandonment 211 * should be treated as userauth method failure and 212 * counted against max_auth_tries. 213 */ 214 abandoned = authmethods_check_abandonment(authctxt, m); 215 216 if (abandoned != NULL && 217 authctxt->failures > options.max_auth_tries) { 218 /* userauth_finish() will now packet_disconnect() */ 219 userauth_finish(authctxt, abandoned); 220 /* NOTREACHED */ 221 } 222 223 /* Handle user|service changes, possibly packet_disconnect() */ 224 userauth_user_svc_change(authctxt, user, service); 225 } 226 227 authctxt->method = m; 228 229 /* run userauth method, try to authenticate user */ 230 if (m != NULL && userauth_method_can_run(m)) { 231 debug2("input_userauth_request: try method %s", method); 232 233 m->postponed = 0; 234 m->abandoned = 0; 235 m->authenticated = 0; 236 237 if (!m->is_initial || 238 authctxt->init_failures < options.max_init_auth_tries) 239 m->userauth(authctxt); 240 241 authmethod_count_attempt(m); 242 243 if (authctxt->unwind_dispatch_loop) { 244 /* 245 * Method ran nested dispatch loop but was 246 * abandoned. Cleanup and return without doing 247 * anything else; we're just unwinding the stack. 248 */ 249 authctxt->unwind_dispatch_loop = 0; 250 goto done; 251 } 252 253 if (m->postponed) 254 goto done; /* multi-round trip userauth not finished */ 255 256 if (m->abandoned) { 257 /* multi-round trip userauth abandoned, log failure */ 258 auth_log(authctxt, 0, method, " ssh2"); 259 goto done; 260 } 261 } 262 263 userauth_finish(authctxt, method); 264 265 done: 266 xfree(service); 267 xfree(user); 268 xfree(method); 269 } 270 271 void 272 userauth_finish(Authctxt *authctxt, char *method) 273 { 274 int authenticated, partial; 275 276 if (authctxt == NULL) 277 fatal("%s: missing context", __func__); 278 279 /* unknown method handling -- must elicit userauth failure msg */ 280 if (authctxt->method == NULL) { 281 authenticated = 0; 282 partial = 0; 283 goto done_checking; 284 } 285 286 #ifndef USE_PAM 287 /* Special handling for root (done elsewhere for PAM) */ 288 if (authctxt->method->authenticated && 289 authctxt->pw != NULL && authctxt->pw->pw_uid == 0 && 290 !auth_root_allowed(method)) 291 authctxt->method->authenticated = 0; 292 #endif /* USE_PAM */ 293 294 #ifdef _UNICOS 295 if (authctxt->method->authenticated && 296 cray_access_denied(authctxt->user)) { 297 authctxt->method->authenticated = 0; 298 fatal("Access denied for user %s.",authctxt->user); 299 } 300 #endif /* _UNICOS */ 301 302 partial = userauth_check_partial_failure(authctxt); 303 authenticated = authctxt->method->authenticated; 304 305 #ifdef USE_PAM 306 /* 307 * If the userauth method failed to complete PAM work then force 308 * partial failure. 309 */ 310 if (authenticated && !AUTHPAM_DONE(authctxt)) 311 partial = 1; 312 #endif /* USE_PAM */ 313 314 /* 315 * To properly support invalid userauth method names we set 316 * authenticated=0, partial=0 above and know that 317 * authctxt->method == NULL. 318 * 319 * No unguarded reference to authctxt->method allowed from here. 320 * Checking authenticated != 0 is a valid guard; authctxt->method 321 * MUST NOT be NULL if authenticated. 322 */ 323 done_checking: 324 if (!authctxt->valid && authenticated) { 325 /* 326 * Should never happen -- if it does PAM's at fault 327 * but we need not panic, just treat as a failure. 328 */ 329 authctxt->method->authenticated = 0; 330 authenticated = 0; 331 log("Ignoring authenticated invalid user %s", 332 authctxt->user); 333 auth_log(authctxt, 0, method, " ssh2"); 334 } 335 336 /* Log before sending the reply */ 337 auth_log(authctxt, authenticated, method, " ssh2"); 338 339 if (authenticated && !partial) { 340 341 /* turn off userauth */ 342 dispatch_set(SSH2_MSG_USERAUTH_REQUEST, &dispatch_protocol_ignore); 343 packet_start(SSH2_MSG_USERAUTH_SUCCESS); 344 packet_send(); 345 packet_write_wait(); 346 /* now we can break out */ 347 authctxt->success = 1; 348 } else { 349 char *methods; 350 351 if (authctxt->method && authctxt->method->is_initial) 352 authctxt->init_failures++; 353 354 authctxt->method = NULL; 355 356 #ifdef USE_PAM 357 /* 358 * Keep track of last PAM error (or PERM_DENIED) for BSM 359 * login failure auditing, which may run after the PAM 360 * state has been cleaned up. 361 */ 362 authctxt->pam_retval = AUTHPAM_ERROR(authctxt, PAM_PERM_DENIED); 363 #endif /* USE_PAM */ 364 365 if (authctxt->failures++ > options.max_auth_tries) { 366 #ifdef HAVE_BSM 367 fatal_remove_cleanup(audit_failed_login_cleanup, 368 authctxt); 369 audit_sshd_login_failure(&ah, PAM_MAXTRIES, 370 authctxt->user); 371 #endif /* HAVE_BSM */ 372 packet_disconnect(AUTH_FAIL_MSG, authctxt->user); 373 } 374 375 #ifdef _UNICOS 376 if (strcmp(method, "password") == 0) 377 cray_login_failure(authctxt->user, IA_UDBERR); 378 #endif /* _UNICOS */ 379 packet_start(SSH2_MSG_USERAUTH_FAILURE); 380 381 /* 382 * If (partial) then authmethods_get() will return only 383 * required methods, likely only "keyboard-interactive;" 384 * (methods == NULL) implies failure, even if (partial == 1) 385 */ 386 methods = authmethods_get(); 387 packet_put_cstring(methods); 388 packet_put_char((authenticated && partial && methods) ? 1 : 0); 389 if (methods) 390 xfree(methods); 391 packet_send(); 392 packet_write_wait(); 393 } 394 } 395 396 /* get current user */ 397 398 struct passwd* 399 auth_get_user(void) 400 { 401 return (x_authctxt != NULL && x_authctxt->valid) ? x_authctxt->pw : NULL; 402 } 403 404 #define DELIM "," 405 406 #if 0 407 static char * 408 authmethods_get_kbdint(void) 409 { 410 Buffer b; 411 int i; 412 413 for (i = 0; authmethods[i] != NULL; i++) { 414 if (strcmp(authmethods[i]->name, "keyboard-interactive") != 0) 415 continue; 416 return xstrdup(authmethods[i]->name); 417 } 418 return NULL; 419 } 420 #endif 421 422 void 423 userauth_user_svc_change(Authctxt *authctxt, char *user, char *service) 424 { 425 /* 426 * NOTE: 427 * 428 * SSHv2 services should be abstracted and service changes during 429 * userauth should be supported as per the userauth draft. In the PAM 430 * case, support for multiple SSHv2 services means that we have to 431 * format the PAM service name according to the SSHv2 service *and* the 432 * SSHv2 userauth being attempted ("passwd", "kbdint" and "other"). 433 * 434 * We'll cross that bridge when we come to it. For now disallow service 435 * changes during userauth if using PAM, but allow username changes. 436 */ 437 438 /* authctxt->service must == ssh-connection here */ 439 if (service != NULL && strcmp(service, authctxt->service) != 0) { 440 packet_disconnect("Change of service not " 441 "allowed: %s and %s", 442 authctxt->service, service); 443 } 444 if (user != NULL && authctxt->user != NULL && 445 strcmp(user, authctxt->user) == 0) 446 return; 447 448 /* All good; update authctxt */ 449 xfree(authctxt->user); 450 authctxt->user = xstrdup(user); 451 pwfree(&authctxt->pw); 452 authctxt->pw = getpwnamallow(user); 453 authctxt->valid = (authctxt->pw != NULL); 454 455 /* Forget method state; abandon postponed userauths */ 456 userauth_reset_methods(); 457 } 458 459 int 460 userauth_check_partial_failure(Authctxt *authctxt) 461 { 462 int i; 463 int required = 0; 464 int sufficient = 0; 465 466 /* 467 * v1 does not set authctxt->method 468 * partial userauth failure is a v2 concept 469 */ 470 if (authctxt->method == NULL) 471 return 0; 472 473 for (i = 0; authmethods[i] != NULL; i++) { 474 if (authmethods[i]->required) 475 required++; 476 if (authmethods[i]->sufficient) 477 sufficient++; 478 } 479 480 if (required == 0 && sufficient == 0) 481 return !authctxt->method->authenticated; 482 483 if (required == 1 && authctxt->method->required) 484 return !authctxt->method->authenticated; 485 486 if (sufficient && authctxt->method->sufficient) 487 return !authctxt->method->authenticated; 488 489 return 1; 490 } 491 492 int 493 userauth_method_can_run(Authmethod *method) 494 { 495 if (method->not_again) 496 return 0; 497 498 return 1; 499 } 500 501 static 502 void 503 userauth_reset_methods(void) 504 { 505 int i; 506 507 for (i = 0; authmethods[i] != NULL; i++) { 508 /* note: counters not reset */ 509 authmethods[i]->required = 0; 510 authmethods[i]->sufficient = 0; 511 authmethods[i]->authenticated = 0; 512 authmethods[i]->not_again = 0; 513 authmethods[i]->postponed = 0; 514 authmethods[i]->abandoned = 0; 515 } 516 } 517 518 void 519 userauth_force_kbdint(void) 520 { 521 int i; 522 523 for (i = 0; authmethods[i] != NULL; i++) { 524 authmethods[i]->required = 0; 525 authmethods[i]->sufficient = 0; 526 } 527 method_kbdint.required = 1; 528 } 529 530 /* 531 * Check to see if a previously run multi-round trip userauth method has 532 * been abandoned and call its cleanup function. 533 * 534 * Abandoned userauth method invocations are counted as userauth failures. 535 */ 536 static 537 char * 538 authmethods_check_abandonment(Authctxt *authctxt, Authmethod *method) 539 { 540 int i; 541 542 /* optimization: check current method first */ 543 if (method && method->postponed) { 544 method->postponed = 0; 545 if (method->abandon) 546 method->abandon(authctxt, method); 547 else 548 method->abandons++; 549 authctxt->failures++; /* abandonment -> failure */ 550 if (method->is_initial) 551 authctxt->init_failures++; 552 553 /* 554 * Since we check for abandonment whenever a userauth is 555 * requested we know only one method could have been 556 * in postponed state, so we can return now. 557 */ 558 return (method->name); 559 } 560 for (i = 0; authmethods[i] != NULL; i++) { 561 if (!authmethods[i]->postponed) 562 continue; 563 564 /* some method was postponed and a diff one is being started */ 565 if (method != authmethods[i]) { 566 authmethods[i]->postponed = 0; 567 if (authmethods[i]->abandon) 568 authmethods[i]->abandon(authctxt, 569 authmethods[i]); 570 else 571 authmethods[i]->abandons++; 572 authctxt->failures++; 573 if (authmethods[i]->is_initial) 574 authctxt->init_failures++; 575 return (authmethods[i]->name); /* see above */ 576 } 577 } 578 579 return NULL; 580 } 581 582 static char * 583 authmethods_get(void) 584 { 585 Buffer b; 586 char *list; 587 int i; 588 int sufficient = 0; 589 int required = 0; 590 int authenticated = 0; 591 int partial = 0; 592 593 /* 594 * If at least one method succeeded partially then at least one 595 * authmethod will be required and only required methods should 596 * continue. 597 */ 598 for (i = 0; authmethods[i] != NULL; i++) { 599 if (authmethods[i]->authenticated) 600 authenticated++; 601 if (authmethods[i]->required) 602 required++; 603 if (authmethods[i]->sufficient) 604 sufficient++; 605 } 606 607 partial = (required + sufficient) > 0; 608 609 buffer_init(&b); 610 for (i = 0; authmethods[i] != NULL; i++) { 611 if (strcmp(authmethods[i]->name, "none") == 0) 612 continue; 613 if (required && !authmethods[i]->required) 614 continue; 615 if (sufficient && !required && !authmethods[i]->sufficient) 616 continue; 617 if (authmethods[i]->not_again) 618 continue; 619 620 if (authmethods[i]->required) { 621 if (buffer_len(&b) > 0) 622 buffer_append(&b, ",", 1); 623 buffer_append(&b, authmethods[i]->name, 624 strlen(authmethods[i]->name)); 625 continue; 626 } 627 628 /* 629 * A method can be enabled (marked sufficient) 630 * dynamically provided that at least one other method 631 * has succeeded partially. 632 */ 633 if ((partial && authmethods[i]->sufficient) || 634 (authmethods[i]->enabled != NULL && 635 *(authmethods[i]->enabled) != 0)) { 636 if (buffer_len(&b) > 0) 637 buffer_append(&b, ",", 1); 638 buffer_append(&b, authmethods[i]->name, 639 strlen(authmethods[i]->name)); 640 } 641 } 642 buffer_append(&b, "\0", 1); 643 list = xstrdup(buffer_ptr(&b)); 644 buffer_free(&b); 645 return list; 646 } 647 648 static Authmethod * 649 authmethod_lookup(const char *name) 650 { 651 int i; 652 653 /* 654 * Method must be sufficient, required or enabled and must not 655 * be marked as not able to run again 656 */ 657 if (name != NULL) 658 for (i = 0; authmethods[i] != NULL; i++) 659 if (((authmethods[i]->sufficient || 660 authmethods[i]->required) || 661 (authmethods[i]->enabled != NULL && 662 *(authmethods[i]->enabled) != 0)) && 663 !authmethods[i]->not_again && 664 strcmp(name, authmethods[i]->name) == 0) 665 return authmethods[i]; 666 debug2("Unrecognized authentication method name: %s", 667 name ? name : "NULL"); 668 return NULL; 669 } 670 671 static void 672 authmethod_count_attempt(Authmethod *method) 673 { 674 if (!method) 675 fatal("Internal error in authmethod_count_attempt()"); 676 677 if (method->postponed) 678 return; 679 680 method->attempts++; 681 682 if (method->abandoned) 683 method->abandons++; 684 else if (method->authenticated) 685 method->successes++; 686 else 687 method->failures++; 688 689 return; 690 } 691