1 /* $OpenBSD: auth2-pubkey.c,v 1.71 2017/09/07 23:48:09 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 27 #include <sys/types.h> 28 #include <sys/stat.h> 29 30 #include <errno.h> 31 #include <fcntl.h> 32 #include <paths.h> 33 #include <pwd.h> 34 #include <signal.h> 35 #include <stdio.h> 36 #include <stdarg.h> 37 #include <string.h> 38 #include <time.h> 39 #include <unistd.h> 40 #include <limits.h> 41 42 #include "xmalloc.h" 43 #include "ssh.h" 44 #include "ssh2.h" 45 #include "packet.h" 46 #include "buffer.h" 47 #include "log.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 "pathnames.h" 55 #include "uidswap.h" 56 #include "auth-options.h" 57 #include "canohost.h" 58 #ifdef GSSAPI 59 #include "ssh-gss.h" 60 #endif 61 #include "monitor_wrap.h" 62 #include "authfile.h" 63 #include "match.h" 64 #include "ssherr.h" 65 #include "channels.h" /* XXX for session.h */ 66 #include "session.h" /* XXX for child_set_env(); refactor? */ 67 68 /* import */ 69 extern ServerOptions options; 70 extern u_char *session_id2; 71 extern u_int session_id2_len; 72 73 static int 74 userauth_pubkey(struct ssh *ssh) 75 { 76 Authctxt *authctxt = ssh->authctxt; 77 struct sshbuf *b; 78 struct sshkey *key = NULL; 79 char *pkalg, *userstyle = NULL, *fp = NULL; 80 u_char *pkblob, *sig, have_sig; 81 size_t blen, slen; 82 int r, pktype; 83 int authenticated = 0; 84 85 if (!authctxt->valid) { 86 debug2("%s: disabled because of invalid user", __func__); 87 return 0; 88 } 89 if ((r = sshpkt_get_u8(ssh, &have_sig)) != 0) 90 fatal("%s: sshpkt_get_u8 failed: %s", __func__, ssh_err(r)); 91 if (ssh->compat & SSH_BUG_PKAUTH) { 92 debug2("%s: SSH_BUG_PKAUTH", __func__); 93 if ((b = sshbuf_new()) == NULL) 94 fatal("%s: sshbuf_new failed", __func__); 95 /* no explicit pkalg given */ 96 /* so we have to extract the pkalg from the pkblob */ 97 /* XXX use sshbuf_from() */ 98 if ((r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0 || 99 (r = sshbuf_put(b, pkblob, blen)) != 0 || 100 (r = sshbuf_get_cstring(b, &pkalg, NULL)) != 0) 101 fatal("%s: failed: %s", __func__, ssh_err(r)); 102 sshbuf_free(b); 103 } else { 104 if ((r = sshpkt_get_cstring(ssh, &pkalg, NULL)) != 0 || 105 (r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0) 106 fatal("%s: sshpkt_get_cstring failed: %s", 107 __func__, ssh_err(r)); 108 } 109 pktype = sshkey_type_from_name(pkalg); 110 if (pktype == KEY_UNSPEC) { 111 /* this is perfectly legal */ 112 logit("%s: unsupported public key algorithm: %s", 113 __func__, pkalg); 114 goto done; 115 } 116 if ((r = sshkey_from_blob(pkblob, blen, &key)) != 0) { 117 error("%s: could not parse key: %s", __func__, ssh_err(r)); 118 goto done; 119 } 120 if (key == NULL) { 121 error("%s: cannot decode key: %s", __func__, pkalg); 122 goto done; 123 } 124 if (key->type != pktype) { 125 error("%s: type mismatch for decoded key " 126 "(received %d, expected %d)", __func__, key->type, pktype); 127 goto done; 128 } 129 if (sshkey_type_plain(key->type) == KEY_RSA && 130 (ssh->compat & SSH_BUG_RSASIGMD5) != 0) { 131 logit("Refusing RSA key because client uses unsafe " 132 "signature scheme"); 133 goto done; 134 } 135 fp = sshkey_fingerprint(key, options.fingerprint_hash, SSH_FP_DEFAULT); 136 if (auth2_key_already_used(authctxt, key)) { 137 logit("refusing previously-used %s key", sshkey_type(key)); 138 goto done; 139 } 140 if (match_pattern_list(sshkey_ssh_name(key), 141 options.pubkey_key_types, 0) != 1) { 142 logit("%s: key type %s not in PubkeyAcceptedKeyTypes", 143 __func__, sshkey_ssh_name(key)); 144 goto done; 145 } 146 147 if (have_sig) { 148 debug3("%s: have signature for %s %s", 149 __func__, sshkey_type(key), fp); 150 if ((r = sshpkt_get_string(ssh, &sig, &slen)) != 0 || 151 (r = sshpkt_get_end(ssh)) != 0) 152 fatal("%s: %s", __func__, ssh_err(r)); 153 if ((b = sshbuf_new()) == NULL) 154 fatal("%s: sshbuf_new failed", __func__); 155 if (ssh->compat & SSH_OLD_SESSIONID) { 156 if ((r = sshbuf_put(b, session_id2, 157 session_id2_len)) != 0) 158 fatal("%s: sshbuf_put session id: %s", 159 __func__, ssh_err(r)); 160 } else { 161 if ((r = sshbuf_put_string(b, session_id2, 162 session_id2_len)) != 0) 163 fatal("%s: sshbuf_put_string session id: %s", 164 __func__, ssh_err(r)); 165 } 166 /* reconstruct packet */ 167 xasprintf(&userstyle, "%s%s%s", authctxt->user, 168 authctxt->style ? ":" : "", 169 authctxt->style ? authctxt->style : ""); 170 if ((r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 || 171 (r = sshbuf_put_cstring(b, userstyle)) != 0 || 172 (r = sshbuf_put_cstring(b, ssh->compat & SSH_BUG_PKSERVICE ? 173 "ssh-userauth" : authctxt->service)) != 0) 174 fatal("%s: build packet failed: %s", 175 __func__, ssh_err(r)); 176 if (ssh->compat & SSH_BUG_PKAUTH) { 177 if ((r = sshbuf_put_u8(b, have_sig)) != 0) 178 fatal("%s: build packet failed: %s", 179 __func__, ssh_err(r)); 180 } else { 181 if ((r = sshbuf_put_cstring(b, "publickey")) != 0 || 182 (r = sshbuf_put_u8(b, have_sig)) != 0 || 183 (r = sshbuf_put_cstring(b, pkalg) != 0)) 184 fatal("%s: build packet failed: %s", 185 __func__, ssh_err(r)); 186 } 187 if ((r = sshbuf_put_string(b, pkblob, blen)) != 0) 188 fatal("%s: build packet failed: %s", 189 __func__, ssh_err(r)); 190 #ifdef DEBUG_PK 191 sshbuf_dump(b, stderr); 192 #endif 193 194 /* test for correct signature */ 195 authenticated = 0; 196 if (PRIVSEP(user_key_allowed(authctxt->pw, key, 1)) && 197 PRIVSEP(sshkey_verify(key, sig, slen, sshbuf_ptr(b), 198 sshbuf_len(b), ssh->compat)) == 0) { 199 authenticated = 1; 200 } 201 sshbuf_free(b); 202 free(sig); 203 auth2_record_key(authctxt, authenticated, key); 204 } else { 205 debug("%s: test whether pkalg/pkblob are acceptable for %s %s", 206 __func__, sshkey_type(key), fp); 207 if ((r = sshpkt_get_end(ssh)) != 0) 208 fatal("%s: %s", __func__, ssh_err(r)); 209 210 /* XXX fake reply and always send PK_OK ? */ 211 /* 212 * XXX this allows testing whether a user is allowed 213 * to login: if you happen to have a valid pubkey this 214 * message is sent. the message is NEVER sent at all 215 * if a user is not allowed to login. is this an 216 * issue? -markus 217 */ 218 if (PRIVSEP(user_key_allowed(authctxt->pw, key, 0))) { 219 if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_PK_OK)) 220 != 0 || 221 (r = sshpkt_put_cstring(ssh, pkalg)) != 0 || 222 (r = sshpkt_put_string(ssh, pkblob, blen)) != 0 || 223 (r = sshpkt_send(ssh)) != 0) 224 fatal("%s: %s", __func__, ssh_err(r)); 225 ssh_packet_write_wait(ssh); 226 authctxt->postponed = 1; 227 } 228 } 229 if (authenticated != 1) 230 auth_clear_options(); 231 done: 232 debug2("%s: authenticated %d pkalg %s", __func__, authenticated, pkalg); 233 sshkey_free(key); 234 free(userstyle); 235 free(pkalg); 236 free(pkblob); 237 free(fp); 238 return authenticated; 239 } 240 241 static int 242 match_principals_option(const char *principal_list, struct sshkey_cert *cert) 243 { 244 char *result; 245 u_int i; 246 247 /* XXX percent_expand() sequences for authorized_principals? */ 248 249 for (i = 0; i < cert->nprincipals; i++) { 250 if ((result = match_list(cert->principals[i], 251 principal_list, NULL)) != NULL) { 252 debug3("matched principal from key options \"%.100s\"", 253 result); 254 free(result); 255 return 1; 256 } 257 } 258 return 0; 259 } 260 261 static int 262 process_principals(FILE *f, const char *file, struct passwd *pw, 263 const struct sshkey_cert *cert) 264 { 265 char line[SSH_MAX_PUBKEY_BYTES], *cp, *ep, *line_opts; 266 u_long linenum = 0; 267 u_int i, found_principal = 0; 268 269 while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { 270 /* Always consume entire input */ 271 if (found_principal) 272 continue; 273 /* Skip leading whitespace. */ 274 for (cp = line; *cp == ' ' || *cp == '\t'; cp++) 275 ; 276 /* Skip blank and comment lines. */ 277 if ((ep = strchr(cp, '#')) != NULL) 278 *ep = '\0'; 279 if (!*cp || *cp == '\n') 280 continue; 281 /* Trim trailing whitespace. */ 282 ep = cp + strlen(cp) - 1; 283 while (ep > cp && (*ep == '\n' || *ep == ' ' || *ep == '\t')) 284 *ep-- = '\0'; 285 /* 286 * If the line has internal whitespace then assume it has 287 * key options. 288 */ 289 line_opts = NULL; 290 if ((ep = strrchr(cp, ' ')) != NULL || 291 (ep = strrchr(cp, '\t')) != NULL) { 292 for (; *ep == ' ' || *ep == '\t'; ep++) 293 ; 294 line_opts = cp; 295 cp = ep; 296 } 297 for (i = 0; i < cert->nprincipals; i++) { 298 if (strcmp(cp, cert->principals[i]) == 0) { 299 debug3("%s:%lu: matched principal \"%.100s\"", 300 file, linenum, cert->principals[i]); 301 if (auth_parse_options(pw, line_opts, 302 file, linenum) != 1) 303 continue; 304 found_principal = 1; 305 continue; 306 } 307 } 308 } 309 return found_principal; 310 } 311 312 static int 313 match_principals_file(char *file, struct passwd *pw, struct sshkey_cert *cert) 314 { 315 FILE *f; 316 int success; 317 318 temporarily_use_uid(pw); 319 debug("trying authorized principals file %s", file); 320 if ((f = auth_openprincipals(file, pw, options.strict_modes)) == NULL) { 321 restore_uid(); 322 return 0; 323 } 324 success = process_principals(f, file, pw, cert); 325 fclose(f); 326 restore_uid(); 327 return success; 328 } 329 330 /* 331 * Checks whether principal is allowed in output of command. 332 * returns 1 if the principal is allowed or 0 otherwise. 333 */ 334 static int 335 match_principals_command(struct passwd *user_pw, const struct sshkey *key) 336 { 337 const struct sshkey_cert *cert = key->cert; 338 FILE *f = NULL; 339 int r, ok, found_principal = 0; 340 struct passwd *pw; 341 int i, ac = 0, uid_swapped = 0; 342 pid_t pid; 343 char *tmp, *username = NULL, *command = NULL, **av = NULL; 344 char *ca_fp = NULL, *key_fp = NULL, *catext = NULL, *keytext = NULL; 345 char serial_s[16]; 346 void (*osigchld)(int); 347 348 if (options.authorized_principals_command == NULL) 349 return 0; 350 if (options.authorized_principals_command_user == NULL) { 351 error("No user for AuthorizedPrincipalsCommand specified, " 352 "skipping"); 353 return 0; 354 } 355 356 /* 357 * NB. all returns later this function should go via "out" to 358 * ensure the original SIGCHLD handler is restored properly. 359 */ 360 osigchld = signal(SIGCHLD, SIG_DFL); 361 362 /* Prepare and verify the user for the command */ 363 username = percent_expand(options.authorized_principals_command_user, 364 "u", user_pw->pw_name, (char *)NULL); 365 pw = getpwnam(username); 366 if (pw == NULL) { 367 error("AuthorizedPrincipalsCommandUser \"%s\" not found: %s", 368 username, strerror(errno)); 369 goto out; 370 } 371 372 /* Turn the command into an argument vector */ 373 if (argv_split(options.authorized_principals_command, &ac, &av) != 0) { 374 error("AuthorizedPrincipalsCommand \"%s\" contains " 375 "invalid quotes", command); 376 goto out; 377 } 378 if (ac == 0) { 379 error("AuthorizedPrincipalsCommand \"%s\" yielded no arguments", 380 command); 381 goto out; 382 } 383 if ((ca_fp = sshkey_fingerprint(cert->signature_key, 384 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) { 385 error("%s: sshkey_fingerprint failed", __func__); 386 goto out; 387 } 388 if ((key_fp = sshkey_fingerprint(key, 389 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) { 390 error("%s: sshkey_fingerprint failed", __func__); 391 goto out; 392 } 393 if ((r = sshkey_to_base64(cert->signature_key, &catext)) != 0) { 394 error("%s: sshkey_to_base64 failed: %s", __func__, ssh_err(r)); 395 goto out; 396 } 397 if ((r = sshkey_to_base64(key, &keytext)) != 0) { 398 error("%s: sshkey_to_base64 failed: %s", __func__, ssh_err(r)); 399 goto out; 400 } 401 snprintf(serial_s, sizeof(serial_s), "%llu", 402 (unsigned long long)cert->serial); 403 for (i = 1; i < ac; i++) { 404 tmp = percent_expand(av[i], 405 "u", user_pw->pw_name, 406 "h", user_pw->pw_dir, 407 "t", sshkey_ssh_name(key), 408 "T", sshkey_ssh_name(cert->signature_key), 409 "f", key_fp, 410 "F", ca_fp, 411 "k", keytext, 412 "K", catext, 413 "i", cert->key_id, 414 "s", serial_s, 415 (char *)NULL); 416 if (tmp == NULL) 417 fatal("%s: percent_expand failed", __func__); 418 free(av[i]); 419 av[i] = tmp; 420 } 421 /* Prepare a printable command for logs, etc. */ 422 command = argv_assemble(ac, av); 423 424 if ((pid = subprocess("AuthorizedPrincipalsCommand", pw, command, 425 ac, av, &f, 426 SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0) 427 goto out; 428 429 uid_swapped = 1; 430 temporarily_use_uid(pw); 431 432 ok = process_principals(f, "(command)", pw, cert); 433 434 fclose(f); 435 f = NULL; 436 437 if (exited_cleanly(pid, "AuthorizedPrincipalsCommand", command, 0) != 0) 438 goto out; 439 440 /* Read completed successfully */ 441 found_principal = ok; 442 out: 443 if (f != NULL) 444 fclose(f); 445 signal(SIGCHLD, osigchld); 446 for (i = 0; i < ac; i++) 447 free(av[i]); 448 free(av); 449 if (uid_swapped) 450 restore_uid(); 451 free(command); 452 free(username); 453 free(ca_fp); 454 free(key_fp); 455 free(catext); 456 free(keytext); 457 return found_principal; 458 } 459 /* 460 * Checks whether key is allowed in authorized_keys-format file, 461 * returns 1 if the key is allowed or 0 otherwise. 462 */ 463 static int 464 check_authkeys_file(FILE *f, char *file, struct sshkey *key, struct passwd *pw) 465 { 466 char line[SSH_MAX_PUBKEY_BYTES]; 467 int found_key = 0; 468 u_long linenum = 0; 469 struct sshkey *found = NULL; 470 471 while (read_keyfile_line(f, file, line, sizeof(line), &linenum) != -1) { 472 char *cp, *key_options = NULL, *fp = NULL; 473 const char *reason = NULL; 474 475 /* Always consume entire file */ 476 if (found_key) 477 continue; 478 if (found != NULL) 479 sshkey_free(found); 480 found = sshkey_new(sshkey_is_cert(key) ? KEY_UNSPEC : key->type); 481 if (found == NULL) 482 goto done; 483 auth_clear_options(); 484 485 /* Skip leading whitespace, empty and comment lines. */ 486 for (cp = line; *cp == ' ' || *cp == '\t'; cp++) 487 ; 488 if (!*cp || *cp == '\n' || *cp == '#') 489 continue; 490 491 if (sshkey_read(found, &cp) != 0) { 492 /* no key? check if there are options for this key */ 493 int quoted = 0; 494 debug2("user_key_allowed: check options: '%s'", cp); 495 key_options = cp; 496 for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { 497 if (*cp == '\\' && cp[1] == '"') 498 cp++; /* Skip both */ 499 else if (*cp == '"') 500 quoted = !quoted; 501 } 502 /* Skip remaining whitespace. */ 503 for (; *cp == ' ' || *cp == '\t'; cp++) 504 ; 505 if (sshkey_read(found, &cp) != 0) { 506 debug2("user_key_allowed: advance: '%s'", cp); 507 /* still no key? advance to next line*/ 508 continue; 509 } 510 } 511 if (sshkey_is_cert(key)) { 512 if (!sshkey_equal(found, key->cert->signature_key)) 513 continue; 514 if (auth_parse_options(pw, key_options, file, 515 linenum) != 1) 516 continue; 517 if (!key_is_cert_authority) 518 continue; 519 if ((fp = sshkey_fingerprint(found, 520 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) 521 continue; 522 debug("matching CA found: file %s, line %lu, %s %s", 523 file, linenum, sshkey_type(found), fp); 524 /* 525 * If the user has specified a list of principals as 526 * a key option, then prefer that list to matching 527 * their username in the certificate principals list. 528 */ 529 if (authorized_principals != NULL && 530 !match_principals_option(authorized_principals, 531 key->cert)) { 532 reason = "Certificate does not contain an " 533 "authorized principal"; 534 fail_reason: 535 free(fp); 536 error("%s", reason); 537 auth_debug_add("%s", reason); 538 continue; 539 } 540 if (sshkey_cert_check_authority(key, 0, 0, 541 authorized_principals == NULL ? pw->pw_name : NULL, 542 &reason) != 0) 543 goto fail_reason; 544 if (auth_cert_options(key, pw, &reason) != 0) 545 goto fail_reason; 546 verbose("Accepted certificate ID \"%s\" (serial %llu) " 547 "signed by %s CA %s via %s", key->cert->key_id, 548 (unsigned long long)key->cert->serial, 549 sshkey_type(found), fp, file); 550 free(fp); 551 found_key = 1; 552 break; 553 } else if (sshkey_equal(found, key)) { 554 if (auth_parse_options(pw, key_options, file, 555 linenum) != 1) 556 continue; 557 if (key_is_cert_authority) 558 continue; 559 if ((fp = sshkey_fingerprint(found, 560 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) 561 continue; 562 debug("matching key found: file %s, line %lu %s %s", 563 file, linenum, sshkey_type(found), fp); 564 free(fp); 565 found_key = 1; 566 continue; 567 } 568 } 569 done: 570 if (found != NULL) 571 sshkey_free(found); 572 if (!found_key) 573 debug2("key not found"); 574 return found_key; 575 } 576 577 /* Authenticate a certificate key against TrustedUserCAKeys */ 578 static int 579 user_cert_trusted_ca(struct passwd *pw, struct sshkey *key) 580 { 581 char *ca_fp, *principals_file = NULL; 582 const char *reason; 583 int r, ret = 0, found_principal = 0, use_authorized_principals; 584 585 if (!sshkey_is_cert(key) || options.trusted_user_ca_keys == NULL) 586 return 0; 587 588 if ((ca_fp = sshkey_fingerprint(key->cert->signature_key, 589 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) 590 return 0; 591 592 if ((r = sshkey_in_file(key->cert->signature_key, 593 options.trusted_user_ca_keys, 1, 0)) != 0) { 594 debug2("%s: CA %s %s is not listed in %s: %s", __func__, 595 sshkey_type(key->cert->signature_key), ca_fp, 596 options.trusted_user_ca_keys, ssh_err(r)); 597 goto out; 598 } 599 /* 600 * If AuthorizedPrincipals is in use, then compare the certificate 601 * principals against the names in that file rather than matching 602 * against the username. 603 */ 604 if ((principals_file = authorized_principals_file(pw)) != NULL) { 605 if (match_principals_file(principals_file, pw, key->cert)) 606 found_principal = 1; 607 } 608 /* Try querying command if specified */ 609 if (!found_principal && match_principals_command(pw, key)) 610 found_principal = 1; 611 /* If principals file or command is specified, then require a match */ 612 use_authorized_principals = principals_file != NULL || 613 options.authorized_principals_command != NULL; 614 if (!found_principal && use_authorized_principals) { 615 reason = "Certificate does not contain an authorized principal"; 616 fail_reason: 617 error("%s", reason); 618 auth_debug_add("%s", reason); 619 goto out; 620 } 621 if (sshkey_cert_check_authority(key, 0, 1, 622 use_authorized_principals ? NULL : pw->pw_name, &reason) != 0) 623 goto fail_reason; 624 if (auth_cert_options(key, pw, &reason) != 0) 625 goto fail_reason; 626 627 verbose("Accepted certificate ID \"%s\" (serial %llu) signed by " 628 "%s CA %s via %s", key->cert->key_id, 629 (unsigned long long)key->cert->serial, 630 sshkey_type(key->cert->signature_key), ca_fp, 631 options.trusted_user_ca_keys); 632 ret = 1; 633 634 out: 635 free(principals_file); 636 free(ca_fp); 637 return ret; 638 } 639 640 /* 641 * Checks whether key is allowed in file. 642 * returns 1 if the key is allowed or 0 otherwise. 643 */ 644 static int 645 user_key_allowed2(struct passwd *pw, struct sshkey *key, char *file) 646 { 647 FILE *f; 648 int found_key = 0; 649 650 /* Temporarily use the user's uid. */ 651 temporarily_use_uid(pw); 652 653 debug("trying public key file %s", file); 654 if ((f = auth_openkeyfile(file, pw, options.strict_modes)) != NULL) { 655 found_key = check_authkeys_file(f, file, key, pw); 656 fclose(f); 657 } 658 659 restore_uid(); 660 return found_key; 661 } 662 663 /* 664 * Checks whether key is allowed in output of command. 665 * returns 1 if the key is allowed or 0 otherwise. 666 */ 667 static int 668 user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key) 669 { 670 FILE *f = NULL; 671 int r, ok, found_key = 0; 672 struct passwd *pw; 673 int i, uid_swapped = 0, ac = 0; 674 pid_t pid; 675 char *username = NULL, *key_fp = NULL, *keytext = NULL; 676 char *tmp, *command = NULL, **av = NULL; 677 void (*osigchld)(int); 678 679 if (options.authorized_keys_command == NULL) 680 return 0; 681 if (options.authorized_keys_command_user == NULL) { 682 error("No user for AuthorizedKeysCommand specified, skipping"); 683 return 0; 684 } 685 686 /* 687 * NB. all returns later this function should go via "out" to 688 * ensure the original SIGCHLD handler is restored properly. 689 */ 690 osigchld = signal(SIGCHLD, SIG_DFL); 691 692 /* Prepare and verify the user for the command */ 693 username = percent_expand(options.authorized_keys_command_user, 694 "u", user_pw->pw_name, (char *)NULL); 695 pw = getpwnam(username); 696 if (pw == NULL) { 697 error("AuthorizedKeysCommandUser \"%s\" not found: %s", 698 username, strerror(errno)); 699 goto out; 700 } 701 702 /* Prepare AuthorizedKeysCommand */ 703 if ((key_fp = sshkey_fingerprint(key, options.fingerprint_hash, 704 SSH_FP_DEFAULT)) == NULL) { 705 error("%s: sshkey_fingerprint failed", __func__); 706 goto out; 707 } 708 if ((r = sshkey_to_base64(key, &keytext)) != 0) { 709 error("%s: sshkey_to_base64 failed: %s", __func__, ssh_err(r)); 710 goto out; 711 } 712 713 /* Turn the command into an argument vector */ 714 if (argv_split(options.authorized_keys_command, &ac, &av) != 0) { 715 error("AuthorizedKeysCommand \"%s\" contains invalid quotes", 716 command); 717 goto out; 718 } 719 if (ac == 0) { 720 error("AuthorizedKeysCommand \"%s\" yielded no arguments", 721 command); 722 goto out; 723 } 724 for (i = 1; i < ac; i++) { 725 tmp = percent_expand(av[i], 726 "u", user_pw->pw_name, 727 "h", user_pw->pw_dir, 728 "t", sshkey_ssh_name(key), 729 "f", key_fp, 730 "k", keytext, 731 (char *)NULL); 732 if (tmp == NULL) 733 fatal("%s: percent_expand failed", __func__); 734 free(av[i]); 735 av[i] = tmp; 736 } 737 /* Prepare a printable command for logs, etc. */ 738 command = argv_assemble(ac, av); 739 740 /* 741 * If AuthorizedKeysCommand was run without arguments 742 * then fall back to the old behaviour of passing the 743 * target username as a single argument. 744 */ 745 if (ac == 1) { 746 av = xreallocarray(av, ac + 2, sizeof(*av)); 747 av[1] = xstrdup(user_pw->pw_name); 748 av[2] = NULL; 749 /* Fix up command too, since it is used in log messages */ 750 free(command); 751 xasprintf(&command, "%s %s", av[0], av[1]); 752 } 753 754 if ((pid = subprocess("AuthorizedKeysCommand", pw, command, 755 ac, av, &f, 756 SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0) 757 goto out; 758 759 uid_swapped = 1; 760 temporarily_use_uid(pw); 761 762 ok = check_authkeys_file(f, options.authorized_keys_command, key, pw); 763 764 fclose(f); 765 f = NULL; 766 767 if (exited_cleanly(pid, "AuthorizedKeysCommand", command, 0) != 0) 768 goto out; 769 770 /* Read completed successfully */ 771 found_key = ok; 772 out: 773 if (f != NULL) 774 fclose(f); 775 signal(SIGCHLD, osigchld); 776 for (i = 0; i < ac; i++) 777 free(av[i]); 778 free(av); 779 if (uid_swapped) 780 restore_uid(); 781 free(command); 782 free(username); 783 free(key_fp); 784 free(keytext); 785 return found_key; 786 } 787 788 /* 789 * Check whether key authenticates and authorises the user. 790 */ 791 int 792 user_key_allowed(struct passwd *pw, struct sshkey *key, int auth_attempt) 793 { 794 u_int success, i; 795 char *file; 796 797 if (auth_key_is_revoked(key)) 798 return 0; 799 if (sshkey_is_cert(key) && 800 auth_key_is_revoked(key->cert->signature_key)) 801 return 0; 802 803 success = user_cert_trusted_ca(pw, key); 804 if (success) 805 return success; 806 807 success = user_key_command_allowed2(pw, key); 808 if (success > 0) 809 return success; 810 811 for (i = 0; !success && i < options.num_authkeys_files; i++) { 812 813 if (strcasecmp(options.authorized_keys_files[i], "none") == 0) 814 continue; 815 file = expand_authorized_keys( 816 options.authorized_keys_files[i], pw); 817 818 success = user_key_allowed2(pw, key, file); 819 free(file); 820 } 821 822 return success; 823 } 824 825 Authmethod method_pubkey = { 826 "publickey", 827 userauth_pubkey, 828 &options.pubkey_authentication 829 }; 830