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