auth2-pubkey.c revision 1.33
1/* $NetBSD: auth2-pubkey.c,v 1.33 2023/07/26 17:58:15 christos Exp $ */ 2/* $OpenBSD: auth2-pubkey.c,v 1.118 2023/02/17 04:22:50 dtucker Exp $ */ 3/* 4 * Copyright (c) 2000 Markus Friedl. All rights reserved. 5 * Copyright (c) 2010 Damien Miller. All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28#include "includes.h" 29__RCSID("$NetBSD: auth2-pubkey.c,v 1.33 2023/07/26 17:58:15 christos Exp $"); 30#include <sys/types.h> 31 32#include <stdlib.h> 33#include <errno.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 "kex.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 "digest.h" 68 69#ifdef WITH_LDAP_PUBKEY 70#include "ldapauth.h" 71#endif 72 73#include "ssherr.h" 74#include "channels.h" /* XXX for session.h */ 75#include "session.h" /* XXX for child_set_env(); refactor? */ 76#include "sk-api.h" 77 78/* import */ 79extern ServerOptions options; 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, const char *method) 94{ 95 Authctxt *authctxt = ssh->authctxt; 96 struct passwd *pw = authctxt->pw; 97 struct sshbuf *b = NULL; 98 struct sshkey *key = NULL, *hostkey = 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 hostbound, r, pktype; 103 int req_presence = 0, req_verify = 0, authenticated = 0; 104 struct sshauthopt *authopts = NULL; 105 struct sshkey_sig_details *sig_details = NULL; 106 107 hostbound = strcmp(method, "publickey-hostbound-v00@openssh.com") == 0; 108 109 if ((r = sshpkt_get_u8(ssh, &have_sig)) != 0 || 110 (r = sshpkt_get_cstring(ssh, &pkalg, NULL)) != 0 || 111 (r = sshpkt_get_string(ssh, &pkblob, &blen)) != 0) 112 fatal_fr(r, "parse %s packet", method); 113 114 /* hostbound auth includes the hostkey offered at initial KEX */ 115 if (hostbound) { 116 if ((r = sshpkt_getb_froms(ssh, &b)) != 0 || 117 (r = sshkey_fromb(b, &hostkey)) != 0) 118 fatal_fr(r, "parse %s hostkey", method); 119 if (ssh->kex->initial_hostkey == NULL) 120 fatal_f("internal error: initial hostkey not recorded"); 121 if (!sshkey_equal(hostkey, ssh->kex->initial_hostkey)) 122 fatal_f("%s packet contained wrong host key", method); 123 sshbuf_free(b); 124 b = NULL; 125 } 126 127 if (log_level_get() >= SYSLOG_LEVEL_DEBUG2) { 128 char *keystring; 129 struct sshbuf *pkbuf; 130 131 if ((pkbuf = sshbuf_from(pkblob, blen)) == NULL) 132 fatal_f("sshbuf_from failed"); 133 if ((keystring = sshbuf_dtob64_string(pkbuf, 0)) == NULL) 134 fatal_f("sshbuf_dtob64 failed"); 135 debug2_f("%s user %s %s public key %s %s", 136 authctxt->valid ? "valid" : "invalid", authctxt->user, 137 have_sig ? "attempting" : "querying", pkalg, keystring); 138 sshbuf_free(pkbuf); 139 free(keystring); 140 } 141 142 pktype = sshkey_type_from_name(pkalg); 143 if (pktype == KEY_UNSPEC) { 144 /* this is perfectly legal */ 145 verbose_f("unsupported public key algorithm: %s", pkalg); 146 goto done; 147 } 148 if ((r = sshkey_from_blob(pkblob, blen, &key)) != 0) { 149 error_fr(r, "parse key"); 150 goto done; 151 } 152 if (key == NULL) { 153 error_f("cannot decode key: %s", pkalg); 154 goto done; 155 } 156 if (key->type != pktype) { 157 error_f("type mismatch for decoded key " 158 "(received %d, expected %d)", key->type, pktype); 159 goto done; 160 } 161 if (auth2_key_already_used(authctxt, key)) { 162 logit("refusing previously-used %s key", sshkey_type(key)); 163 goto done; 164 } 165 if (match_pattern_list(pkalg, options.pubkey_accepted_algos, 0) != 1) { 166 logit_f("signature algorithm %s not in " 167 "PubkeyAcceptedAlgorithms", pkalg); 168 goto done; 169 } 170 if ((r = sshkey_check_cert_sigtype(key, 171 options.ca_sign_algorithms)) != 0) { 172 logit_fr(r, "certificate signature algorithm %s", 173 (key->cert == NULL || key->cert->signature_type == NULL) ? 174 "(null)" : key->cert->signature_type); 175 goto done; 176 } 177 if ((r = sshkey_check_rsa_length(key, 178 options.required_rsa_size)) != 0) { 179 logit_r(r, "refusing %s key", sshkey_type(key)); 180 goto done; 181 } 182 key_s = format_key(key); 183 if (sshkey_is_cert(key)) 184 ca_s = format_key(key->cert->signature_key); 185 186 if (have_sig) { 187 debug3_f("%s have %s signature for %s%s%s", 188 method, pkalg, key_s, 189 ca_s == NULL ? "" : " CA ", ca_s == NULL ? "" : ca_s); 190 if ((r = sshpkt_get_string(ssh, &sig, &slen)) != 0 || 191 (r = sshpkt_get_end(ssh)) != 0) 192 fatal_fr(r, "parse signature packet"); 193 if ((b = sshbuf_new()) == NULL) 194 fatal_f("sshbuf_new failed"); 195 if (ssh->compat & SSH_OLD_SESSIONID) { 196 if ((r = sshbuf_putb(b, ssh->kex->session_id)) != 0) 197 fatal_fr(r, "put old session id"); 198 } else { 199 if ((r = sshbuf_put_stringb(b, 200 ssh->kex->session_id)) != 0) 201 fatal_fr(r, "put session id"); 202 } 203 if (!authctxt->valid || authctxt->user == NULL) { 204 debug2_f("disabled because of invalid user"); 205 goto done; 206 } 207 /* reconstruct packet */ 208 xasprintf(&userstyle, "%s%s%s", authctxt->user, 209 authctxt->style ? ":" : "", 210 authctxt->style ? authctxt->style : ""); 211 if ((r = sshbuf_put_u8(b, SSH2_MSG_USERAUTH_REQUEST)) != 0 || 212 (r = sshbuf_put_cstring(b, userstyle)) != 0 || 213 (r = sshbuf_put_cstring(b, authctxt->service)) != 0 || 214 (r = sshbuf_put_cstring(b, method)) != 0 || 215 (r = sshbuf_put_u8(b, have_sig)) != 0 || 216 (r = sshbuf_put_cstring(b, pkalg)) != 0 || 217 (r = sshbuf_put_string(b, pkblob, blen)) != 0) 218 fatal_fr(r, "reconstruct %s packet", method); 219 if (hostbound && 220 (r = sshkey_puts(ssh->kex->initial_hostkey, b)) != 0) 221 fatal_fr(r, "reconstruct %s packet", method); 222#ifdef DEBUG_PK 223 sshbuf_dump(b, stderr); 224#endif 225 /* test for correct signature */ 226 authenticated = 0; 227 if (PRIVSEP(user_key_allowed(ssh, pw, key, 1, &authopts)) && 228 PRIVSEP(sshkey_verify(key, sig, slen, 229 sshbuf_ptr(b), sshbuf_len(b), 230 (ssh->compat & SSH_BUG_SIGTYPE) == 0 ? pkalg : NULL, 231 ssh->compat, &sig_details)) == 0) { 232 authenticated = 1; 233 } 234 if (authenticated == 1 && sig_details != NULL) { 235 auth2_record_info(authctxt, "signature count = %u", 236 sig_details->sk_counter); 237 debug_f("sk_counter = %u, sk_flags = 0x%02x", 238 sig_details->sk_counter, sig_details->sk_flags); 239 req_presence = (options.pubkey_auth_options & 240 PUBKEYAUTH_TOUCH_REQUIRED) || 241 !authopts->no_require_user_presence; 242 if (req_presence && (sig_details->sk_flags & 243 SSH_SK_USER_PRESENCE_REQD) == 0) { 244 error("public key %s signature for %s%s from " 245 "%.128s port %d rejected: user presence " 246 "(authenticator touch) requirement " 247 "not met ", key_s, 248 authctxt->valid ? "" : "invalid user ", 249 authctxt->user, ssh_remote_ipaddr(ssh), 250 ssh_remote_port(ssh)); 251 authenticated = 0; 252 goto done; 253 } 254 req_verify = (options.pubkey_auth_options & 255 PUBKEYAUTH_VERIFY_REQUIRED) || 256 authopts->require_verify; 257 if (req_verify && (sig_details->sk_flags & 258 SSH_SK_USER_VERIFICATION_REQD) == 0) { 259 error("public key %s signature for %s%s from " 260 "%.128s port %d rejected: user " 261 "verification requirement not met ", key_s, 262 authctxt->valid ? "" : "invalid user ", 263 authctxt->user, ssh_remote_ipaddr(ssh), 264 ssh_remote_port(ssh)); 265 authenticated = 0; 266 goto done; 267 } 268 } 269 auth2_record_key(authctxt, authenticated, key); 270 } else { 271 debug_f("%s test pkalg %s pkblob %s%s%s", method, pkalg, key_s, 272 ca_s == NULL ? "" : " CA ", ca_s == NULL ? "" : ca_s); 273 274 if ((r = sshpkt_get_end(ssh)) != 0) 275 fatal_fr(r, "parse packet"); 276 277 if (!authctxt->valid || authctxt->user == NULL) { 278 debug2_f("disabled because of invalid user"); 279 goto done; 280 } 281 /* XXX fake reply and always send PK_OK ? */ 282 /* 283 * XXX this allows testing whether a user is allowed 284 * to login: if you happen to have a valid pubkey this 285 * message is sent. the message is NEVER sent at all 286 * if a user is not allowed to login. is this an 287 * issue? -markus 288 */ 289 if (PRIVSEP(user_key_allowed(ssh, pw, key, 0, NULL))) { 290 if ((r = sshpkt_start(ssh, SSH2_MSG_USERAUTH_PK_OK)) 291 != 0 || 292 (r = sshpkt_put_cstring(ssh, pkalg)) != 0 || 293 (r = sshpkt_put_string(ssh, pkblob, blen)) != 0 || 294 (r = sshpkt_send(ssh)) != 0 || 295 (r = ssh_packet_write_wait(ssh)) < 0) 296 fatal_fr(r, "send packet"); 297 authctxt->postponed = 1; 298 } 299 } 300done: 301 if (authenticated == 1 && auth_activate_options(ssh, authopts) != 0) { 302 debug_f("key options inconsistent with existing"); 303 authenticated = 0; 304 } 305 debug2_f("authenticated %d pkalg %s", authenticated, pkalg); 306 307 sshbuf_free(b); 308 sshauthopt_free(authopts); 309 sshkey_free(key); 310 sshkey_free(hostkey); 311 free(userstyle); 312 free(pkalg); 313 free(pkblob); 314 free(key_s); 315 free(ca_s); 316 free(sig); 317 sshkey_sig_details_free(sig_details); 318 return authenticated; 319} 320 321static int 322match_principals_file(struct passwd *pw, char *file, 323 struct sshkey_cert *cert, struct sshauthopt **authoptsp) 324{ 325 FILE *f; 326 int success; 327 328 if (authoptsp != NULL) 329 *authoptsp = NULL; 330 331 temporarily_use_uid(pw); 332 debug("trying authorized principals file %s", file); 333 if ((f = auth_openprincipals(file, pw, options.strict_modes)) == NULL) { 334 restore_uid(); 335 return 0; 336 } 337 success = auth_process_principals(f, file, cert, authoptsp); 338 fclose(f); 339 restore_uid(); 340 return success; 341} 342 343/* 344 * Checks whether principal is allowed in output of command. 345 * returns 1 if the principal is allowed or 0 otherwise. 346 */ 347static int 348match_principals_command(struct passwd *user_pw, 349 const struct sshkey *key, struct sshauthopt **authoptsp) 350{ 351 struct passwd *runas_pw = NULL; 352 const struct sshkey_cert *cert = key->cert; 353 FILE *f = NULL; 354 int r, ok, found_principal = 0; 355 int i, ac = 0, uid_swapped = 0; 356 pid_t pid; 357 char *tmp, *username = NULL, *command = NULL, **av = NULL; 358 char *ca_fp = NULL, *key_fp = NULL, *catext = NULL, *keytext = NULL; 359 char serial_s[32], uidstr[32]; 360 void (*osigchld)(int); 361 362 if (authoptsp != NULL) 363 *authoptsp = NULL; 364 if (options.authorized_principals_command == NULL) 365 return 0; 366 if (options.authorized_principals_command_user == NULL) { 367 error("No user for AuthorizedPrincipalsCommand specified, " 368 "skipping"); 369 return 0; 370 } 371 372 /* 373 * NB. all returns later this function should go via "out" to 374 * ensure the original SIGCHLD handler is restored properly. 375 */ 376 osigchld = ssh_signal(SIGCHLD, SIG_DFL); 377 378 /* Prepare and verify the user for the command */ 379 username = percent_expand(options.authorized_principals_command_user, 380 "u", user_pw->pw_name, (char *)NULL); 381 runas_pw = getpwnam(username); 382 if (runas_pw == NULL) { 383 error("AuthorizedPrincipalsCommandUser \"%s\" not found: %s", 384 username, strerror(errno)); 385 goto out; 386 } 387 388 /* Turn the command into an argument vector */ 389 if (argv_split(options.authorized_principals_command, 390 &ac, &av, 0) != 0) { 391 error("AuthorizedPrincipalsCommand \"%s\" contains " 392 "invalid quotes", options.authorized_principals_command); 393 goto out; 394 } 395 if (ac == 0) { 396 error("AuthorizedPrincipalsCommand \"%s\" yielded no arguments", 397 options.authorized_principals_command); 398 goto out; 399 } 400 if ((ca_fp = sshkey_fingerprint(cert->signature_key, 401 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) { 402 error_f("sshkey_fingerprint failed"); 403 goto out; 404 } 405 if ((key_fp = sshkey_fingerprint(key, 406 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) { 407 error_f("sshkey_fingerprint failed"); 408 goto out; 409 } 410 if ((r = sshkey_to_base64(cert->signature_key, &catext)) != 0) { 411 error_fr(r, "sshkey_to_base64 failed"); 412 goto out; 413 } 414 if ((r = sshkey_to_base64(key, &keytext)) != 0) { 415 error_fr(r, "sshkey_to_base64 failed"); 416 goto out; 417 } 418 snprintf(serial_s, sizeof(serial_s), "%llu", 419 (unsigned long long)cert->serial); 420 snprintf(uidstr, sizeof(uidstr), "%llu", 421 (unsigned long long)user_pw->pw_uid); 422 for (i = 1; i < ac; i++) { 423 tmp = percent_expand(av[i], 424 "U", uidstr, 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_f("percent_expand failed"); 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", command, 445 ac, av, &f, 446 SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD, 447 runas_pw, temporarily_use_uid, restore_uid)) == 0) 448 goto out; 449 450 uid_swapped = 1; 451 temporarily_use_uid(runas_pw); 452 453 ok = auth_process_principals(f, "(command)", cert, authoptsp); 454 455 fclose(f); 456 f = NULL; 457 458 if (exited_cleanly(pid, "AuthorizedPrincipalsCommand", command, 0) != 0) 459 goto out; 460 461 /* Read completed successfully */ 462 found_principal = ok; 463 out: 464 if (f != NULL) 465 fclose(f); 466 ssh_signal(SIGCHLD, osigchld); 467 for (i = 0; i < ac; i++) 468 free(av[i]); 469 free(av); 470 if (uid_swapped) 471 restore_uid(); 472 free(command); 473 free(username); 474 free(ca_fp); 475 free(key_fp); 476 free(catext); 477 free(keytext); 478 return found_principal; 479} 480 481/* Authenticate a certificate key against TrustedUserCAKeys */ 482static int 483user_cert_trusted_ca(struct passwd *pw, struct sshkey *key, 484 const char *remote_ip, const char *remote_host, 485 struct sshauthopt **authoptsp) 486{ 487 char *ca_fp, *principals_file = NULL; 488 const char *reason; 489 struct sshauthopt *principals_opts = NULL, *cert_opts = NULL; 490 struct sshauthopt *final_opts = NULL; 491 int r, ret = 0, found_principal = 0, use_authorized_principals; 492 493 if (authoptsp != NULL) 494 *authoptsp = NULL; 495 496 if (!sshkey_is_cert(key) || options.trusted_user_ca_keys == NULL) 497 return 0; 498 499 if ((ca_fp = sshkey_fingerprint(key->cert->signature_key, 500 options.fingerprint_hash, SSH_FP_DEFAULT)) == NULL) 501 return 0; 502 503 if ((r = sshkey_in_file(key->cert->signature_key, 504 options.trusted_user_ca_keys, 1, 0)) != 0) { 505 debug2_fr(r, "CA %s %s is not listed in %s", 506 sshkey_type(key->cert->signature_key), ca_fp, 507 options.trusted_user_ca_keys); 508 goto out; 509 } 510 /* 511 * If AuthorizedPrincipals is in use, then compare the certificate 512 * principals against the names in that file rather than matching 513 * against the username. 514 */ 515 if ((principals_file = authorized_principals_file(pw)) != NULL) { 516 if (match_principals_file(pw, principals_file, 517 key->cert, &principals_opts)) 518 found_principal = 1; 519 } 520 /* Try querying command if specified */ 521 if (!found_principal && match_principals_command(pw, key, 522 &principals_opts)) 523 found_principal = 1; 524 /* If principals file or command is specified, then require a match */ 525 use_authorized_principals = principals_file != NULL || 526 options.authorized_principals_command != NULL; 527 if (!found_principal && use_authorized_principals) { 528 reason = "Certificate does not contain an authorized principal"; 529 goto fail_reason; 530 } 531 if (use_authorized_principals && principals_opts == NULL) 532 fatal_f("internal error: missing principals_opts"); 533 if (sshkey_cert_check_authority_now(key, 0, 1, 0, 534 use_authorized_principals ? NULL : pw->pw_name, &reason) != 0) 535 goto fail_reason; 536 537 /* Check authority from options in key and from principals file/cmd */ 538 if ((cert_opts = sshauthopt_from_cert(key)) == NULL) { 539 reason = "Invalid certificate options"; 540 goto fail_reason; 541 } 542 if (auth_authorise_keyopts(pw, cert_opts, 0, 543 remote_ip, remote_host, "cert") != 0) { 544 reason = "Refused by certificate options"; 545 goto fail_reason; 546 } 547 if (principals_opts == NULL) { 548 final_opts = cert_opts; 549 cert_opts = NULL; 550 } else { 551 if (auth_authorise_keyopts(pw, principals_opts, 0, 552 remote_ip, remote_host, "principals") != 0) { 553 reason = "Refused by certificate principals options"; 554 goto fail_reason; 555 } 556 if ((final_opts = sshauthopt_merge(principals_opts, 557 cert_opts, &reason)) == NULL) { 558 fail_reason: 559 error("%s", reason); 560 auth_debug_add("%s", reason); 561 goto out; 562 } 563 } 564 565 /* Success */ 566 verbose("Accepted certificate ID \"%s\" (serial %llu) signed by " 567 "%s CA %s via %s", key->cert->key_id, 568 (unsigned long long)key->cert->serial, 569 sshkey_type(key->cert->signature_key), ca_fp, 570 options.trusted_user_ca_keys); 571 if (authoptsp != NULL) { 572 *authoptsp = final_opts; 573 final_opts = NULL; 574 } 575 ret = 1; 576 out: 577 sshauthopt_free(principals_opts); 578 sshauthopt_free(cert_opts); 579 sshauthopt_free(final_opts); 580 free(principals_file); 581 free(ca_fp); 582 return ret; 583} 584 585/* 586 * Checks whether key is allowed in file. 587 * returns 1 if the key is allowed or 0 otherwise. 588 */ 589static int 590user_key_allowed2(struct passwd *pw, struct sshkey *key, 591 char *file, const char *remote_ip, const char *remote_host, 592 struct sshauthopt **authoptsp) 593{ 594 FILE *f; 595 int found_key = 0; 596 597 if (authoptsp != NULL) 598 *authoptsp = NULL; 599 600 /* Temporarily use the user's uid. */ 601 temporarily_use_uid(pw); 602 603 debug("trying public key file %s", file); 604 if ((f = auth_openkeyfile(file, pw, options.strict_modes)) != NULL) { 605 found_key = auth_check_authkeys_file(pw, f, file, 606 key, remote_ip, remote_host, authoptsp); 607 fclose(f); 608 } 609 610 restore_uid(); 611 return found_key; 612} 613 614/* 615 * Checks whether key is allowed in output of command. 616 * returns 1 if the key is allowed or 0 otherwise. 617 */ 618static int 619user_key_command_allowed2(struct passwd *user_pw, struct sshkey *key, 620 const char *remote_ip, const char *remote_host, 621 struct sshauthopt **authoptsp) 622{ 623 struct passwd *runas_pw = NULL; 624 FILE *f = NULL; 625 int r, ok, found_key = 0; 626 int i, uid_swapped = 0, ac = 0; 627 pid_t pid; 628 char *username = NULL, *key_fp = NULL, *keytext = NULL; 629 char uidstr[32], *tmp, *command = NULL, **av = NULL; 630 void (*osigchld)(int); 631 632 if (authoptsp != NULL) 633 *authoptsp = NULL; 634 if (options.authorized_keys_command == NULL) 635 return 0; 636 if (options.authorized_keys_command_user == NULL) { 637 error("No user for AuthorizedKeysCommand specified, skipping"); 638 return 0; 639 } 640 641 /* 642 * NB. all returns later this function should go via "out" to 643 * ensure the original SIGCHLD handler is restored properly. 644 */ 645 osigchld = ssh_signal(SIGCHLD, SIG_DFL); 646 647 /* Prepare and verify the user for the command */ 648 username = percent_expand(options.authorized_keys_command_user, 649 "u", user_pw->pw_name, (char *)NULL); 650 runas_pw = getpwnam(username); 651 if (runas_pw == NULL) { 652 error("AuthorizedKeysCommandUser \"%s\" not found: %s", 653 username, strerror(errno)); 654 goto out; 655 } 656 657 /* Prepare AuthorizedKeysCommand */ 658 if ((key_fp = sshkey_fingerprint(key, options.fingerprint_hash, 659 SSH_FP_DEFAULT)) == NULL) { 660 error_f("sshkey_fingerprint failed"); 661 goto out; 662 } 663 if ((r = sshkey_to_base64(key, &keytext)) != 0) { 664 error_fr(r, "sshkey_to_base64 failed"); 665 goto out; 666 } 667 668 /* Turn the command into an argument vector */ 669 if (argv_split(options.authorized_keys_command, &ac, &av, 0) != 0) { 670 error("AuthorizedKeysCommand \"%s\" contains invalid quotes", 671 options.authorized_keys_command); 672 goto out; 673 } 674 if (ac == 0) { 675 error("AuthorizedKeysCommand \"%s\" yielded no arguments", 676 options.authorized_keys_command); 677 goto out; 678 } 679 snprintf(uidstr, sizeof(uidstr), "%llu", 680 (unsigned long long)user_pw->pw_uid); 681 for (i = 1; i < ac; i++) { 682 tmp = percent_expand(av[i], 683 "U", uidstr, 684 "u", user_pw->pw_name, 685 "h", user_pw->pw_dir, 686 "t", sshkey_ssh_name(key), 687 "f", key_fp, 688 "k", keytext, 689 (char *)NULL); 690 if (tmp == NULL) 691 fatal_f("percent_expand failed"); 692 free(av[i]); 693 av[i] = tmp; 694 } 695 /* Prepare a printable command for logs, etc. */ 696 command = argv_assemble(ac, av); 697 698 /* 699 * If AuthorizedKeysCommand was run without arguments 700 * then fall back to the old behaviour of passing the 701 * target username as a single argument. 702 */ 703 if (ac == 1) { 704 av = xreallocarray(av, ac + 2, sizeof(*av)); 705 av[1] = xstrdup(user_pw->pw_name); 706 av[2] = NULL; 707 /* Fix up command too, since it is used in log messages */ 708 free(command); 709 xasprintf(&command, "%s %s", av[0], av[1]); 710 } 711 712 if ((pid = subprocess("AuthorizedKeysCommand", command, 713 ac, av, &f, 714 SSH_SUBPROCESS_STDOUT_CAPTURE|SSH_SUBPROCESS_STDERR_DISCARD, 715 runas_pw, temporarily_use_uid, restore_uid)) == 0) 716 goto out; 717 718 uid_swapped = 1; 719 temporarily_use_uid(runas_pw); 720 721 ok = auth_check_authkeys_file(user_pw, f, 722 options.authorized_keys_command, key, remote_ip, 723 remote_host, authoptsp); 724 725 fclose(f); 726 f = NULL; 727 728 if (exited_cleanly(pid, "AuthorizedKeysCommand", command, 0) != 0) 729 goto out; 730 731 /* Read completed successfully */ 732 found_key = ok; 733 out: 734 if (f != NULL) 735 fclose(f); 736 ssh_signal(SIGCHLD, osigchld); 737 for (i = 0; i < ac; i++) 738 free(av[i]); 739 free(av); 740 if (uid_swapped) 741 restore_uid(); 742 free(command); 743 free(username); 744 free(key_fp); 745 free(keytext); 746 return found_key; 747} 748 749/* 750 * Check whether key authenticates and authorises the user. 751 */ 752int 753user_key_allowed(struct ssh *ssh, struct passwd *pw, struct sshkey *key, 754 int auth_attempt, struct sshauthopt **authoptsp) 755{ 756 u_int success = 0, i; 757 char *file; 758 struct sshauthopt *opts = NULL; 759 const char *remote_ip = ssh_remote_ipaddr(ssh); 760 const char *remote_host = auth_get_canonical_hostname(ssh, 761 options.use_dns); 762 763 if (authoptsp != NULL) 764 *authoptsp = NULL; 765 766 if (auth_key_is_revoked(key)) 767 return 0; 768 if (sshkey_is_cert(key) && 769 auth_key_is_revoked(key->cert->signature_key)) 770 return 0; 771 772 for (i = 0; !success && i < options.num_authkeys_files; i++) { 773 if (strcasecmp(options.authorized_keys_files[i], "none") == 0) 774 continue; 775 file = expand_authorized_keys( 776 options.authorized_keys_files[i], pw); 777 success = user_key_allowed2(pw, key, file, 778 remote_ip, remote_host, &opts); 779 free(file); 780 if (!success) { 781 sshauthopt_free(opts); 782 opts = NULL; 783 } 784 } 785 if (success) 786 goto out; 787 788 if ((success = user_cert_trusted_ca(pw, key, remote_ip, remote_host, 789 &opts)) != 0) 790 goto out; 791 sshauthopt_free(opts); 792 opts = NULL; 793 794 if ((success = user_key_command_allowed2(pw, key, remote_ip, 795 remote_host, &opts)) != 0) 796 goto out; 797 sshauthopt_free(opts); 798 opts = NULL; 799 800 out: 801 if (success && authoptsp != NULL) { 802 *authoptsp = opts; 803 opts = NULL; 804 } 805 sshauthopt_free(opts); 806 return success; 807} 808 809Authmethod method_pubkey = { 810 "publickey", 811 "publickey-hostbound-v00@openssh.com", 812 userauth_pubkey, 813 &options.pubkey_authentication 814}; 815