1 /* $OpenBSD: auth2.c,v 1.161 2021/04/03 06:18:40 djm Exp $ */ 2 /* 3 * Copyright (c) 2000 Markus Friedl. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 15 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 16 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 17 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 18 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 19 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 20 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 21 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 23 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 */ 25 26 #include "includes.h" 27 __RCSID("$FreeBSD$"); 28 29 #include <sys/types.h> 30 #include <sys/stat.h> 31 #include <sys/uio.h> 32 33 #include <fcntl.h> 34 #include <limits.h> 35 #include <pwd.h> 36 #include <stdarg.h> 37 #include <string.h> 38 #include <unistd.h> 39 #include <time.h> 40 41 #include "stdlib.h" 42 #include "atomicio.h" 43 #include "xmalloc.h" 44 #include "ssh2.h" 45 #include "packet.h" 46 #include "log.h" 47 #include "sshbuf.h" 48 #include "misc.h" 49 #include "servconf.h" 50 #include "compat.h" 51 #include "sshkey.h" 52 #include "hostfile.h" 53 #include "auth.h" 54 #include "dispatch.h" 55 #include "pathnames.h" 56 #include "ssherr.h" 57 #include "blacklist_client.h" 58 #ifdef GSSAPI 59 #include "ssh-gss.h" 60 #endif 61 #include "monitor_wrap.h" 62 #include "digest.h" 63 64 /* import */ 65 extern ServerOptions options; 66 extern struct sshbuf *loginmsg; 67 68 /* methods */ 69 70 extern Authmethod method_none; 71 extern Authmethod method_pubkey; 72 extern Authmethod method_passwd; 73 extern Authmethod method_kbdint; 74 extern Authmethod method_hostbased; 75 #ifdef GSSAPI 76 extern Authmethod method_gssapi; 77 #endif 78 79 Authmethod *authmethods[] = { 80 &method_none, 81 &method_pubkey, 82 #ifdef GSSAPI 83 &method_gssapi, 84 #endif 85 &method_passwd, 86 &method_kbdint, 87 &method_hostbased, 88 NULL 89 }; 90 91 /* protocol */ 92 93 static int input_service_request(int, u_int32_t, struct ssh *); 94 static int input_userauth_request(int, u_int32_t, struct ssh *); 95 96 /* helper */ 97 static Authmethod *authmethod_lookup(Authctxt *, const char *); 98 static char *authmethods_get(Authctxt *authctxt); 99 100 #define MATCH_NONE 0 /* method or submethod mismatch */ 101 #define MATCH_METHOD 1 /* method matches (no submethod specified) */ 102 #define MATCH_BOTH 2 /* method and submethod match */ 103 #define MATCH_PARTIAL 3 /* method matches, submethod can't be checked */ 104 static int list_starts_with(const char *, const char *, const char *); 105 106 char * 107 auth2_read_banner(void) 108 { 109 struct stat st; 110 char *banner = NULL; 111 size_t len, n; 112 int fd; 113 114 if ((fd = open(options.banner, O_RDONLY)) == -1) 115 return (NULL); 116 if (fstat(fd, &st) == -1) { 117 close(fd); 118 return (NULL); 119 } 120 if (st.st_size <= 0 || st.st_size > 1*1024*1024) { 121 close(fd); 122 return (NULL); 123 } 124 125 len = (size_t)st.st_size; /* truncate */ 126 banner = xmalloc(len + 1); 127 n = atomicio(read, fd, banner, len); 128 close(fd); 129 130 if (n != len) { 131 free(banner); 132 return (NULL); 133 } 134 banner[n] = '\0'; 135 136 return (banner); 137 } 138 139 static void 140 userauth_send_banner(struct ssh *ssh, const char *msg) 141 { 142 int r; 143 144 if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_BANNER)) != 0 || 145 (r = sshpkt_put_cstring(ssh, msg)) != 0 || 146 (r = sshpkt_put_cstring(ssh, "")) != 0 || /* language, unused */ 147 (r = sshpkt_send(ssh)) != 0) 148 fatal_fr(r, "send packet"); 149 debug("%s: sent", __func__); 150 } 151 152 static void 153 userauth_banner(struct ssh *ssh) 154 { 155 char *banner = NULL; 156 157 if (options.banner == NULL) 158 return; 159 160 if ((banner = PRIVSEP(auth2_read_banner())) == NULL) 161 goto done; 162 userauth_send_banner(ssh, banner); 163 164 done: 165 free(banner); 166 } 167 168 /* 169 * loop until authctxt->success == TRUE 170 */ 171 void 172 do_authentication2(struct ssh *ssh) 173 { 174 Authctxt *authctxt = ssh->authctxt; 175 176 ssh_dispatch_init(ssh, &dispatch_protocol_error); 177 ssh_dispatch_set(ssh, SSH2_MSG_SERVICE_REQUEST, &input_service_request); 178 ssh_dispatch_run_fatal(ssh, DISPATCH_BLOCK, &authctxt->success); 179 ssh->authctxt = NULL; 180 } 181 182 /*ARGSUSED*/ 183 static int 184 input_service_request(int type, u_int32_t seq, struct ssh *ssh) 185 { 186 Authctxt *authctxt = ssh->authctxt; 187 char *service = NULL; 188 int r, acceptit = 0; 189 190 if ((r = sshpkt_get_cstring(ssh, &service, NULL)) != 0 || 191 (r = sshpkt_get_end(ssh)) != 0) 192 goto out; 193 194 if (authctxt == NULL) 195 fatal("input_service_request: no authctxt"); 196 197 if (strcmp(service, "ssh-userauth") == 0) { 198 if (!authctxt->success) { 199 acceptit = 1; 200 /* now we can handle user-auth requests */ 201 ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_REQUEST, 202 &input_userauth_request); 203 } 204 } 205 /* XXX all other service requests are denied */ 206 207 if (acceptit) { 208 if ((r = sshpkt_start(ssh, SSH2_MSG_SERVICE_ACCEPT)) != 0 || 209 (r = sshpkt_put_cstring(ssh, service)) != 0 || 210 (r = sshpkt_send(ssh)) != 0 || 211 (r = ssh_packet_write_wait(ssh)) != 0) 212 goto out; 213 } else { 214 debug("bad service request %s", service); 215 ssh_packet_disconnect(ssh, "bad service request %s", service); 216 } 217 r = 0; 218 out: 219 free(service); 220 return r; 221 } 222 223 #define MIN_FAIL_DELAY_SECONDS 0.005 224 static double 225 user_specific_delay(const char *user) 226 { 227 char b[512]; 228 size_t len = ssh_digest_bytes(SSH_DIGEST_SHA512); 229 u_char *hash = xmalloc(len); 230 double delay; 231 232 (void)snprintf(b, sizeof b, "%llu%s", 233 (unsigned long long)options.timing_secret, user); 234 if (ssh_digest_memory(SSH_DIGEST_SHA512, b, strlen(b), hash, len) != 0) 235 fatal_f("ssh_digest_memory"); 236 /* 0-4.2 ms of delay */ 237 delay = (double)PEEK_U32(hash) / 1000 / 1000 / 1000 / 1000; 238 freezero(hash, len); 239 debug3_f("user specific delay %0.3lfms", delay/1000); 240 return MIN_FAIL_DELAY_SECONDS + delay; 241 } 242 243 static void 244 ensure_minimum_time_since(double start, double seconds) 245 { 246 struct timespec ts; 247 double elapsed = monotime_double() - start, req = seconds, remain; 248 249 /* if we've already passed the requested time, scale up */ 250 while ((remain = seconds - elapsed) < 0.0) 251 seconds *= 2; 252 253 ts.tv_sec = remain; 254 ts.tv_nsec = (remain - ts.tv_sec) * 1000000000; 255 debug3_f("elapsed %0.3lfms, delaying %0.3lfms (requested %0.3lfms)", 256 elapsed*1000, remain*1000, req*1000); 257 nanosleep(&ts, NULL); 258 } 259 260 /*ARGSUSED*/ 261 static int 262 input_userauth_request(int type, u_int32_t seq, struct ssh *ssh) 263 { 264 Authctxt *authctxt = ssh->authctxt; 265 Authmethod *m = NULL; 266 char *user = NULL, *service = NULL, *method = NULL, *style = NULL; 267 int r, authenticated = 0; 268 double tstart = monotime_double(); 269 270 if (authctxt == NULL) 271 fatal("input_userauth_request: no authctxt"); 272 273 if ((r = sshpkt_get_cstring(ssh, &user, NULL)) != 0 || 274 (r = sshpkt_get_cstring(ssh, &service, NULL)) != 0 || 275 (r = sshpkt_get_cstring(ssh, &method, NULL)) != 0) 276 goto out; 277 debug("userauth-request for user %s service %s method %s", user, service, method); 278 debug("attempt %d failures %d", authctxt->attempt, authctxt->failures); 279 280 if ((style = strchr(user, ':')) != NULL) 281 *style++ = 0; 282 283 if (authctxt->attempt++ == 0) { 284 /* setup auth context */ 285 authctxt->pw = PRIVSEP(getpwnamallow(ssh, user)); 286 authctxt->user = xstrdup(user); 287 if (authctxt->pw && strcmp(service, "ssh-connection")==0) { 288 authctxt->valid = 1; 289 debug2_f("setting up authctxt for %s", user); 290 } else { 291 /* Invalid user, fake password information */ 292 authctxt->pw = fakepw(); 293 #ifdef SSH_AUDIT_EVENTS 294 PRIVSEP(audit_event(ssh, SSH_INVALID_USER)); 295 #endif 296 } 297 #ifdef USE_PAM 298 if (options.use_pam) 299 PRIVSEP(start_pam(ssh)); 300 #endif 301 ssh_packet_set_log_preamble(ssh, "%suser %s", 302 authctxt->valid ? "authenticating " : "invalid ", user); 303 setproctitle("%s%s", authctxt->valid ? user : "unknown", 304 use_privsep ? " [net]" : ""); 305 authctxt->service = xstrdup(service); 306 authctxt->style = style ? xstrdup(style) : NULL; 307 if (use_privsep) 308 mm_inform_authserv(service, style); 309 userauth_banner(ssh); 310 if (auth2_setup_methods_lists(authctxt) != 0) 311 ssh_packet_disconnect(ssh, 312 "no authentication methods enabled"); 313 } else if (strcmp(user, authctxt->user) != 0 || 314 strcmp(service, authctxt->service) != 0) { 315 ssh_packet_disconnect(ssh, "Change of username or service " 316 "not allowed: (%s,%s) -> (%s,%s)", 317 authctxt->user, authctxt->service, user, service); 318 } 319 /* reset state */ 320 auth2_challenge_stop(ssh); 321 322 #ifdef GSSAPI 323 /* XXX move to auth2_gssapi_stop() */ 324 ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_TOKEN, NULL); 325 ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_GSSAPI_EXCHANGE_COMPLETE, NULL); 326 #endif 327 328 auth2_authctxt_reset_info(authctxt); 329 authctxt->postponed = 0; 330 authctxt->server_caused_failure = 0; 331 332 /* try to authenticate user */ 333 m = authmethod_lookup(authctxt, method); 334 if (m != NULL && authctxt->failures < options.max_authtries) { 335 debug2("input_userauth_request: try method %s", method); 336 authenticated = m->userauth(ssh); 337 } 338 if (!authctxt->authenticated) 339 ensure_minimum_time_since(tstart, 340 user_specific_delay(authctxt->user)); 341 userauth_finish(ssh, authenticated, method, NULL); 342 r = 0; 343 out: 344 free(service); 345 free(user); 346 free(method); 347 return r; 348 } 349 350 void 351 userauth_finish(struct ssh *ssh, int authenticated, const char *method, 352 const char *submethod) 353 { 354 Authctxt *authctxt = ssh->authctxt; 355 char *methods; 356 int r, partial = 0; 357 358 if (!authctxt->valid && authenticated) 359 fatal("INTERNAL ERROR: authenticated invalid user %s", 360 authctxt->user); 361 if (authenticated && authctxt->postponed) 362 fatal("INTERNAL ERROR: authenticated and postponed"); 363 364 /* Special handling for root */ 365 if (authenticated && authctxt->pw->pw_uid == 0 && 366 !auth_root_allowed(ssh, method)) { 367 authenticated = 0; 368 #ifdef SSH_AUDIT_EVENTS 369 PRIVSEP(audit_event(ssh, SSH_LOGIN_ROOT_DENIED)); 370 #endif 371 } 372 373 if (authenticated && options.num_auth_methods != 0) { 374 if (!auth2_update_methods_lists(authctxt, method, submethod)) { 375 authenticated = 0; 376 partial = 1; 377 } 378 } 379 380 /* Log before sending the reply */ 381 auth_log(ssh, authenticated, partial, method, submethod); 382 383 /* Update information exposed to session */ 384 if (authenticated || partial) 385 auth2_update_session_info(authctxt, method, submethod); 386 387 if (authctxt->postponed) 388 return; 389 390 #ifdef USE_PAM 391 if (options.use_pam && authenticated) { 392 int r, success = PRIVSEP(do_pam_account()); 393 394 /* If PAM returned a message, send it to the user. */ 395 if (sshbuf_len(loginmsg) > 0) { 396 if ((r = sshbuf_put(loginmsg, "\0", 1)) != 0) 397 fatal("%s: buffer error: %s", 398 __func__, ssh_err(r)); 399 userauth_send_banner(ssh, sshbuf_ptr(loginmsg)); 400 if ((r = ssh_packet_write_wait(ssh)) != 0) { 401 sshpkt_fatal(ssh, r, 402 "%s: send PAM banner", __func__); 403 } 404 } 405 if (!success) { 406 fatal("Access denied for user %s by PAM account " 407 "configuration", authctxt->user); 408 } 409 } 410 #endif 411 412 if (authenticated == 1) { 413 /* turn off userauth */ 414 ssh_dispatch_set(ssh, SSH2_MSG_USERAUTH_REQUEST, 415 &dispatch_protocol_ignore); 416 if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_SUCCESS)) != 0 || 417 (r = sshpkt_send(ssh)) != 0 || 418 (r = ssh_packet_write_wait(ssh)) != 0) 419 fatal_fr(r, "send success packet"); 420 /* now we can break out */ 421 authctxt->success = 1; 422 ssh_packet_set_log_preamble(ssh, "user %s", authctxt->user); 423 } else { 424 /* Allow initial try of "none" auth without failure penalty */ 425 if (!partial && !authctxt->server_caused_failure && 426 (authctxt->attempt > 1 || strcmp(method, "none") != 0)) { 427 authctxt->failures++; 428 BLACKLIST_NOTIFY(ssh, BLACKLIST_AUTH_FAIL, "ssh"); 429 } 430 if (authctxt->failures >= options.max_authtries) { 431 #ifdef SSH_AUDIT_EVENTS 432 PRIVSEP(audit_event(ssh, SSH_LOGIN_EXCEED_MAXTRIES)); 433 #endif 434 auth_maxtries_exceeded(ssh); 435 } 436 methods = authmethods_get(authctxt); 437 debug3_f("failure partial=%d next methods=\"%s\"", 438 partial, methods); 439 if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_FAILURE)) != 0 || 440 (r = sshpkt_put_cstring(ssh, methods)) != 0 || 441 (r = sshpkt_put_u8(ssh, partial)) != 0 || 442 (r = sshpkt_send(ssh)) != 0 || 443 (r = ssh_packet_write_wait(ssh)) != 0) 444 fatal_fr(r, "send failure packet"); 445 free(methods); 446 } 447 } 448 449 /* 450 * Checks whether method is allowed by at least one AuthenticationMethods 451 * methods list. Returns 1 if allowed, or no methods lists configured. 452 * 0 otherwise. 453 */ 454 int 455 auth2_method_allowed(Authctxt *authctxt, const char *method, 456 const char *submethod) 457 { 458 u_int i; 459 460 /* 461 * NB. authctxt->num_auth_methods might be zero as a result of 462 * auth2_setup_methods_lists(), so check the configuration. 463 */ 464 if (options.num_auth_methods == 0) 465 return 1; 466 for (i = 0; i < authctxt->num_auth_methods; i++) { 467 if (list_starts_with(authctxt->auth_methods[i], method, 468 submethod) != MATCH_NONE) 469 return 1; 470 } 471 return 0; 472 } 473 474 static char * 475 authmethods_get(Authctxt *authctxt) 476 { 477 struct sshbuf *b; 478 char *list; 479 int i, r; 480 481 if ((b = sshbuf_new()) == NULL) 482 fatal_f("sshbuf_new failed"); 483 for (i = 0; authmethods[i] != NULL; i++) { 484 if (strcmp(authmethods[i]->name, "none") == 0) 485 continue; 486 if (authmethods[i]->enabled == NULL || 487 *(authmethods[i]->enabled) == 0) 488 continue; 489 if (!auth2_method_allowed(authctxt, authmethods[i]->name, 490 NULL)) 491 continue; 492 if ((r = sshbuf_putf(b, "%s%s", sshbuf_len(b) ? "," : "", 493 authmethods[i]->name)) != 0) 494 fatal_fr(r, "buffer error"); 495 } 496 if ((list = sshbuf_dup_string(b)) == NULL) 497 fatal_f("sshbuf_dup_string failed"); 498 sshbuf_free(b); 499 return list; 500 } 501 502 static Authmethod * 503 authmethod_lookup(Authctxt *authctxt, const char *name) 504 { 505 int i; 506 507 if (name != NULL) 508 for (i = 0; authmethods[i] != NULL; i++) 509 if (authmethods[i]->enabled != NULL && 510 *(authmethods[i]->enabled) != 0 && 511 strcmp(name, authmethods[i]->name) == 0 && 512 auth2_method_allowed(authctxt, 513 authmethods[i]->name, NULL)) 514 return authmethods[i]; 515 debug2("Unrecognized authentication method name: %s", 516 name ? name : "NULL"); 517 return NULL; 518 } 519 520 /* 521 * Check a comma-separated list of methods for validity. Is need_enable is 522 * non-zero, then also require that the methods are enabled. 523 * Returns 0 on success or -1 if the methods list is invalid. 524 */ 525 int 526 auth2_methods_valid(const char *_methods, int need_enable) 527 { 528 char *methods, *omethods, *method, *p; 529 u_int i, found; 530 int ret = -1; 531 532 if (*_methods == '\0') { 533 error("empty authentication method list"); 534 return -1; 535 } 536 omethods = methods = xstrdup(_methods); 537 while ((method = strsep(&methods, ",")) != NULL) { 538 for (found = i = 0; !found && authmethods[i] != NULL; i++) { 539 if ((p = strchr(method, ':')) != NULL) 540 *p = '\0'; 541 if (strcmp(method, authmethods[i]->name) != 0) 542 continue; 543 if (need_enable) { 544 if (authmethods[i]->enabled == NULL || 545 *(authmethods[i]->enabled) == 0) { 546 error("Disabled method \"%s\" in " 547 "AuthenticationMethods list \"%s\"", 548 method, _methods); 549 goto out; 550 } 551 } 552 found = 1; 553 break; 554 } 555 if (!found) { 556 error("Unknown authentication method \"%s\" in list", 557 method); 558 goto out; 559 } 560 } 561 ret = 0; 562 out: 563 free(omethods); 564 return ret; 565 } 566 567 /* 568 * Prune the AuthenticationMethods supplied in the configuration, removing 569 * any methods lists that include disabled methods. Note that this might 570 * leave authctxt->num_auth_methods == 0, even when multiple required auth 571 * has been requested. For this reason, all tests for whether multiple is 572 * enabled should consult options.num_auth_methods directly. 573 */ 574 int 575 auth2_setup_methods_lists(Authctxt *authctxt) 576 { 577 u_int i; 578 579 /* First, normalise away the "any" pseudo-method */ 580 if (options.num_auth_methods == 1 && 581 strcmp(options.auth_methods[0], "any") == 0) { 582 free(options.auth_methods[0]); 583 options.auth_methods[0] = NULL; 584 options.num_auth_methods = 0; 585 } 586 587 if (options.num_auth_methods == 0) 588 return 0; 589 debug3_f("checking methods"); 590 authctxt->auth_methods = xcalloc(options.num_auth_methods, 591 sizeof(*authctxt->auth_methods)); 592 authctxt->num_auth_methods = 0; 593 for (i = 0; i < options.num_auth_methods; i++) { 594 if (auth2_methods_valid(options.auth_methods[i], 1) != 0) { 595 logit("Authentication methods list \"%s\" contains " 596 "disabled method, skipping", 597 options.auth_methods[i]); 598 continue; 599 } 600 debug("authentication methods list %d: %s", 601 authctxt->num_auth_methods, options.auth_methods[i]); 602 authctxt->auth_methods[authctxt->num_auth_methods++] = 603 xstrdup(options.auth_methods[i]); 604 } 605 if (authctxt->num_auth_methods == 0) { 606 error("No AuthenticationMethods left after eliminating " 607 "disabled methods"); 608 return -1; 609 } 610 return 0; 611 } 612 613 static int 614 list_starts_with(const char *methods, const char *method, 615 const char *submethod) 616 { 617 size_t l = strlen(method); 618 int match; 619 const char *p; 620 621 if (strncmp(methods, method, l) != 0) 622 return MATCH_NONE; 623 p = methods + l; 624 match = MATCH_METHOD; 625 if (*p == ':') { 626 if (!submethod) 627 return MATCH_PARTIAL; 628 l = strlen(submethod); 629 p += 1; 630 if (strncmp(submethod, p, l)) 631 return MATCH_NONE; 632 p += l; 633 match = MATCH_BOTH; 634 } 635 if (*p != ',' && *p != '\0') 636 return MATCH_NONE; 637 return match; 638 } 639 640 /* 641 * Remove method from the start of a comma-separated list of methods. 642 * Returns 0 if the list of methods did not start with that method or 1 643 * if it did. 644 */ 645 static int 646 remove_method(char **methods, const char *method, const char *submethod) 647 { 648 char *omethods = *methods, *p; 649 size_t l = strlen(method); 650 int match; 651 652 match = list_starts_with(omethods, method, submethod); 653 if (match != MATCH_METHOD && match != MATCH_BOTH) 654 return 0; 655 p = omethods + l; 656 if (submethod && match == MATCH_BOTH) 657 p += 1 + strlen(submethod); /* include colon */ 658 if (*p == ',') 659 p++; 660 *methods = xstrdup(p); 661 free(omethods); 662 return 1; 663 } 664 665 /* 666 * Called after successful authentication. Will remove the successful method 667 * from the start of each list in which it occurs. If it was the last method 668 * in any list, then authentication is deemed successful. 669 * Returns 1 if the method completed any authentication list or 0 otherwise. 670 */ 671 int 672 auth2_update_methods_lists(Authctxt *authctxt, const char *method, 673 const char *submethod) 674 { 675 u_int i, found = 0; 676 677 debug3_f("updating methods list after \"%s\"", method); 678 for (i = 0; i < authctxt->num_auth_methods; i++) { 679 if (!remove_method(&(authctxt->auth_methods[i]), method, 680 submethod)) 681 continue; 682 found = 1; 683 if (*authctxt->auth_methods[i] == '\0') { 684 debug2("authentication methods list %d complete", i); 685 return 1; 686 } 687 debug3("authentication methods list %d remaining: \"%s\"", 688 i, authctxt->auth_methods[i]); 689 } 690 /* This should not happen, but would be bad if it did */ 691 if (!found) 692 fatal_f("method not in AuthenticationMethods"); 693 return 0; 694 } 695 696 /* Reset method-specific information */ 697 void auth2_authctxt_reset_info(Authctxt *authctxt) 698 { 699 sshkey_free(authctxt->auth_method_key); 700 free(authctxt->auth_method_info); 701 authctxt->auth_method_key = NULL; 702 authctxt->auth_method_info = NULL; 703 } 704 705 /* Record auth method-specific information for logs */ 706 void 707 auth2_record_info(Authctxt *authctxt, const char *fmt, ...) 708 { 709 va_list ap; 710 int i; 711 712 free(authctxt->auth_method_info); 713 authctxt->auth_method_info = NULL; 714 715 va_start(ap, fmt); 716 i = vasprintf(&authctxt->auth_method_info, fmt, ap); 717 va_end(ap); 718 719 if (i == -1) 720 fatal_f("vasprintf failed"); 721 } 722 723 /* 724 * Records a public key used in authentication. This is used for logging 725 * and to ensure that the same key is not subsequently accepted again for 726 * multiple authentication. 727 */ 728 void 729 auth2_record_key(Authctxt *authctxt, int authenticated, 730 const struct sshkey *key) 731 { 732 struct sshkey **tmp, *dup; 733 int r; 734 735 if ((r = sshkey_from_private(key, &dup)) != 0) 736 fatal_fr(r, "copy key"); 737 sshkey_free(authctxt->auth_method_key); 738 authctxt->auth_method_key = dup; 739 740 if (!authenticated) 741 return; 742 743 /* If authenticated, make sure we don't accept this key again */ 744 if ((r = sshkey_from_private(key, &dup)) != 0) 745 fatal_fr(r, "copy key"); 746 if (authctxt->nprev_keys >= INT_MAX || 747 (tmp = recallocarray(authctxt->prev_keys, authctxt->nprev_keys, 748 authctxt->nprev_keys + 1, sizeof(*authctxt->prev_keys))) == NULL) 749 fatal_f("reallocarray failed"); 750 authctxt->prev_keys = tmp; 751 authctxt->prev_keys[authctxt->nprev_keys] = dup; 752 authctxt->nprev_keys++; 753 754 } 755 756 /* Checks whether a key has already been previously used for authentication */ 757 int 758 auth2_key_already_used(Authctxt *authctxt, const struct sshkey *key) 759 { 760 u_int i; 761 char *fp; 762 763 for (i = 0; i < authctxt->nprev_keys; i++) { 764 if (sshkey_equal_public(key, authctxt->prev_keys[i])) { 765 fp = sshkey_fingerprint(authctxt->prev_keys[i], 766 options.fingerprint_hash, SSH_FP_DEFAULT); 767 debug3_f("key already used: %s %s", 768 sshkey_type(authctxt->prev_keys[i]), 769 fp == NULL ? "UNKNOWN" : fp); 770 free(fp); 771 return 1; 772 } 773 } 774 return 0; 775 } 776 777 /* 778 * Updates authctxt->session_info with details of authentication. Should be 779 * whenever an authentication method succeeds. 780 */ 781 void 782 auth2_update_session_info(Authctxt *authctxt, const char *method, 783 const char *submethod) 784 { 785 int r; 786 787 if (authctxt->session_info == NULL) { 788 if ((authctxt->session_info = sshbuf_new()) == NULL) 789 fatal_f("sshbuf_new"); 790 } 791 792 /* Append method[/submethod] */ 793 if ((r = sshbuf_putf(authctxt->session_info, "%s%s%s", 794 method, submethod == NULL ? "" : "/", 795 submethod == NULL ? "" : submethod)) != 0) 796 fatal_fr(r, "append method"); 797 798 /* Append key if present */ 799 if (authctxt->auth_method_key != NULL) { 800 if ((r = sshbuf_put_u8(authctxt->session_info, ' ')) != 0 || 801 (r = sshkey_format_text(authctxt->auth_method_key, 802 authctxt->session_info)) != 0) 803 fatal_fr(r, "append key"); 804 } 805 806 if (authctxt->auth_method_info != NULL) { 807 /* Ensure no ambiguity here */ 808 if (strchr(authctxt->auth_method_info, '\n') != NULL) 809 fatal_f("auth_method_info contains \\n"); 810 if ((r = sshbuf_put_u8(authctxt->session_info, ' ')) != 0 || 811 (r = sshbuf_putf(authctxt->session_info, "%s", 812 authctxt->auth_method_info)) != 0) { 813 fatal_fr(r, "append method info"); 814 } 815 } 816 if ((r = sshbuf_put_u8(authctxt->session_info, '\n')) != 0) 817 fatal_fr(r, "append"); 818 } 819 820