1 /* $OpenBSD: auth2-pubkey.c,v 1.53 2015/06/15 18:44:22 jsing 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 28 #include <sys/types.h> 29 #include <sys/stat.h> 30 #include <sys/wait.h> 31 32 #include <errno.h> 33 #include <fcntl.h> 34 #ifdef HAVE_PATHS_H 35 # include <paths.h> 36 #endif 37 #include <pwd.h> 38 #include <signal.h> 39 #include <stdio.h> 40 #include <stdarg.h> 41 #include <string.h> 42 #include <time.h> 43 #include <unistd.h> 44 #include <limits.h> 45 46 #include "xmalloc.h" 47 #include "ssh.h" 48 #include "ssh2.h" 49 #include "packet.h" 50 #include "buffer.h" 51 #include "log.h" 52 #include "misc.h" 53 #include "servconf.h" 54 #include "compat.h" 55 #include "key.h" 56 #include "hostfile.h" 57 #include "auth.h" 58 #include "pathnames.h" 59 #include "uidswap.h" 60 #include "auth-options.h" 61 #include "canohost.h" 62 #ifdef GSSAPI 63 #include "ssh-gss.h" 64 #endif 65 #include "monitor_wrap.h" 66 #include "authfile.h" 67 #include "match.h" 68 #include "ssherr.h" 69 #include "channels.h" /* XXX for session.h */ 70 #include "session.h" /* XXX for child_set_env(); refactor? */ 71 72 /* import */ 73 extern ServerOptions options; 74 extern u_char *session_id2; 75 extern u_int session_id2_len; 76 77 static int 78 userauth_pubkey(Authctxt *authctxt) 79 { 80 Buffer b; 81 Key *key = NULL; 82 char *pkalg, *userstyle; 83 u_char *pkblob, *sig; 84 u_int alen, blen, slen; 85 int have_sig, pktype; 86 int authenticated = 0; 87 88 if (!authctxt->valid) { 89 debug2("userauth_pubkey: disabled because of invalid user"); 90 return 0; 91 } 92 have_sig = packet_get_char(); 93 if (datafellows & SSH_BUG_PKAUTH) { 94 debug2("userauth_pubkey: SSH_BUG_PKAUTH"); 95 /* no explicit pkalg given */ 96 pkblob = packet_get_string(&blen); 97 buffer_init(&b); 98 buffer_append(&b, pkblob, blen); 99 /* so we have to extract the pkalg from the pkblob */ 100 pkalg = buffer_get_string(&b, &alen); 101 buffer_free(&b); 102 } else { 103 pkalg = packet_get_string(&alen); 104 pkblob = packet_get_string(&blen); 105 } 106 pktype = key_type_from_name(pkalg); 107 if (pktype == KEY_UNSPEC) { 108 /* this is perfectly legal */ 109 logit("userauth_pubkey: unsupported public key algorithm: %s", 110 pkalg); 111 goto done; 112 } 113 key = key_from_blob(pkblob, blen); 114 if (key == NULL) { 115 error("userauth_pubkey: cannot decode key: %s", pkalg); 116 goto done; 117 } 118 if (key->type != pktype) { 119 error("userauth_pubkey: type mismatch for decoded key " 120 "(received %d, expected %d)", key->type, pktype); 121 goto done; 122 } 123 if (key_type_plain(key->type) == KEY_RSA && 124 (datafellows & SSH_BUG_RSASIGMD5) != 0) { 125 logit("Refusing RSA key because client uses unsafe " 126 "signature scheme"); 127 goto done; 128 } 129 if (auth2_userkey_already_used(authctxt, key)) { 130 logit("refusing previously-used %s key", key_type(key)); 131 goto done; 132 } 133 if (match_pattern_list(sshkey_ssh_name(key), 134 options.pubkey_key_types, 0) != 1) { 135 logit("%s: key type %s not in PubkeyAcceptedKeyTypes", 136 __func__, sshkey_ssh_name(key)); 137 goto done; 138 } 139 140 if (have_sig) { 141 sig = packet_get_string(&slen); 142 packet_check_eom(); 143 buffer_init(&b); 144 if (datafellows & SSH_OLD_SESSIONID) { 145 buffer_append(&b, session_id2, session_id2_len); 146 } else { 147 buffer_put_string(&b, session_id2, session_id2_len); 148 } 149 /* reconstruct packet */ 150 buffer_put_char(&b, SSH2_MSG_USERAUTH_REQUEST); 151 xasprintf(&userstyle, "%s%s%s", authctxt->user, 152 authctxt->style ? ":" : "", 153 authctxt->style ? authctxt->style : ""); 154 buffer_put_cstring(&b, userstyle); 155 free(userstyle); 156 buffer_put_cstring(&b, 157 datafellows & SSH_BUG_PKSERVICE ? 158 "ssh-userauth" : 159 authctxt->service); 160 if (datafellows & SSH_BUG_PKAUTH) { 161 buffer_put_char(&b, have_sig); 162 } else { 163 buffer_put_cstring(&b, "publickey"); 164 buffer_put_char(&b, have_sig); 165 buffer_put_cstring(&b, pkalg); 166 } 167 buffer_put_string(&b, pkblob, blen); 168 #ifdef DEBUG_PK 169 buffer_dump(&b); 170 #endif 171 pubkey_auth_info(authctxt, key, NULL); 172 173 /* test for correct signature */ 174 authenticated = 0; 175 if (PRIVSEP(user_key_allowed(authctxt->pw, key, 1)) && 176 PRIVSEP(key_verify(key, sig, slen, buffer_ptr(&b), 177 buffer_len(&b))) == 1) { 178 authenticated = 1; 179 /* Record the successful key to prevent reuse */ 180 auth2_record_userkey(authctxt, key); 181 key = NULL; /* Don't free below */ 182 } 183 buffer_free(&b); 184 free(sig); 185 } else { 186 debug("test whether pkalg/pkblob are acceptable"); 187 packet_check_eom(); 188 189 /* XXX fake reply and always send PK_OK ? */ 190 /* 191 * XXX this allows testing whether a user is allowed 192 * to login: if you happen to have a valid pubkey this 193 * message is sent. the message is NEVER sent at all 194 * if a user is not allowed to login. is this an 195 * issue? -markus 196 */ 197 if (PRIVSEP(user_key_allowed(authctxt->pw, key, 0))) { 198 packet_start(SSH2_MSG_USERAUTH_PK_OK); 199 packet_put_string(pkalg, alen); 200 packet_put_string(pkblob, blen); 201 packet_send(); 202 packet_write_wait(); 203 authctxt->postponed = 1; 204 } 205 } 206 if (authenticated != 1) 207 auth_clear_options(); 208 done: 209 debug2("userauth_pubkey: authenticated %d pkalg %s", authenticated, pkalg); 210 if (key != NULL) 211 key_free(key); 212 free(pkalg); 213 free(pkblob); 214 return authenticated; 215 } 216 217 void 218 pubkey_auth_info(Authctxt *authctxt, const Key *key, const char *fmt, ...) 219 { 220 char *fp, *extra; 221 va_list ap; 222 int i; 223 224 extra = NULL; 225 if (fmt != NULL) { 226 va_start(ap, fmt); 227 i = vasprintf(&extra, fmt, ap); 228 va_end(ap); 229 if (i < 0 || extra == NULL) 230 fatal("%s: vasprintf failed", __func__); 231 } 232 233 if (key_is_cert(key)) { 234 fp = sshkey_fingerprint(key->cert->signature_key, 235 options.fingerprint_hash, SSH_FP_DEFAULT); 236 auth_info(authctxt, "%s ID %s (serial %llu) CA %s %s%s%s", 237 key_type(key), key->cert->key_id, 238 (unsigned long long)key->cert->serial, 239 key_type(key->cert->signature_key), 240 fp == NULL ? "(null)" : fp, 241 extra == NULL ? "" : ", ", extra == NULL ? "" : extra); 242 free(fp); 243 } else { 244 fp = sshkey_fingerprint(key, options.fingerprint_hash, 245 SSH_FP_DEFAULT); 246 auth_info(authctxt, "%s %s%s%s", key_type(key), 247 fp == NULL ? "(null)" : fp, 248 extra == NULL ? "" : ", ", extra == NULL ? "" : extra); 249 free(fp); 250 } 251 free(extra); 252 } 253 254 /* 255 * Splits 's' into an argument vector. Handles quoted string and basic 256 * escape characters (\\, \", \'). Caller must free the argument vector 257 * and its members. 258 */ 259 static int 260 split_argv(const char *s, int *argcp, char ***argvp) 261 { 262 int r = SSH_ERR_INTERNAL_ERROR; 263 int argc = 0, quote, i, j; 264 char *arg, **argv = xcalloc(1, sizeof(*argv)); 265 266 *argvp = NULL; 267 *argcp = 0; 268 269 for (i = 0; s[i] != '\0'; i++) { 270 /* Skip leading whitespace */ 271 if (s[i] == ' ' || s[i] == '\t') 272 continue; 273 274 /* Start of a token */ 275 quote = 0; 276 if (s[i] == '\\' && 277 (s[i + 1] == '\'' || s[i + 1] == '\"' || s[i + 1] == '\\')) 278 i++; 279 else if (s[i] == '\'' || s[i] == '"') 280 quote = s[i++]; 281 282 argv = xreallocarray(argv, (argc + 2), sizeof(*argv)); 283 arg = argv[argc++] = xcalloc(1, strlen(s + i) + 1); 284 argv[argc] = NULL; 285 286 /* Copy the token in, removing escapes */ 287 for (j = 0; s[i] != '\0'; i++) { 288 if (s[i] == '\\') { 289 if (s[i + 1] == '\'' || 290 s[i + 1] == '\"' || 291 s[i + 1] == '\\') { 292 i++; /* Skip '\' */ 293 arg[j++] = s[i]; 294 } else { 295 /* Unrecognised escape */ 296 arg[j++] = s[i]; 297 } 298 } else if (quote == 0 && (s[i] == ' ' || s[i] == '\t')) 299 break; /* done */ 300 else if (quote != 0 && s[i] == quote) 301 break; /* done */ 302 else 303 arg[j++] = s[i]; 304 } 305 if (s[i] == '\0') { 306 if (quote != 0) { 307 /* Ran out of string looking for close quote */ 308 r = SSH_ERR_INVALID_FORMAT; 309 goto out; 310 } 311 break; 312 } 313 } 314 /* Success */ 315 *argcp = argc; 316 *argvp = argv; 317 argc = 0; 318 argv = NULL; 319 r = 0; 320 out: 321 if (argc != 0 && argv != NULL) { 322 for (i = 0; i < argc; i++) 323 free(argv[i]); 324 free(argv); 325 } 326 return r; 327 } 328 329 /* 330 * Reassemble an argument vector into a string, quoting and escaping as 331 * necessary. Caller must free returned string. 332 */ 333 static char * 334 assemble_argv(int argc, char **argv) 335 { 336 int i, j, ws, r; 337 char c, *ret; 338 struct sshbuf *buf, *arg; 339 340 if ((buf = sshbuf_new()) == NULL || (arg = sshbuf_new()) == NULL) 341 fatal("%s: sshbuf_new failed", __func__); 342 343 for (i = 0; i < argc; i++) { 344 ws = 0; 345 sshbuf_reset(arg); 346 for (j = 0; argv[i][j] != '\0'; j++) { 347 r = 0; 348 c = argv[i][j]; 349 switch (c) { 350 case ' ': 351 case '\t': 352 ws = 1; 353 r = sshbuf_put_u8(arg, c); 354 break; 355 case '\\': 356 case '\'': 357 case '"': 358 if ((r = sshbuf_put_u8(arg, '\\')) != 0) 359 break; 360 /* FALLTHROUGH */ 361 default: 362 r = sshbuf_put_u8(arg, c); 363 break; 364 } 365 if (r != 0) 366 fatal("%s: sshbuf_put_u8: %s", 367 __func__, ssh_err(r)); 368 } 369 if ((i != 0 && (r = sshbuf_put_u8(buf, ' ')) != 0) || 370 (ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0) || 371 (r = sshbuf_putb(buf, arg)) != 0 || 372 (ws != 0 && (r = sshbuf_put_u8(buf, '"')) != 0)) 373 fatal("%s: buffer error: %s", __func__, ssh_err(r)); 374 } 375 if ((ret = malloc(sshbuf_len(buf) + 1)) == NULL) 376 fatal("%s: malloc failed", __func__); 377 memcpy(ret, sshbuf_ptr(buf), sshbuf_len(buf)); 378 ret[sshbuf_len(buf)] = '\0'; 379 sshbuf_free(buf); 380 sshbuf_free(arg); 381 return ret; 382 } 383 384 /* 385 * Runs command in a subprocess. Returns pid on success and a FILE* to the 386 * subprocess' stdout or 0 on failure. 387 * NB. "command" is only used for logging. 388 */ 389 static pid_t 390 subprocess(const char *tag, struct passwd *pw, const char *command, 391 int ac, char **av, FILE **child) 392 { 393 FILE *f; 394 struct stat st; 395 int devnull, p[2], i; 396 pid_t pid; 397 char *cp, errmsg[512]; 398 u_int envsize; 399 char **child_env; 400 401 *child = NULL; 402 403 debug3("%s: %s command \"%s\" running as %s", __func__, 404 tag, command, pw->pw_name); 405 406 /* Verify the path exists and is safe-ish to execute */ 407 if (*av[0] != '/') { 408 error("%s path is not absolute", tag); 409 return 0; 410 } 411 temporarily_use_uid(pw); 412 if (stat(av[0], &st) < 0) { 413 error("Could not stat %s \"%s\": %s", tag, 414 av[0], strerror(errno)); 415 restore_uid(); 416 return 0; 417 } 418 if (auth_secure_path(av[0], &st, NULL, 0, 419 errmsg, sizeof(errmsg)) != 0) { 420 error("Unsafe %s \"%s\": %s", tag, av[0], errmsg); 421 restore_uid(); 422 return 0; 423 } 424 425 /* 426 * Run the command; stderr is left in place, stdout is the 427 * authorized_keys output. 428 */ 429 if (pipe(p) != 0) { 430 error("%s: pipe: %s", tag, strerror(errno)); 431 restore_uid(); 432 return 0; 433 } 434 435 /* 436 * Don't want to call this in the child, where it can fatal() and 437 * run cleanup_exit() code. 438 */ 439 restore_uid(); 440 441 switch ((pid = fork())) { 442 case -1: /* error */ 443 error("%s: fork: %s", tag, strerror(errno)); 444 close(p[0]); 445 close(p[1]); 446 return 0; 447 case 0: /* child */ 448 /* Prepare a minimal environment for the child. */ 449 envsize = 5; 450 child_env = xcalloc(sizeof(*child_env), envsize); 451 child_set_env(&child_env, &envsize, "PATH", _PATH_STDPATH); 452 child_set_env(&child_env, &envsize, "USER", pw->pw_name); 453 child_set_env(&child_env, &envsize, "LOGNAME", pw->pw_name); 454 child_set_env(&child_env, &envsize, "HOME", pw->pw_dir); 455 if ((cp = getenv("LANG")) != NULL) 456 child_set_env(&child_env, &envsize, "LANG", cp); 457 458 for (i = 0; i < NSIG; i++) 459 signal(i, SIG_DFL); 460 461 if ((devnull = open(_PATH_DEVNULL, O_RDWR)) == -1) { 462 error("%s: open %s: %s", tag, _PATH_DEVNULL, 463 strerror(errno)); 464 _exit(1); 465 } 466 /* Keep stderr around a while longer to catch errors */ 467 if (dup2(devnull, STDIN_FILENO) == -1 || 468 dup2(p[1], STDOUT_FILENO) == -1) { 469 error("%s: dup2: %s", tag, strerror(errno)); 470 _exit(1); 471 } 472 closefrom(STDERR_FILENO + 1); 473 474 /* Don't use permanently_set_uid() here to avoid fatal() */ 475 if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) != 0) { 476 error("%s: setresgid %u: %s", tag, (u_int)pw->pw_gid, 477 strerror(errno)); 478 _exit(1); 479 } 480 if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) != 0) { 481 error("%s: setresuid %u: %s", tag, (u_int)pw->pw_uid, 482 strerror(errno)); 483 _exit(1); 484 } 485 /* stdin is pointed to /dev/null at this point */ 486 if (dup2(STDIN_FILENO, STDERR_FILENO) == -1) { 487 error("%s: dup2: %s", tag, strerror(errno)); 488 _exit(1); 489 } 490 491 execve(av[0], av, child_env); 492 error("%s exec \"%s\": %s", tag, command, strerror(errno)); 493 _exit(127); 494 default: /* parent */ 495 break; 496 } 497 498 close(p[1]); 499 if ((f = fdopen(p[0], "r")) == NULL) { 500 error("%s: fdopen: %s", tag, strerror(errno)); 501 close(p[0]); 502 /* Don't leave zombie child */ 503 kill(pid, SIGTERM); 504 while (waitpid(pid, NULL, 0) == -1 && errno == EINTR) 505 ; 506 return 0; 507 } 508 /* Success */ 509 debug3("%s: %s pid %ld", __func__, tag, (long)pid); 510 *child = f; 511 return pid; 512 } 513 514 /* Returns 0 if pid exited cleanly, non-zero otherwise */ 515 static int 516 exited_cleanly(pid_t pid, const char *tag, const char *cmd) 517 { 518 int status; 519 520 while (waitpid(pid, &status, 0) == -1) { 521 if (errno != EINTR) { 522 error("%s: waitpid: %s", tag, strerror(errno)); 523 return -1; 524 } 525 } 526 if (WIFSIGNALED(status)) { 527 error("%s %s exited on signal %d", tag, cmd, WTERMSIG(status)); 528 return -1; 529 } else if (WEXITSTATUS(status) != 0) { 530 error("%s %s failed, status %d", tag, cmd, WEXITSTATUS(status)); 531 return -1; 532 } 533 return 0; 534 } 535 536 static int 537 match_principals_option(const char *principal_list, struct sshkey_cert *cert) 538 { 539 char *result; 540 u_int i; 541 542 /* XXX percent_expand() sequences for authorized_principals? */ 543 544 for (i = 0; i < cert->nprincipals; i++) { 545 if ((result = match_list(cert->principals[i], 546 principal_list, NULL)) != NULL) { 547 debug3("matched principal from key options \"%.100s\"", 548 result); 549 free(result); 550 return 1; 551 } 552 } 553 return 0; 554 } 555 556 static int 557 process_principals(FILE *f, char *file, struct passwd *pw, 558 struct sshkey_cert *cert) 559 { 560 char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts; 561 u_long linenum = 0; 562 u_int i; 563 564 while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { 565 /* Skip leading whitespace. */ 566 for (cp = line; *cp == ' ' || *cp == '\t'; cp++) 567 ; 568 /* Skip blank and comment lines. */ 569 if ((ep = strchr(cp, '#')) != NULL) 570 *ep = '\0'; 571 if (!*cp || *cp == '\n') 572 continue; 573 /* Trim trailing whitespace. */ 574 ep = cp + strlen(cp) - 1; 575 while (ep > cp && (*ep == '\n' || *ep == ' ' || *ep == '\t')) 576 *ep-- = '\0'; 577 /* 578 * If the line has internal whitespace then assume it has 579 * key options. 580 */ 581 line_opts = NULL; 582 if ((ep = strrchr(cp, ' ')) != NULL || 583 (ep = strrchr(cp, '\t')) != NULL) { 584 for (; *ep == ' ' || *ep == '\t'; ep++) 585 ; 586 line_opts = cp; 587 cp = ep; 588 } 589 for (i = 0; i < cert->nprincipals; i++) { 590 if (strcmp(cp, cert->principals[i]) == 0) { 591 debug3("%s:%lu: matched principal \"%.100s\"", 592 file == NULL ? "(command)" : file, 593 linenum, cert->principals[i]); 594 if (auth_parse_options(pw, line_opts, 595 file, linenum) != 1) 596 continue; 597 return 1; 598 } 599 } 600 } 601 return 0; 602 } 603 604 static int 605 match_principals_file(char *file, struct passwd *pw, struct sshkey_cert *cert) 606 { 607 FILE *f; 608 int success; 609 610 temporarily_use_uid(pw); 611 debug("trying authorized principals file %s", file); 612 if ((f = auth_openprincipals(file, pw, options.strict_modes)) == NULL) { 613 restore_uid(); 614 return 0; 615 } 616 success = process_principals(f, file, pw, cert); 617 fclose(f); 618 restore_uid(); 619 return success; 620 } 621 622 /* 623 * Checks whether principal is allowed in output of command. 624 * returns 1 if the principal is allowed or 0 otherwise. 625 */ 626 static int 627 match_principals_command(struct passwd *user_pw, struct sshkey_cert *cert) 628 { 629 FILE *f = NULL; 630 int ok, found_principal = 0; 631 struct passwd *pw; 632 int i, ac = 0, uid_swapped = 0; 633 pid_t pid; 634 char *tmp, *username = NULL, *command = NULL, **av = NULL; 635 void (*osigchld)(int); 636 637 if (options.authorized_principals_command == NULL) 638 return 0; 639 if (options.authorized_principals_command_user == NULL) { 640 error("No user for AuthorizedPrincipalsCommand specified, " 641 "skipping"); 642 return 0; 643 } 644 645 /* 646 * NB. all returns later this function should go via "out" to 647 * ensure the original SIGCHLD handler is restored properly. 648 */ 649 osigchld = signal(SIGCHLD, SIG_DFL); 650 651 /* Prepare and verify the user for the command */ 652 username = percent_expand(options.authorized_principals_command_user, 653 "u", user_pw->pw_name, (char *)NULL); 654 pw = getpwnam(username); 655 if (pw == NULL) { 656 error("AuthorizedPrincipalsCommandUser \"%s\" not found: %s", 657 username, strerror(errno)); 658 goto out; 659 } 660 661 /* Turn the command into an argument vector */ 662 if (split_argv(options.authorized_principals_command, &ac, &av) != 0) { 663 error("AuthorizedPrincipalsCommand \"%s\" contains " 664 "invalid quotes", command); 665 goto out; 666 } 667 if (ac == 0) { 668 error("AuthorizedPrincipalsCommand \"%s\" yielded no arguments", 669 command); 670 goto out; 671 } 672 for (i = 1; i < ac; i++) { 673 tmp = percent_expand(av[i], 674 "u", user_pw->pw_name, 675 "h", user_pw->pw_dir, 676 (char *)NULL); 677 if (tmp == NULL) 678 fatal("%s: percent_expand failed", __func__); 679 free(av[i]); 680 av[i] = tmp; 681 } 682 /* Prepare a printable command for logs, etc. */ 683 command = assemble_argv(ac, av); 684 685 if ((pid = subprocess("AuthorizedPrincipalsCommand", pw, command, 686 ac, av, &f)) == 0) 687 goto out; 688 689 uid_swapped = 1; 690 temporarily_use_uid(pw); 691 692 ok = process_principals(f, NULL, pw, cert); 693 694 if (exited_cleanly(pid, "AuthorizedPrincipalsCommand", command) != 0) 695 goto out; 696 697 /* Read completed successfully */ 698 found_principal = ok; 699 out: 700 if (f != NULL) 701 fclose(f); 702 signal(SIGCHLD, osigchld); 703 for (i = 0; i < ac; i++) 704 free(av[i]); 705 free(av); 706 if (uid_swapped) 707 restore_uid(); 708 free(command); 709 free(username); 710 return found_principal; 711 } 712 /* 713 * Checks whether key is allowed in authorized_keys-format file, 714 * returns 1 if the key is allowed or 0 otherwise. 715 */ 716 static int 717 check_authkeys_file(FILE *f, char *file, Key* key, struct passwd *pw) 718 { 719 char line[SSH_MAX_PUBKEY_BYTES]; 720 const char *reason; 721 int found_key = 0; 722 u_long linenum = 0; 723 Key *found; 724 char *fp; 725 726 found_key = 0; 727 728 found = NULL; 729 while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { 730 char *cp, *key_options = NULL; 731 if (found != NULL) 732 key_free(found); 733 found = key_new(key_is_cert(key) ? KEY_UNSPEC : key->type); 734 auth_clear_options(); 735 736 /* Skip leading whitespace, empty and comment lines. */ 737 for (cp = line; *cp == ' ' || *cp == '\t'; cp++) 738 ; 739 if (!*cp || *cp == '\n' || *cp == '#') 740 continue; 741 742 if (key_read(found, &cp) != 1) { 743 /* no key? check if there are options for this key */ 744 int quoted = 0; 745 debug2("user_key_allowed: check options: '%s'", cp); 746 key_options = cp; 747 for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { 748 if (*cp == '\\' && cp[1] == '"') 749 cp++; /* Skip both */ 750 else if (*cp == '"') 751 quoted = !quoted; 752 } 753 /* Skip remaining whitespace. */ 754 for (; *cp == ' ' || *cp == '\t'; cp++) 755 ; 756 if (key_read(found, &cp) != 1) { 757 debug2("user_key_allowed: advance: '%s'", cp); 758 /* still no key? advance to next line*/ 759 continue; 760 } 761 } 762 if (key_is_cert(key)) { 763 if (!key_equal(found, key->cert->signature_key)) 764 continue; 765 if (auth_parse_options(pw, key_options, file, 766 linenum) != 1) 767 continue; 768 if (!key_is_cert_authority) 769 continue; 770 if ((fp = sshkey_fingerprint(found, 771 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) 772 continue; 773 debug("matching CA found: file %s, line %lu, %s %s", 774 file, linenum, key_type(found), fp); 775 /* 776 * If the user has specified a list of principals as 777 * a key option, then prefer that list to matching 778 * their username in the certificate principals list. 779 */ 780 if (authorized_principals != NULL && 781 !match_principals_option(authorized_principals, 782 key->cert)) { 783 reason = "Certificate does not contain an " 784 "authorized principal"; 785 fail_reason: 786 free(fp); 787 error("%s", reason); 788 auth_debug_add("%s", reason); 789 continue; 790 } 791 if (key_cert_check_authority(key, 0, 0, 792 authorized_principals == NULL ? pw->pw_name : NULL, 793 &reason) != 0) 794 goto fail_reason; 795 if (auth_cert_options(key, pw) != 0) { 796 free(fp); 797 continue; 798 } 799 verbose("Accepted certificate ID \"%s\" " 800 "signed by %s CA %s via %s", key->cert->key_id, 801 key_type(found), fp, file); 802 free(fp); 803 found_key = 1; 804 break; 805 } else if (key_equal(found, key)) { 806 if (auth_parse_options(pw, key_options, file, 807 linenum) != 1) 808 continue; 809 if (key_is_cert_authority) 810 continue; 811 if ((fp = sshkey_fingerprint(found, 812 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) 813 continue; 814 debug("matching key found: file %s, line %lu %s %s", 815 file, linenum, key_type(found), fp); 816 free(fp); 817 found_key = 1; 818 break; 819 } 820 } 821 if (found != NULL) 822 key_free(found); 823 if (!found_key) 824 debug2("key not found"); 825 return found_key; 826 } 827 828 /* Authenticate a certificate key against TrustedUserCAKeys */ 829 static int 830 user_cert_trusted_ca(struct passwd *pw, Key *key) 831 { 832 char *ca_fp, *principals_file = NULL; 833 const char *reason; 834 int ret = 0, found_principal = 0, use_authorized_principals; 835 836 if (!key_is_cert(key) || options.trusted_user_ca_keys == NULL) 837 return 0; 838 839 if ((ca_fp = sshkey_fingerprint(key->cert->signature_key, 840 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) 841 return 0; 842 843 if (sshkey_in_file(key->cert->signature_key, 844 options.trusted_user_ca_keys, 1, 0) != 0) { 845 debug2("%s: CA %s %s is not listed in %s", __func__, 846 key_type(key->cert->signature_key), ca_fp, 847 options.trusted_user_ca_keys); 848 goto out; 849 } 850 /* 851 * If AuthorizedPrincipals is in use, then compare the certificate 852 * principals against the names in that file rather than matching 853 * against the username. 854 */ 855 if ((principals_file = authorized_principals_file(pw)) != NULL) { 856 if (match_principals_file(principals_file, pw, key->cert)) 857 found_principal = 1; 858 } 859 /* Try querying command if specified */ 860 if (!found_principal && match_principals_command(pw, key->cert)) 861 found_principal = 1; 862 /* If principals file or command is specified, then require a match */ 863 use_authorized_principals = principals_file != NULL || 864 options.authorized_principals_command != NULL; 865 if (!found_principal && use_authorized_principals) { 866 reason = "Certificate does not contain an authorized principal"; 867 fail_reason: 868 error("%s", reason); 869 auth_debug_add("%s", reason); 870 goto out; 871 } 872 if (key_cert_check_authority(key, 0, 1, 873 use_authorized_principals ? NULL : pw->pw_name, &reason) != 0) 874 goto fail_reason; 875 if (auth_cert_options(key, pw) != 0) 876 goto out; 877 878 verbose("Accepted certificate ID \"%s\" signed by %s CA %s via %s", 879 key->cert->key_id, key_type(key->cert->signature_key), ca_fp, 880 options.trusted_user_ca_keys); 881 ret = 1; 882 883 out: 884 free(principals_file); 885 free(ca_fp); 886 return ret; 887 } 888 889 /* 890 * Checks whether key is allowed in file. 891 * returns 1 if the key is allowed or 0 otherwise. 892 */ 893 static int 894 user_key_allowed2(struct passwd *pw, Key *key, char *file) 895 { 896 FILE *f; 897 int found_key = 0; 898 899 /* Temporarily use the user's uid. */ 900 temporarily_use_uid(pw); 901 902 debug("trying public key file %s", file); 903 if ((f = auth_openkeyfile(file, pw, options.strict_modes)) != NULL) { 904 found_key = check_authkeys_file(f, file, key, pw); 905 fclose(f); 906 } 907 908 restore_uid(); 909 return found_key; 910 } 911 912 /* 913 * Checks whether key is allowed in output of command. 914 * returns 1 if the key is allowed or 0 otherwise. 915 */ 916 static int 917 user_key_command_allowed2(struct passwd *user_pw, Key *key) 918 { 919 FILE *f = NULL; 920 int r, ok, found_key = 0; 921 struct passwd *pw; 922 int i, uid_swapped = 0, ac = 0; 923 pid_t pid; 924 char *username = NULL, *key_fp = NULL, *keytext = NULL; 925 char *tmp, *command = NULL, **av = NULL; 926 void (*osigchld)(int); 927 928 if (options.authorized_keys_command == NULL) 929 return 0; 930 if (options.authorized_keys_command_user == NULL) { 931 error("No user for AuthorizedKeysCommand specified, skipping"); 932 return 0; 933 } 934 935 /* 936 * NB. all returns later this function should go via "out" to 937 * ensure the original SIGCHLD handler is restored properly. 938 */ 939 osigchld = signal(SIGCHLD, SIG_DFL); 940 941 /* Prepare and verify the user for the command */ 942 username = percent_expand(options.authorized_keys_command_user, 943 "u", user_pw->pw_name, (char *)NULL); 944 pw = getpwnam(username); 945 if (pw == NULL) { 946 error("AuthorizedKeysCommandUser \"%s\" not found: %s", 947 username, strerror(errno)); 948 goto out; 949 } 950 951 /* Prepare AuthorizedKeysCommand */ 952 if ((key_fp = sshkey_fingerprint(key, options.fingerprint_hash, 953 SSH_FP_DEFAULT)) == NULL) { 954 error("%s: sshkey_fingerprint failed", __func__); 955 goto out; 956 } 957 if ((r = sshkey_to_base64(key, &keytext)) != 0) { 958 error("%s: sshkey_to_base64 failed: %s", __func__, ssh_err(r)); 959 goto out; 960 } 961 962 /* Turn the command into an argument vector */ 963 if (split_argv(options.authorized_keys_command, &ac, &av) != 0) { 964 error("AuthorizedKeysCommand \"%s\" contains invalid quotes", 965 command); 966 goto out; 967 } 968 if (ac == 0) { 969 error("AuthorizedKeysCommand \"%s\" yielded no arguments", 970 command); 971 goto out; 972 } 973 for (i = 1; i < ac; i++) { 974 tmp = percent_expand(av[i], 975 "u", user_pw->pw_name, 976 "h", user_pw->pw_dir, 977 "t", sshkey_ssh_name(key), 978 "f", key_fp, 979 "k", keytext, 980 (char *)NULL); 981 if (tmp == NULL) 982 fatal("%s: percent_expand failed", __func__); 983 free(av[i]); 984 av[i] = tmp; 985 } 986 /* Prepare a printable command for logs, etc. */ 987 command = assemble_argv(ac, av); 988 989 /* 990 * If AuthorizedKeysCommand was run without arguments 991 * then fall back to the old behaviour of passing the 992 * target username as a single argument. 993 */ 994 if (ac == 1) { 995 av = xreallocarray(av, ac + 2, sizeof(*av)); 996 av[1] = xstrdup(user_pw->pw_name); 997 av[2] = NULL; 998 /* Fix up command too, since it is used in log messages */ 999 free(command); 1000 xasprintf(&command, "%s %s", av[0], av[1]); 1001 } 1002 1003 if ((pid = subprocess("AuthorizedKeysCommand", pw, command, 1004 ac, av, &f)) == 0) 1005 goto out; 1006 1007 uid_swapped = 1; 1008 temporarily_use_uid(pw); 1009 1010 ok = check_authkeys_file(f, options.authorized_keys_command, key, pw); 1011 1012 if (exited_cleanly(pid, "AuthorizedKeysCommand", command) != 0) 1013 goto out; 1014 1015 /* Read completed successfully */ 1016 found_key = ok; 1017 out: 1018 if (f != NULL) 1019 fclose(f); 1020 signal(SIGCHLD, osigchld); 1021 for (i = 0; i < ac; i++) 1022 free(av[i]); 1023 free(av); 1024 if (uid_swapped) 1025 restore_uid(); 1026 free(command); 1027 free(username); 1028 free(key_fp); 1029 free(keytext); 1030 return found_key; 1031 } 1032 1033 /* 1034 * Check whether key authenticates and authorises the user. 1035 */ 1036 int 1037 user_key_allowed(struct passwd *pw, Key *key, int auth_attempt) 1038 { 1039 u_int success, i; 1040 char *file; 1041 1042 if (auth_key_is_revoked(key)) 1043 return 0; 1044 if (key_is_cert(key) && auth_key_is_revoked(key->cert->signature_key)) 1045 return 0; 1046 1047 success = user_cert_trusted_ca(pw, key); 1048 if (success) 1049 return success; 1050 1051 success = user_key_command_allowed2(pw, key); 1052 if (success > 0) 1053 return success; 1054 1055 for (i = 0; !success && i < options.num_authkeys_files; i++) { 1056 1057 if (strcasecmp(options.authorized_keys_files[i], "none") == 0) 1058 continue; 1059 file = expand_authorized_keys( 1060 options.authorized_keys_files[i], pw); 1061 1062 success = user_key_allowed2(pw, key, file); 1063 free(file); 1064 } 1065 1066 return success; 1067 } 1068 1069 /* Records a public key in the list of previously-successful keys */ 1070 void 1071 auth2_record_userkey(Authctxt *authctxt, struct sshkey *key) 1072 { 1073 struct sshkey **tmp; 1074 1075 if (authctxt->nprev_userkeys >= INT_MAX || 1076 (tmp = reallocarray(authctxt->prev_userkeys, 1077 authctxt->nprev_userkeys + 1, sizeof(*tmp))) == NULL) 1078 fatal("%s: reallocarray failed", __func__); 1079 authctxt->prev_userkeys = tmp; 1080 authctxt->prev_userkeys[authctxt->nprev_userkeys] = key; 1081 authctxt->nprev_userkeys++; 1082 } 1083 1084 /* Checks whether a key has already been used successfully for authentication */ 1085 int 1086 auth2_userkey_already_used(Authctxt *authctxt, struct sshkey *key) 1087 { 1088 u_int i; 1089 1090 for (i = 0; i < authctxt->nprev_userkeys; i++) { 1091 if (sshkey_equal_public(key, authctxt->prev_userkeys[i])) { 1092 return 1; 1093 } 1094 } 1095 return 0; 1096 } 1097 1098 Authmethod method_pubkey = { 1099 "publickey", 1100 userauth_pubkey, 1101 &options.pubkey_authentication 1102 }; 1103