1 /* $OpenBSD: auth2-pubkey.c,v 1.84 2018/08/23 03:01:08 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 28 #include <sys/types.h> 29 #include <sys/stat.h> 30 31 #include <errno.h> 32 #include <fcntl.h> 33 #ifdef HAVE_PATHS_H 34 # include <paths.h> 35 #endif 36 #include <pwd.h> 37 #include <signal.h> 38 #include <stdio.h> 39 #include <stdarg.h> 40 #include <string.h> 41 #include <time.h> 42 #include <unistd.h> 43 #include <limits.h> 44 45 #include "xmalloc.h" 46 #include "ssh.h" 47 #include "ssh2.h" 48 #include "packet.h" 49 #include "sshbuf.h" 50 #include "log.h" 51 #include "misc.h" 52 #include "servconf.h" 53 #include "compat.h" 54 #include "sshkey.h" 55 #include "hostfile.h" 56 #include "auth.h" 57 #include "pathnames.h" 58 #include "uidswap.h" 59 #include "auth-options.h" 60 #include "canohost.h" 61 #ifdef GSSAPI 62 #include "ssh-gss.h" 63 #endif 64 #include "monitor_wrap.h" 65 #include "authfile.h" 66 #include "match.h" 67 #include "ssherr.h" 68 #include "channels.h" /* XXX for session.h */ 69 #include "session.h" /* XXX for child_set_env(); refactor? */ 70 71 /* import */ 72 extern ServerOptions options; 73 extern u_char *session_id2; 74 extern u_int session_id2_len; 75 76 static char * 77 format_key(const struct sshkey *key) 78 { 79 char *ret, *fp = sshkey_fingerprint(key, 80 options.fingerprint_hash, SSH_FP_DEFAULT); 81 82 xasprintf(&ret, "%s %s", sshkey_type(key), fp); 83 free(fp); 84 return ret; 85 } 86 87 static int 88 userauth_pubkey(struct ssh *ssh) 89 { 90 Authctxt *authctxt = ssh->authctxt; 91 struct passwd *pw = authctxt->pw; 92 struct sshbuf *b = NULL; 93 struct sshkey *key = NULL; 94 char *pkalg = NULL, *userstyle = NULL, *key_s = NULL, *ca_s = NULL; 95 u_char *pkblob = NULL, *sig = NULL, have_sig; 96 size_t blen, slen; 97 int r, pktype; 98 int authenticated = 0; 99 struct sshauthopt *authopts = NULL; 100 101 if ((r = sshpkt_get_u8(ssh, &have_sig)) != 0 || 102 (r = sshpkt_get_cstring(ssh, &pkalg, NULL)) != 0 || 103 (r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0) 104 fatal("%s: parse request failed: %s", __func__, ssh_err(r)); 105 pktype = sshkey_type_from_name(pkalg); 106 if (pktype == KEY_UNSPEC) { 107 /* this is perfectly legal */ 108 verbose("%s: unsupported public key algorithm: %s", 109 __func__, pkalg); 110 goto done; 111 } 112 if ((r = sshkey_from_blob(pkblob, blen, &key)) != 0) { 113 error("%s: could not parse key: %s", __func__, ssh_err(r)); 114 goto done; 115 } 116 if (key == NULL) { 117 error("%s: cannot decode key: %s", __func__, pkalg); 118 goto done; 119 } 120 if (key->type != pktype) { 121 error("%s: type mismatch for decoded key " 122 "(received %d, expected %d)", __func__, key->type, pktype); 123 goto done; 124 } 125 if (sshkey_type_plain(key->type) == KEY_RSA && 126 (ssh->compat & SSH_BUG_RSASIGMD5) != 0) { 127 logit("Refusing RSA key because client uses unsafe " 128 "signature scheme"); 129 goto done; 130 } 131 if (auth2_key_already_used(authctxt, key)) { 132 logit("refusing previously-used %s key", sshkey_type(key)); 133 goto done; 134 } 135 if (match_pattern_list(pkalg, options.pubkey_key_types, 0) != 1) { 136 logit("%s: key type %s not in PubkeyAcceptedKeyTypes", 137 __func__, sshkey_ssh_name(key)); 138 goto done; 139 } 140 141 key_s = format_key(key); 142 if (sshkey_is_cert(key)) 143 ca_s = format_key(key->cert->signature_key); 144 145 if (have_sig) { 146 debug3("%s: have %s signature for %s%s%s", 147 __func__, pkalg, key_s, 148 ca_s == NULL ? "" : " CA ", 149 ca_s == NULL ? "" : ca_s); 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 if (!authctxt->valid || authctxt->user == NULL) { 167 debug2("%s: disabled because of invalid user", 168 __func__); 169 goto done; 170 } 171 /* reconstruct packet */ 172 xasprintf(&userstyle, "%s%s%s", authctxt->user, 173 authctxt->style ? ":" : "", 174 authctxt->style ? authctxt->style : ""); 175 if ((r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 || 176 (r = sshbuf_put_cstring(b, userstyle)) != 0 || 177 (r = sshbuf_put_cstring(b, authctxt->service)) != 0 || 178 (r = sshbuf_put_cstring(b, "publickey")) != 0 || 179 (r = sshbuf_put_u8(b, have_sig)) != 0 || 180 (r = sshbuf_put_cstring(b, pkalg) != 0) || 181 (r = sshbuf_put_string(b, pkblob, blen)) != 0) 182 fatal("%s: build packet failed: %s", 183 __func__, ssh_err(r)); 184 #ifdef DEBUG_PK 185 sshbuf_dump(b, stderr); 186 #endif 187 /* test for correct signature */ 188 authenticated = 0; 189 if (PRIVSEP(user_key_allowed(ssh, pw, key, 1, &authopts)) && 190 PRIVSEP(sshkey_verify(key, sig, slen, 191 sshbuf_ptr(b), sshbuf_len(b), 192 (ssh->compat & SSH_BUG_SIGTYPE) == 0 ? pkalg : NULL, 193 ssh->compat)) == 0) { 194 authenticated = 1; 195 } 196 auth2_record_key(authctxt, authenticated, key); 197 } else { 198 debug("%s: test pkalg %s pkblob %s%s%s", 199 __func__, pkalg, key_s, 200 ca_s == NULL ? "" : " CA ", 201 ca_s == NULL ? "" : ca_s); 202 203 if ((r = sshpkt_get_end(ssh)) != 0) 204 fatal("%s: %s", __func__, ssh_err(r)); 205 206 if (!authctxt->valid || authctxt->user == NULL) { 207 debug2("%s: disabled because of invalid user", 208 __func__); 209 goto done; 210 } 211 /* XXX fake reply and always send PK_OK ? */ 212 /* 213 * XXX this allows testing whether a user is allowed 214 * to login: if you happen to have a valid pubkey this 215 * message is sent. the message is NEVER sent at all 216 * if a user is not allowed to login. is this an 217 * issue? -markus 218 */ 219 if (PRIVSEP(user_key_allowed(ssh, pw, key, 0, NULL))) { 220 if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_PK_OK)) 221 != 0 || 222 (r = sshpkt_put_cstring(ssh, pkalg)) != 0 || 223 (r = sshpkt_put_string(ssh, pkblob, blen)) != 0 || 224 (r = sshpkt_send(ssh)) != 0 || 225 (r = ssh_packet_write_wait(ssh)) != 0) 226 fatal("%s: %s", __func__, ssh_err(r)); 227 authctxt->postponed = 1; 228 } 229 } 230 done: 231 if (authenticated == 1 && auth_activate_options(ssh, authopts) != 0) { 232 debug("%s: key options inconsistent with existing", __func__); 233 authenticated = 0; 234 } 235 debug2("%s: authenticated %d pkalg %s", __func__, authenticated, pkalg); 236 237 sshbuf_free(b); 238 sshauthopt_free(authopts); 239 sshkey_free(key); 240 free(userstyle); 241 free(pkalg); 242 free(pkblob); 243 free(key_s); 244 free(ca_s); 245 free(sig); 246 return authenticated; 247 } 248 249 static int 250 match_principals_option(const char *principal_list, struct sshkey_cert *cert) 251 { 252 char *result; 253 u_int i; 254 255 /* XXX percent_expand() sequences for authorized_principals? */ 256 257 for (i = 0; i < cert->nprincipals; i++) { 258 if ((result = match_list(cert->principals[i], 259 principal_list, NULL)) != NULL) { 260 debug3("matched principal from key options \"%.100s\"", 261 result); 262 free(result); 263 return 1; 264 } 265 } 266 return 0; 267 } 268 269 /* 270 * Process a single authorized_principals format line. Returns 0 and sets 271 * authoptsp is principal is authorised, -1 otherwise. "loc" is used as a 272 * log preamble for file/line information. 273 */ 274 static int 275 check_principals_line(struct ssh *ssh, char *cp, const struct sshkey_cert *cert, 276 const char *loc, struct sshauthopt **authoptsp) 277 { 278 u_int i, found = 0; 279 char *ep, *line_opts; 280 const char *reason = NULL; 281 struct sshauthopt *opts = NULL; 282 283 if (authoptsp != NULL) 284 *authoptsp = NULL; 285 286 /* Trim trailing whitespace. */ 287 ep = cp + strlen(cp) - 1; 288 while (ep > cp && (*ep == '\n' || *ep == ' ' || *ep == '\t')) 289 *ep-- = '\0'; 290 291 /* 292 * If the line has internal whitespace then assume it has 293 * key options. 294 */ 295 line_opts = NULL; 296 if ((ep = strrchr(cp, ' ')) != NULL || 297 (ep = strrchr(cp, '\t')) != NULL) { 298 for (; *ep == ' ' || *ep == '\t'; ep++) 299 ; 300 line_opts = cp; 301 cp = ep; 302 } 303 if ((opts = sshauthopt_parse(line_opts, &reason)) == NULL) { 304 debug("%s: bad principals options: %s", loc, reason); 305 auth_debug_add("%s: bad principals options: %s", loc, reason); 306 return -1; 307 } 308 /* Check principals in cert against those on line */ 309 for (i = 0; i < cert->nprincipals; i++) { 310 if (strcmp(cp, cert->principals[i]) != 0) 311 continue; 312 debug3("%s: matched principal \"%.100s\"", 313 loc, cert->principals[i]); 314 found = 1; 315 } 316 if (found && authoptsp != NULL) { 317 *authoptsp = opts; 318 opts = NULL; 319 } 320 sshauthopt_free(opts); 321 return found ? 0 : -1; 322 } 323 324 static int 325 process_principals(struct ssh *ssh, FILE *f, const char *file, 326 const struct sshkey_cert *cert, struct sshauthopt **authoptsp) 327 { 328 char loc[256], *line = NULL, *cp, *ep; 329 size_t linesize = 0; 330 u_long linenum = 0; 331 u_int found_principal = 0; 332 333 if (authoptsp != NULL) 334 *authoptsp = NULL; 335 336 while (getline(&line, &linesize, f) != -1) { 337 linenum++; 338 /* Always consume entire input */ 339 if (found_principal) 340 continue; 341 342 /* Skip leading whitespace. */ 343 for (cp = line; *cp == ' ' || *cp == '\t'; cp++) 344 ; 345 /* Skip blank and comment lines. */ 346 if ((ep = strchr(cp, '#')) != NULL) 347 *ep = '\0'; 348 if (!*cp || *cp == '\n') 349 continue; 350 351 snprintf(loc, sizeof(loc), "%.200s:%lu", file, linenum); 352 if (check_principals_line(ssh, cp, cert, loc, authoptsp) == 0) 353 found_principal = 1; 354 } 355 free(line); 356 return found_principal; 357 } 358 359 /* XXX remove pw args here and elsewhere once ssh->authctxt is guaranteed */ 360 361 static int 362 match_principals_file(struct ssh *ssh, struct passwd *pw, char *file, 363 struct sshkey_cert *cert, struct sshauthopt **authoptsp) 364 { 365 FILE *f; 366 int success; 367 368 if (authoptsp != NULL) 369 *authoptsp = NULL; 370 371 temporarily_use_uid(pw); 372 debug("trying authorized principals file %s", file); 373 if ((f = auth_openprincipals(file, pw, options.strict_modes)) == NULL) { 374 restore_uid(); 375 return 0; 376 } 377 success = process_principals(ssh, f, file, cert, authoptsp); 378 fclose(f); 379 restore_uid(); 380 return success; 381 } 382 383 /* 384 * Checks whether principal is allowed in output of command. 385 * returns 1 if the principal is allowed or 0 otherwise. 386 */ 387 static int 388 match_principals_command(struct ssh *ssh, struct passwd *user_pw, 389 const struct sshkey *key, struct sshauthopt **authoptsp) 390 { 391 struct passwd *runas_pw = NULL; 392 const struct sshkey_cert *cert = key->cert; 393 FILE *f = NULL; 394 int r, ok, found_principal = 0; 395 int i, ac = 0, uid_swapped = 0; 396 pid_t pid; 397 char *tmp, *username = NULL, *command = NULL, **av = NULL; 398 char *ca_fp = NULL, *key_fp = NULL, *catext = NULL, *keytext = NULL; 399 char serial_s[16], uidstr[32]; 400 void (*osigchld)(int); 401 402 if (authoptsp != NULL) 403 *authoptsp = NULL; 404 if (options.authorized_principals_command == NULL) 405 return 0; 406 if (options.authorized_principals_command_user == NULL) { 407 error("No user for AuthorizedPrincipalsCommand specified, " 408 "skipping"); 409 return 0; 410 } 411 412 /* 413 * NB. all returns later this function should go via "out" to 414 * ensure the original SIGCHLD handler is restored properly. 415 */ 416 osigchld = signal(SIGCHLD, SIG_DFL); 417 418 /* Prepare and verify the user for the command */ 419 username = percent_expand(options.authorized_principals_command_user, 420 "u", user_pw->pw_name, (char *)NULL); 421 runas_pw = getpwnam(username); 422 if (runas_pw == NULL) { 423 error("AuthorizedPrincipalsCommandUser \"%s\" not found: %s", 424 username, strerror(errno)); 425 goto out; 426 } 427 428 /* Turn the command into an argument vector */ 429 if (argv_split(options.authorized_principals_command, &ac, &av) != 0) { 430 error("AuthorizedPrincipalsCommand \"%s\" contains " 431 "invalid quotes", command); 432 goto out; 433 } 434 if (ac == 0) { 435 error("AuthorizedPrincipalsCommand \"%s\" yielded no arguments", 436 command); 437 goto out; 438 } 439 if ((ca_fp = sshkey_fingerprint(cert->signature_key, 440 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) { 441 error("%s: sshkey_fingerprint failed", __func__); 442 goto out; 443 } 444 if ((key_fp = sshkey_fingerprint(key, 445 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) { 446 error("%s: sshkey_fingerprint failed", __func__); 447 goto out; 448 } 449 if ((r = sshkey_to_base64(cert->signature_key, &catext)) != 0) { 450 error("%s: sshkey_to_base64 failed: %s", __func__, ssh_err(r)); 451 goto out; 452 } 453 if ((r = sshkey_to_base64(key, &keytext)) != 0) { 454 error("%s: sshkey_to_base64 failed: %s", __func__, ssh_err(r)); 455 goto out; 456 } 457 snprintf(serial_s, sizeof(serial_s), "%llu", 458 (unsigned long long)cert->serial); 459 snprintf(uidstr, sizeof(uidstr), "%llu", 460 (unsigned long long)user_pw->pw_uid); 461 for (i = 1; i < ac; i++) { 462 tmp = percent_expand(av[i], 463 "U", uidstr, 464 "u", user_pw->pw_name, 465 "h", user_pw->pw_dir, 466 "t", sshkey_ssh_name(key), 467 "T", sshkey_ssh_name(cert->signature_key), 468 "f", key_fp, 469 "F", ca_fp, 470 "k", keytext, 471 "K", catext, 472 "i", cert->key_id, 473 "s", serial_s, 474 (char *)NULL); 475 if (tmp == NULL) 476 fatal("%s: percent_expand failed", __func__); 477 free(av[i]); 478 av[i] = tmp; 479 } 480 /* Prepare a printable command for logs, etc. */ 481 command = argv_assemble(ac, av); 482 483 if ((pid = subprocess("AuthorizedPrincipalsCommand", runas_pw, command, 484 ac, av, &f, 485 SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0) 486 goto out; 487 488 uid_swapped = 1; 489 temporarily_use_uid(runas_pw); 490 491 ok = process_principals(ssh, f, "(command)", cert, authoptsp); 492 493 fclose(f); 494 f = NULL; 495 496 if (exited_cleanly(pid, "AuthorizedPrincipalsCommand", command, 0) != 0) 497 goto out; 498 499 /* Read completed successfully */ 500 found_principal = ok; 501 out: 502 if (f != NULL) 503 fclose(f); 504 signal(SIGCHLD, osigchld); 505 for (i = 0; i < ac; i++) 506 free(av[i]); 507 free(av); 508 if (uid_swapped) 509 restore_uid(); 510 free(command); 511 free(username); 512 free(ca_fp); 513 free(key_fp); 514 free(catext); 515 free(keytext); 516 return found_principal; 517 } 518 519 static void 520 skip_space(char **cpp) 521 { 522 char *cp; 523 524 for (cp = *cpp; *cp == ' ' || *cp == '\t'; cp++) 525 ; 526 *cpp = cp; 527 } 528 529 /* 530 * Advanced *cpp past the end of key options, defined as the first unquoted 531 * whitespace character. Returns 0 on success or -1 on failure (e.g. 532 * unterminated quotes). 533 */ 534 static int 535 advance_past_options(char **cpp) 536 { 537 char *cp = *cpp; 538 int quoted = 0; 539 540 for (; *cp && (quoted || (*cp != ' ' && *cp != '\t')); cp++) { 541 if (*cp == '\\' && cp[1] == '"') 542 cp++; /* Skip both */ 543 else if (*cp == '"') 544 quoted = !quoted; 545 } 546 *cpp = cp; 547 /* return failure for unterminated quotes */ 548 return (*cp == '\0' && quoted) ? -1 : 0; 549 } 550 551 /* 552 * Check a single line of an authorized_keys-format file. Returns 0 if key 553 * matches, -1 otherwise. Will return key/cert options via *authoptsp 554 * on success. "loc" is used as file/line location in log messages. 555 */ 556 static int 557 check_authkey_line(struct ssh *ssh, struct passwd *pw, struct sshkey *key, 558 char *cp, const char *loc, struct sshauthopt **authoptsp) 559 { 560 int want_keytype = sshkey_is_cert(key) ? KEY_UNSPEC : key->type; 561 struct sshkey *found = NULL; 562 struct sshauthopt *keyopts = NULL, *certopts = NULL, *finalopts = NULL; 563 char *key_options = NULL, *fp = NULL; 564 const char *reason = NULL; 565 int ret = -1; 566 567 if (authoptsp != NULL) 568 *authoptsp = NULL; 569 570 if ((found = sshkey_new(want_keytype)) == NULL) { 571 debug3("%s: keytype %d failed", __func__, want_keytype); 572 goto out; 573 } 574 575 /* XXX djm: peek at key type in line and skip if unwanted */ 576 577 if (sshkey_read(found, &cp) != 0) { 578 /* no key? check for options */ 579 debug2("%s: check options: '%s'", loc, cp); 580 key_options = cp; 581 if (advance_past_options(&cp) != 0) { 582 reason = "invalid key option string"; 583 goto fail_reason; 584 } 585 skip_space(&cp); 586 if (sshkey_read(found, &cp) != 0) { 587 /* still no key? advance to next line*/ 588 debug2("%s: advance: '%s'", loc, cp); 589 goto out; 590 } 591 } 592 /* Parse key options now; we need to know if this is a CA key */ 593 if ((keyopts = sshauthopt_parse(key_options, &reason)) == NULL) { 594 debug("%s: bad key options: %s", loc, reason); 595 auth_debug_add("%s: bad key options: %s", loc, reason); 596 goto out; 597 } 598 /* Ignore keys that don't match or incorrectly marked as CAs */ 599 if (sshkey_is_cert(key)) { 600 /* Certificate; check signature key against CA */ 601 if (!sshkey_equal(found, key->cert->signature_key) || 602 !keyopts->cert_authority) 603 goto out; 604 } else { 605 /* Plain key: check it against key found in file */ 606 if (!sshkey_equal(found, key) || keyopts->cert_authority) 607 goto out; 608 } 609 610 /* We have a candidate key, perform authorisation checks */ 611 if ((fp = sshkey_fingerprint(found, 612 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) 613 fatal("%s: fingerprint failed", __func__); 614 615 debug("%s: matching %s found: %s %s", loc, 616 sshkey_is_cert(key) ? "CA" : "key", sshkey_type(found), fp); 617 618 if (auth_authorise_keyopts(ssh, pw, keyopts, 619 sshkey_is_cert(key), loc) != 0) { 620 reason = "Refused by key options"; 621 goto fail_reason; 622 } 623 /* That's all we need for plain keys. */ 624 if (!sshkey_is_cert(key)) { 625 verbose("Accepted key %s %s found at %s", 626 sshkey_type(found), fp, loc); 627 finalopts = keyopts; 628 keyopts = NULL; 629 goto success; 630 } 631 632 /* 633 * Additional authorisation for certificates. 634 */ 635 636 /* Parse and check options present in certificate */ 637 if ((certopts = sshauthopt_from_cert(key)) == NULL) { 638 reason = "Invalid certificate options"; 639 goto fail_reason; 640 } 641 if (auth_authorise_keyopts(ssh, pw, certopts, 0, loc) != 0) { 642 reason = "Refused by certificate options"; 643 goto fail_reason; 644 } 645 if ((finalopts = sshauthopt_merge(keyopts, certopts, &reason)) == NULL) 646 goto fail_reason; 647 648 /* 649 * If the user has specified a list of principals as 650 * a key option, then prefer that list to matching 651 * their username in the certificate principals list. 652 */ 653 if (keyopts->cert_principals != NULL && 654 !match_principals_option(keyopts->cert_principals, key->cert)) { 655 reason = "Certificate does not contain an authorized principal"; 656 goto fail_reason; 657 } 658 if (sshkey_cert_check_authority(key, 0, 0, 659 keyopts->cert_principals == NULL ? pw->pw_name : NULL, &reason) != 0) 660 goto fail_reason; 661 662 verbose("Accepted certificate ID \"%s\" (serial %llu) " 663 "signed by CA %s %s found at %s", 664 key->cert->key_id, 665 (unsigned long long)key->cert->serial, 666 sshkey_type(found), fp, loc); 667 668 success: 669 if (finalopts == NULL) 670 fatal("%s: internal error: missing options", __func__); 671 if (authoptsp != NULL) { 672 *authoptsp = finalopts; 673 finalopts = NULL; 674 } 675 /* success */ 676 ret = 0; 677 goto out; 678 679 fail_reason: 680 error("%s", reason); 681 auth_debug_add("%s", reason); 682 out: 683 free(fp); 684 sshauthopt_free(keyopts); 685 sshauthopt_free(certopts); 686 sshauthopt_free(finalopts); 687 sshkey_free(found); 688 return ret; 689 } 690 691 /* 692 * Checks whether key is allowed in authorized_keys-format file, 693 * returns 1 if the key is allowed or 0 otherwise. 694 */ 695 static int 696 check_authkeys_file(struct ssh *ssh, struct passwd *pw, FILE *f, 697 char *file, struct sshkey *key, struct sshauthopt **authoptsp) 698 { 699 char *cp, *line = NULL, loc[256]; 700 size_t linesize = 0; 701 int found_key = 0; 702 u_long linenum = 0; 703 704 if (authoptsp != NULL) 705 *authoptsp = NULL; 706 707 while (getline(&line, &linesize, f) != -1) { 708 linenum++; 709 /* Always consume entire file */ 710 if (found_key) 711 continue; 712 713 /* Skip leading whitespace, empty and comment lines. */ 714 cp = line; 715 skip_space(&cp); 716 if (!*cp || *cp == '\n' || *cp == '#') 717 continue; 718 snprintf(loc, sizeof(loc), "%.200s:%lu", file, linenum); 719 if (check_authkey_line(ssh, pw, key, cp, loc, authoptsp) == 0) 720 found_key = 1; 721 } 722 free(line); 723 return found_key; 724 } 725 726 /* Authenticate a certificate key against TrustedUserCAKeys */ 727 static int 728 user_cert_trusted_ca(struct ssh *ssh, struct passwd *pw, struct sshkey *key, 729 struct sshauthopt **authoptsp) 730 { 731 char *ca_fp, *principals_file = NULL; 732 const char *reason; 733 struct sshauthopt *principals_opts = NULL, *cert_opts = NULL; 734 struct sshauthopt *final_opts = NULL; 735 int r, ret = 0, found_principal = 0, use_authorized_principals; 736 737 if (authoptsp != NULL) 738 *authoptsp = NULL; 739 740 if (!sshkey_is_cert(key) || options.trusted_user_ca_keys == NULL) 741 return 0; 742 743 if ((ca_fp = sshkey_fingerprint(key->cert->signature_key, 744 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) 745 return 0; 746 747 if ((r = sshkey_in_file(key->cert->signature_key, 748 options.trusted_user_ca_keys, 1, 0)) != 0) { 749 debug2("%s: CA %s %s is not listed in %s: %s", __func__, 750 sshkey_type(key->cert->signature_key), ca_fp, 751 options.trusted_user_ca_keys, ssh_err(r)); 752 goto out; 753 } 754 /* 755 * If AuthorizedPrincipals is in use, then compare the certificate 756 * principals against the names in that file rather than matching 757 * against the username. 758 */ 759 if ((principals_file = authorized_principals_file(pw)) != NULL) { 760 if (match_principals_file(ssh, pw, principals_file, 761 key->cert, &principals_opts)) 762 found_principal = 1; 763 } 764 /* Try querying command if specified */ 765 if (!found_principal && match_principals_command(ssh, pw, key, 766 &principals_opts)) 767 found_principal = 1; 768 /* If principals file or command is specified, then require a match */ 769 use_authorized_principals = principals_file != NULL || 770 options.authorized_principals_command != NULL; 771 if (!found_principal && use_authorized_principals) { 772 reason = "Certificate does not contain an authorized principal"; 773 goto fail_reason; 774 } 775 if (use_authorized_principals && principals_opts == NULL) 776 fatal("%s: internal error: missing principals_opts", __func__); 777 if (sshkey_cert_check_authority(key, 0, 1, 778 use_authorized_principals ? NULL : pw->pw_name, &reason) != 0) 779 goto fail_reason; 780 781 /* Check authority from options in key and from principals file/cmd */ 782 if ((cert_opts = sshauthopt_from_cert(key)) == NULL) { 783 reason = "Invalid certificate options"; 784 goto fail_reason; 785 } 786 if (auth_authorise_keyopts(ssh, pw, cert_opts, 0, "cert") != 0) { 787 reason = "Refused by certificate options"; 788 goto fail_reason; 789 } 790 if (principals_opts == NULL) { 791 final_opts = cert_opts; 792 cert_opts = NULL; 793 } else { 794 if (auth_authorise_keyopts(ssh, pw, principals_opts, 0, 795 "principals") != 0) { 796 reason = "Refused by certificate principals options"; 797 goto fail_reason; 798 } 799 if ((final_opts = sshauthopt_merge(principals_opts, 800 cert_opts, &reason)) == NULL) { 801 fail_reason: 802 error("%s", reason); 803 auth_debug_add("%s", reason); 804 goto out; 805 } 806 } 807 808 /* Success */ 809 verbose("Accepted certificate ID \"%s\" (serial %llu) signed by " 810 "%s CA %s via %s", key->cert->key_id, 811 (unsigned long long)key->cert->serial, 812 sshkey_type(key->cert->signature_key), ca_fp, 813 options.trusted_user_ca_keys); 814 if (authoptsp != NULL) { 815 *authoptsp = final_opts; 816 final_opts = NULL; 817 } 818 ret = 1; 819 out: 820 sshauthopt_free(principals_opts); 821 sshauthopt_free(cert_opts); 822 sshauthopt_free(final_opts); 823 free(principals_file); 824 free(ca_fp); 825 return ret; 826 } 827 828 /* 829 * Checks whether key is allowed in file. 830 * returns 1 if the key is allowed or 0 otherwise. 831 */ 832 static int 833 user_key_allowed2(struct ssh *ssh, struct passwd *pw, struct sshkey *key, 834 char *file, struct sshauthopt **authoptsp) 835 { 836 FILE *f; 837 int found_key = 0; 838 839 if (authoptsp != NULL) 840 *authoptsp = NULL; 841 842 /* Temporarily use the user's uid. */ 843 temporarily_use_uid(pw); 844 845 debug("trying public key file %s", file); 846 if ((f = auth_openkeyfile(file, pw, options.strict_modes)) != NULL) { 847 found_key = check_authkeys_file(ssh, pw, f, file, 848 key, authoptsp); 849 fclose(f); 850 } 851 852 restore_uid(); 853 return found_key; 854 } 855 856 /* 857 * Checks whether key is allowed in output of command. 858 * returns 1 if the key is allowed or 0 otherwise. 859 */ 860 static int 861 user_key_command_allowed2(struct ssh *ssh, struct passwd *user_pw, 862 struct sshkey *key, struct sshauthopt **authoptsp) 863 { 864 struct passwd *runas_pw = NULL; 865 FILE *f = NULL; 866 int r, ok, found_key = 0; 867 int i, uid_swapped = 0, ac = 0; 868 pid_t pid; 869 char *username = NULL, *key_fp = NULL, *keytext = NULL; 870 char uidstr[32], *tmp, *command = NULL, **av = NULL; 871 void (*osigchld)(int); 872 873 if (authoptsp != NULL) 874 *authoptsp = NULL; 875 if (options.authorized_keys_command == NULL) 876 return 0; 877 if (options.authorized_keys_command_user == NULL) { 878 error("No user for AuthorizedKeysCommand specified, skipping"); 879 return 0; 880 } 881 882 /* 883 * NB. all returns later this function should go via "out" to 884 * ensure the original SIGCHLD handler is restored properly. 885 */ 886 osigchld = signal(SIGCHLD, SIG_DFL); 887 888 /* Prepare and verify the user for the command */ 889 username = percent_expand(options.authorized_keys_command_user, 890 "u", user_pw->pw_name, (char *)NULL); 891 runas_pw = getpwnam(username); 892 if (runas_pw == NULL) { 893 error("AuthorizedKeysCommandUser \"%s\" not found: %s", 894 username, strerror(errno)); 895 goto out; 896 } 897 898 /* Prepare AuthorizedKeysCommand */ 899 if ((key_fp = sshkey_fingerprint(key, options.fingerprint_hash, 900 SSH_FP_DEFAULT)) == NULL) { 901 error("%s: sshkey_fingerprint failed", __func__); 902 goto out; 903 } 904 if ((r = sshkey_to_base64(key, &keytext)) != 0) { 905 error("%s: sshkey_to_base64 failed: %s", __func__, ssh_err(r)); 906 goto out; 907 } 908 909 /* Turn the command into an argument vector */ 910 if (argv_split(options.authorized_keys_command, &ac, &av) != 0) { 911 error("AuthorizedKeysCommand \"%s\" contains invalid quotes", 912 command); 913 goto out; 914 } 915 if (ac == 0) { 916 error("AuthorizedKeysCommand \"%s\" yielded no arguments", 917 command); 918 goto out; 919 } 920 snprintf(uidstr, sizeof(uidstr), "%llu", 921 (unsigned long long)user_pw->pw_uid); 922 for (i = 1; i < ac; i++) { 923 tmp = percent_expand(av[i], 924 "U", uidstr, 925 "u", user_pw->pw_name, 926 "h", user_pw->pw_dir, 927 "t", sshkey_ssh_name(key), 928 "f", key_fp, 929 "k", keytext, 930 (char *)NULL); 931 if (tmp == NULL) 932 fatal("%s: percent_expand failed", __func__); 933 free(av[i]); 934 av[i] = tmp; 935 } 936 /* Prepare a printable command for logs, etc. */ 937 command = argv_assemble(ac, av); 938 939 /* 940 * If AuthorizedKeysCommand was run without arguments 941 * then fall back to the old behaviour of passing the 942 * target username as a single argument. 943 */ 944 if (ac == 1) { 945 av = xreallocarray(av, ac + 2, sizeof(*av)); 946 av[1] = xstrdup(user_pw->pw_name); 947 av[2] = NULL; 948 /* Fix up command too, since it is used in log messages */ 949 free(command); 950 xasprintf(&command, "%s %s", av[0], av[1]); 951 } 952 953 if ((pid = subprocess("AuthorizedKeysCommand", runas_pw, command, 954 ac, av, &f, 955 SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD)) == 0) 956 goto out; 957 958 uid_swapped = 1; 959 temporarily_use_uid(runas_pw); 960 961 ok = check_authkeys_file(ssh, user_pw, f, 962 options.authorized_keys_command, key, authoptsp); 963 964 fclose(f); 965 f = NULL; 966 967 if (exited_cleanly(pid, "AuthorizedKeysCommand", command, 0) != 0) 968 goto out; 969 970 /* Read completed successfully */ 971 found_key = ok; 972 out: 973 if (f != NULL) 974 fclose(f); 975 signal(SIGCHLD, osigchld); 976 for (i = 0; i < ac; i++) 977 free(av[i]); 978 free(av); 979 if (uid_swapped) 980 restore_uid(); 981 free(command); 982 free(username); 983 free(key_fp); 984 free(keytext); 985 return found_key; 986 } 987 988 /* 989 * Check whether key authenticates and authorises the user. 990 */ 991 int 992 user_key_allowed(struct ssh *ssh, struct passwd *pw, struct sshkey *key, 993 int auth_attempt, struct sshauthopt **authoptsp) 994 { 995 u_int success, i; 996 char *file; 997 struct sshauthopt *opts = NULL; 998 if (authoptsp != NULL) 999 *authoptsp = NULL; 1000 1001 if (auth_key_is_revoked(key)) 1002 return 0; 1003 if (sshkey_is_cert(key) && 1004 auth_key_is_revoked(key->cert->signature_key)) 1005 return 0; 1006 1007 if ((success = user_cert_trusted_ca(ssh, pw, key, &opts)) != 0) 1008 goto out; 1009 sshauthopt_free(opts); 1010 opts = NULL; 1011 1012 if ((success = user_key_command_allowed2(ssh, pw, key, &opts)) != 0) 1013 goto out; 1014 sshauthopt_free(opts); 1015 opts = NULL; 1016 1017 for (i = 0; !success && i < options.num_authkeys_files; i++) { 1018 if (strcasecmp(options.authorized_keys_files[i], "none") == 0) 1019 continue; 1020 file = expand_authorized_keys( 1021 options.authorized_keys_files[i], pw); 1022 success = user_key_allowed2(ssh, pw, key, file, &opts); 1023 free(file); 1024 } 1025 1026 out: 1027 if (success && authoptsp != NULL) { 1028 *authoptsp = opts; 1029 opts = NULL; 1030 } 1031 sshauthopt_free(opts); 1032 return success; 1033 } 1034 1035 Authmethod method_pubkey = { 1036 "publickey", 1037 userauth_pubkey, 1038 &options.pubkey_authentication 1039 }; 1040