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