1 /* $OpenBSD: ssh-add.c,v 1.163 2021/12/22 06:56:41 jmc Exp $ */ 2 /* 3 * Author: Tatu Ylonen <ylo@cs.hut.fi> 4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 5 * All rights reserved 6 * Adds an identity to the authentication server, or removes an identity. 7 * 8 * As far as I am concerned, the code I have written for this software 9 * can be used freely for any purpose. Any derived versions of this 10 * software must be clearly marked as such, and if the derived work is 11 * incompatible with the protocol description in the RFC file, it must be 12 * called by a name other than "ssh" or "Secure Shell". 13 * 14 * SSH2 implementation, 15 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions 19 * are met: 20 * 1. Redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer. 22 * 2. Redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution. 25 * 26 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 27 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 28 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 29 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 30 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 31 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 32 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 33 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 34 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 35 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 36 */ 37 38 #include <sys/types.h> 39 #include <sys/stat.h> 40 41 #ifdef WITH_OPENSSL 42 #include <openssl/evp.h> 43 #endif 44 45 #include <errno.h> 46 #include <fcntl.h> 47 #include <pwd.h> 48 #include <stdio.h> 49 #include <stdlib.h> 50 #include <string.h> 51 #include <stdarg.h> 52 #include <unistd.h> 53 #include <limits.h> 54 55 #include "xmalloc.h" 56 #include "ssh.h" 57 #include "log.h" 58 #include "sshkey.h" 59 #include "sshbuf.h" 60 #include "authfd.h" 61 #include "authfile.h" 62 #include "pathnames.h" 63 #include "misc.h" 64 #include "ssherr.h" 65 #include "digest.h" 66 #include "ssh-sk.h" 67 #include "sk-api.h" 68 #include "hostfile.h" 69 70 /* argv0 */ 71 extern char *__progname; 72 73 /* Default files to add */ 74 static char *default_files[] = { 75 _PATH_SSH_CLIENT_ID_RSA, 76 _PATH_SSH_CLIENT_ID_DSA, 77 _PATH_SSH_CLIENT_ID_ECDSA, 78 _PATH_SSH_CLIENT_ID_ECDSA_SK, 79 _PATH_SSH_CLIENT_ID_ED25519, 80 _PATH_SSH_CLIENT_ID_ED25519_SK, 81 _PATH_SSH_CLIENT_ID_XMSS, 82 NULL 83 }; 84 85 static int fingerprint_hash = SSH_FP_HASH_DEFAULT; 86 87 /* Default lifetime (0 == forever) */ 88 static int lifetime = 0; 89 90 /* User has to confirm key use */ 91 static int confirm = 0; 92 93 /* Maximum number of signatures (XMSS) */ 94 static u_int maxsign = 0; 95 static u_int minleft = 0; 96 97 /* we keep a cache of one passphrase */ 98 static char *pass = NULL; 99 static void 100 clear_pass(void) 101 { 102 if (pass) { 103 freezero(pass, strlen(pass)); 104 pass = NULL; 105 } 106 } 107 108 static int 109 delete_one(int agent_fd, const struct sshkey *key, const char *comment, 110 const char *path, int qflag) 111 { 112 int r; 113 114 if ((r = ssh_remove_identity(agent_fd, key)) != 0) { 115 fprintf(stderr, "Could not remove identity \"%s\": %s\n", 116 path, ssh_err(r)); 117 return r; 118 } 119 if (!qflag) { 120 fprintf(stderr, "Identity removed: %s %s (%s)\n", path, 121 sshkey_type(key), comment); 122 } 123 return 0; 124 } 125 126 static int 127 delete_stdin(int agent_fd, int qflag) 128 { 129 char *line = NULL, *cp; 130 size_t linesize = 0; 131 struct sshkey *key = NULL; 132 int lnum = 0, r, ret = -1; 133 134 while (getline(&line, &linesize, stdin) != -1) { 135 lnum++; 136 sshkey_free(key); 137 key = NULL; 138 line[strcspn(line, "\n")] = '\0'; 139 cp = line + strspn(line, " \t"); 140 if (*cp == '#' || *cp == '\0') 141 continue; 142 if ((key = sshkey_new(KEY_UNSPEC)) == NULL) 143 fatal_f("sshkey_new"); 144 if ((r = sshkey_read(key, &cp)) != 0) { 145 error_r(r, "(stdin):%d: invalid key", lnum); 146 continue; 147 } 148 if (delete_one(agent_fd, key, cp, "(stdin)", qflag) == 0) 149 ret = 0; 150 } 151 sshkey_free(key); 152 free(line); 153 return ret; 154 } 155 156 static int 157 delete_file(int agent_fd, const char *filename, int key_only, int qflag) 158 { 159 struct sshkey *public, *cert = NULL; 160 char *certpath = NULL, *comment = NULL; 161 int r, ret = -1; 162 163 if (strcmp(filename, "-") == 0) 164 return delete_stdin(agent_fd, qflag); 165 166 if ((r = sshkey_load_public(filename, &public, &comment)) != 0) { 167 printf("Bad key file %s: %s\n", filename, ssh_err(r)); 168 return -1; 169 } 170 if (delete_one(agent_fd, public, comment, filename, qflag) == 0) 171 ret = 0; 172 173 if (key_only) 174 goto out; 175 176 /* Now try to delete the corresponding certificate too */ 177 free(comment); 178 comment = NULL; 179 xasprintf(&certpath, "%s-cert.pub", filename); 180 if ((r = sshkey_load_public(certpath, &cert, &comment)) != 0) { 181 if (r != SSH_ERR_SYSTEM_ERROR || errno != ENOENT) 182 error_r(r, "Failed to load certificate \"%s\"", certpath); 183 goto out; 184 } 185 186 if (!sshkey_equal_public(cert, public)) 187 fatal("Certificate %s does not match private key %s", 188 certpath, filename); 189 190 if (delete_one(agent_fd, cert, comment, certpath, qflag) == 0) 191 ret = 0; 192 193 out: 194 sshkey_free(cert); 195 sshkey_free(public); 196 free(certpath); 197 free(comment); 198 199 return ret; 200 } 201 202 /* Send a request to remove all identities. */ 203 static int 204 delete_all(int agent_fd, int qflag) 205 { 206 int ret = -1; 207 208 /* 209 * Since the agent might be forwarded, old or non-OpenSSH, when asked 210 * to remove all keys, attempt to remove both protocol v.1 and v.2 211 * keys. 212 */ 213 if (ssh_remove_all_identities(agent_fd, 2) == 0) 214 ret = 0; 215 /* ignore error-code for ssh1 */ 216 ssh_remove_all_identities(agent_fd, 1); 217 218 if (ret != 0) 219 fprintf(stderr, "Failed to remove all identities.\n"); 220 else if (!qflag) 221 fprintf(stderr, "All identities removed.\n"); 222 223 return ret; 224 } 225 226 static int 227 add_file(int agent_fd, const char *filename, int key_only, int qflag, 228 const char *skprovider, struct dest_constraint **dest_constraints, 229 size_t ndest_constraints) 230 { 231 struct sshkey *private, *cert; 232 char *comment = NULL; 233 char msg[1024], *certpath = NULL; 234 int r, fd, ret = -1; 235 size_t i; 236 u_int32_t left; 237 struct sshbuf *keyblob; 238 struct ssh_identitylist *idlist; 239 240 if (strcmp(filename, "-") == 0) { 241 fd = STDIN_FILENO; 242 filename = "(stdin)"; 243 } else if ((fd = open(filename, O_RDONLY)) == -1) { 244 perror(filename); 245 return -1; 246 } 247 248 /* 249 * Since we'll try to load a keyfile multiple times, permission errors 250 * will occur multiple times, so check perms first and bail if wrong. 251 */ 252 if (fd != STDIN_FILENO) { 253 if (sshkey_perm_ok(fd, filename) != 0) { 254 close(fd); 255 return -1; 256 } 257 } 258 if ((r = sshbuf_load_fd(fd, &keyblob)) != 0) { 259 fprintf(stderr, "Error loading key \"%s\": %s\n", 260 filename, ssh_err(r)); 261 sshbuf_free(keyblob); 262 close(fd); 263 return -1; 264 } 265 close(fd); 266 267 /* At first, try empty passphrase */ 268 if ((r = sshkey_parse_private_fileblob(keyblob, "", &private, 269 &comment)) != 0 && r != SSH_ERR_KEY_WRONG_PASSPHRASE) { 270 fprintf(stderr, "Error loading key \"%s\": %s\n", 271 filename, ssh_err(r)); 272 goto fail_load; 273 } 274 /* try last */ 275 if (private == NULL && pass != NULL) { 276 if ((r = sshkey_parse_private_fileblob(keyblob, pass, &private, 277 &comment)) != 0 && r != SSH_ERR_KEY_WRONG_PASSPHRASE) { 278 fprintf(stderr, "Error loading key \"%s\": %s\n", 279 filename, ssh_err(r)); 280 goto fail_load; 281 } 282 } 283 if (private == NULL) { 284 /* clear passphrase since it did not work */ 285 clear_pass(); 286 snprintf(msg, sizeof msg, "Enter passphrase for %s%s: ", 287 filename, confirm ? " (will confirm each use)" : ""); 288 for (;;) { 289 pass = read_passphrase(msg, RP_ALLOW_STDIN); 290 if (strcmp(pass, "") == 0) 291 goto fail_load; 292 if ((r = sshkey_parse_private_fileblob(keyblob, pass, 293 &private, &comment)) == 0) 294 break; 295 else if (r != SSH_ERR_KEY_WRONG_PASSPHRASE) { 296 fprintf(stderr, 297 "Error loading key \"%s\": %s\n", 298 filename, ssh_err(r)); 299 fail_load: 300 clear_pass(); 301 sshbuf_free(keyblob); 302 return -1; 303 } 304 clear_pass(); 305 snprintf(msg, sizeof msg, 306 "Bad passphrase, try again for %s%s: ", filename, 307 confirm ? " (will confirm each use)" : ""); 308 } 309 } 310 if (comment == NULL || *comment == '\0') 311 comment = xstrdup(filename); 312 sshbuf_free(keyblob); 313 314 /* For XMSS */ 315 if ((r = sshkey_set_filename(private, filename)) != 0) { 316 fprintf(stderr, "Could not add filename to private key: %s (%s)\n", 317 filename, comment); 318 goto out; 319 } 320 if (maxsign && minleft && 321 (r = ssh_fetch_identitylist(agent_fd, &idlist)) == 0) { 322 for (i = 0; i < idlist->nkeys; i++) { 323 if (!sshkey_equal_public(idlist->keys[i], private)) 324 continue; 325 left = sshkey_signatures_left(idlist->keys[i]); 326 if (left < minleft) { 327 fprintf(stderr, 328 "Only %d signatures left.\n", left); 329 break; 330 } 331 fprintf(stderr, "Skipping update: "); 332 if (left == minleft) { 333 fprintf(stderr, 334 "required signatures left (%d).\n", left); 335 } else { 336 fprintf(stderr, 337 "more signatures left (%d) than" 338 " required (%d).\n", left, minleft); 339 } 340 ssh_free_identitylist(idlist); 341 goto out; 342 } 343 ssh_free_identitylist(idlist); 344 } 345 346 if (sshkey_is_sk(private)) { 347 if (skprovider == NULL) { 348 fprintf(stderr, "Cannot load FIDO key %s " 349 "without provider\n", filename); 350 goto out; 351 } 352 if ((private->sk_flags & SSH_SK_USER_VERIFICATION_REQD) != 0) { 353 fprintf(stderr, "FIDO verify-required key %s is not " 354 "currently supported by ssh-agent\n", filename); 355 goto out; 356 } 357 } else { 358 /* Don't send provider constraint for other keys */ 359 skprovider = NULL; 360 } 361 362 if ((r = ssh_add_identity_constrained(agent_fd, private, comment, 363 lifetime, confirm, maxsign, skprovider, 364 dest_constraints, ndest_constraints)) == 0) { 365 ret = 0; 366 if (!qflag) { 367 fprintf(stderr, "Identity added: %s (%s)\n", 368 filename, comment); 369 if (lifetime != 0) { 370 fprintf(stderr, 371 "Lifetime set to %d seconds\n", lifetime); 372 } 373 if (confirm != 0) { 374 fprintf(stderr, "The user must confirm " 375 "each use of the key\n"); 376 } 377 } 378 } else { 379 fprintf(stderr, "Could not add identity \"%s\": %s\n", 380 filename, ssh_err(r)); 381 } 382 383 /* Skip trying to load the cert if requested */ 384 if (key_only) 385 goto out; 386 387 /* Now try to add the certificate flavour too */ 388 xasprintf(&certpath, "%s-cert.pub", filename); 389 if ((r = sshkey_load_public(certpath, &cert, NULL)) != 0) { 390 if (r != SSH_ERR_SYSTEM_ERROR || errno != ENOENT) 391 error_r(r, "Failed to load certificate \"%s\"", certpath); 392 goto out; 393 } 394 395 if (!sshkey_equal_public(cert, private)) { 396 error("Certificate %s does not match private key %s", 397 certpath, filename); 398 sshkey_free(cert); 399 goto out; 400 } 401 402 /* Graft with private bits */ 403 if ((r = sshkey_to_certified(private)) != 0) { 404 error_fr(r, "sshkey_to_certified"); 405 sshkey_free(cert); 406 goto out; 407 } 408 if ((r = sshkey_cert_copy(cert, private)) != 0) { 409 error_fr(r, "sshkey_cert_copy"); 410 sshkey_free(cert); 411 goto out; 412 } 413 sshkey_free(cert); 414 415 if ((r = ssh_add_identity_constrained(agent_fd, private, comment, 416 lifetime, confirm, maxsign, skprovider, 417 dest_constraints, ndest_constraints)) != 0) { 418 error_r(r, "Certificate %s (%s) add failed", certpath, 419 private->cert->key_id); 420 goto out; 421 } 422 /* success */ 423 if (!qflag) { 424 fprintf(stderr, "Certificate added: %s (%s)\n", certpath, 425 private->cert->key_id); 426 if (lifetime != 0) { 427 fprintf(stderr, "Lifetime set to %d seconds\n", 428 lifetime); 429 } 430 if (confirm != 0) { 431 fprintf(stderr, "The user must confirm each use " 432 "of the key\n"); 433 } 434 } 435 436 out: 437 free(certpath); 438 free(comment); 439 sshkey_free(private); 440 441 return ret; 442 } 443 444 static int 445 update_card(int agent_fd, int add, const char *id, int qflag, 446 struct dest_constraint **dest_constraints, size_t ndest_constraints) 447 { 448 char *pin = NULL; 449 int r, ret = -1; 450 451 if (add) { 452 if ((pin = read_passphrase("Enter passphrase for PKCS#11: ", 453 RP_ALLOW_STDIN)) == NULL) 454 return -1; 455 } 456 457 if ((r = ssh_update_card(agent_fd, add, id, pin == NULL ? "" : pin, 458 lifetime, confirm, dest_constraints, ndest_constraints)) == 0) { 459 ret = 0; 460 if (!qflag) { 461 fprintf(stderr, "Card %s: %s\n", 462 add ? "added" : "removed", id); 463 } 464 } else { 465 fprintf(stderr, "Could not %s card \"%s\": %s\n", 466 add ? "add" : "remove", id, ssh_err(r)); 467 ret = -1; 468 } 469 free(pin); 470 return ret; 471 } 472 473 static int 474 test_key(int agent_fd, const char *filename) 475 { 476 struct sshkey *key = NULL; 477 u_char *sig = NULL; 478 size_t slen = 0; 479 int r, ret = -1; 480 char data[1024]; 481 482 if ((r = sshkey_load_public(filename, &key, NULL)) != 0) { 483 error_r(r, "Couldn't read public key %s", filename); 484 return -1; 485 } 486 arc4random_buf(data, sizeof(data)); 487 if ((r = ssh_agent_sign(agent_fd, key, &sig, &slen, data, sizeof(data), 488 NULL, 0)) != 0) { 489 error_r(r, "Agent signature failed for %s", filename); 490 goto done; 491 } 492 if ((r = sshkey_verify(key, sig, slen, data, sizeof(data), 493 NULL, 0, NULL)) != 0) { 494 error_r(r, "Signature verification failed for %s", filename); 495 goto done; 496 } 497 /* success */ 498 ret = 0; 499 done: 500 free(sig); 501 sshkey_free(key); 502 return ret; 503 } 504 505 static int 506 list_identities(int agent_fd, int do_fp) 507 { 508 char *fp; 509 int r; 510 struct ssh_identitylist *idlist; 511 u_int32_t left; 512 size_t i; 513 514 if ((r = ssh_fetch_identitylist(agent_fd, &idlist)) != 0) { 515 if (r != SSH_ERR_AGENT_NO_IDENTITIES) 516 fprintf(stderr, "error fetching identities: %s\n", 517 ssh_err(r)); 518 else 519 printf("The agent has no identities.\n"); 520 return -1; 521 } 522 for (i = 0; i < idlist->nkeys; i++) { 523 if (do_fp) { 524 fp = sshkey_fingerprint(idlist->keys[i], 525 fingerprint_hash, SSH_FP_DEFAULT); 526 printf("%u %s %s (%s)\n", sshkey_size(idlist->keys[i]), 527 fp == NULL ? "(null)" : fp, idlist->comments[i], 528 sshkey_type(idlist->keys[i])); 529 free(fp); 530 } else { 531 if ((r = sshkey_write(idlist->keys[i], stdout)) != 0) { 532 fprintf(stderr, "sshkey_write: %s\n", 533 ssh_err(r)); 534 continue; 535 } 536 fprintf(stdout, " %s", idlist->comments[i]); 537 left = sshkey_signatures_left(idlist->keys[i]); 538 if (left > 0) 539 fprintf(stdout, 540 " [signatures left %d]", left); 541 fprintf(stdout, "\n"); 542 } 543 } 544 ssh_free_identitylist(idlist); 545 return 0; 546 } 547 548 static int 549 lock_agent(int agent_fd, int lock) 550 { 551 char prompt[100], *p1, *p2; 552 int r, passok = 1, ret = -1; 553 554 strlcpy(prompt, "Enter lock password: ", sizeof(prompt)); 555 p1 = read_passphrase(prompt, RP_ALLOW_STDIN); 556 if (lock) { 557 strlcpy(prompt, "Again: ", sizeof prompt); 558 p2 = read_passphrase(prompt, RP_ALLOW_STDIN); 559 if (strcmp(p1, p2) != 0) { 560 fprintf(stderr, "Passwords do not match.\n"); 561 passok = 0; 562 } 563 freezero(p2, strlen(p2)); 564 } 565 if (passok) { 566 if ((r = ssh_lock_agent(agent_fd, lock, p1)) == 0) { 567 fprintf(stderr, "Agent %slocked.\n", lock ? "" : "un"); 568 ret = 0; 569 } else { 570 fprintf(stderr, "Failed to %slock agent: %s\n", 571 lock ? "" : "un", ssh_err(r)); 572 } 573 } 574 freezero(p1, strlen(p1)); 575 return (ret); 576 } 577 578 static int 579 load_resident_keys(int agent_fd, const char *skprovider, int qflag, 580 struct dest_constraint **dest_constraints, size_t ndest_constraints) 581 { 582 struct sshsk_resident_key **srks; 583 size_t nsrks, i; 584 struct sshkey *key; 585 int r, ok = 0; 586 char *fp; 587 588 pass = read_passphrase("Enter PIN for authenticator: ", RP_ALLOW_STDIN); 589 if ((r = sshsk_load_resident(skprovider, NULL, pass, 0, 590 &srks, &nsrks)) != 0) { 591 error_r(r, "Unable to load resident keys"); 592 return r; 593 } 594 for (i = 0; i < nsrks; i++) { 595 key = srks[i]->key; 596 if ((fp = sshkey_fingerprint(key, 597 fingerprint_hash, SSH_FP_DEFAULT)) == NULL) 598 fatal_f("sshkey_fingerprint failed"); 599 if ((r = ssh_add_identity_constrained(agent_fd, key, "", 600 lifetime, confirm, maxsign, skprovider, 601 dest_constraints, ndest_constraints)) != 0) { 602 error("Unable to add key %s %s", 603 sshkey_type(key), fp); 604 free(fp); 605 ok = r; 606 continue; 607 } 608 if (ok == 0) 609 ok = 1; 610 if (!qflag) { 611 fprintf(stderr, "Resident identity added: %s %s\n", 612 sshkey_type(key), fp); 613 if (lifetime != 0) { 614 fprintf(stderr, 615 "Lifetime set to %d seconds\n", lifetime); 616 } 617 if (confirm != 0) { 618 fprintf(stderr, "The user must confirm " 619 "each use of the key\n"); 620 } 621 } 622 free(fp); 623 } 624 sshsk_free_resident_keys(srks, nsrks); 625 if (nsrks == 0) 626 return SSH_ERR_KEY_NOT_FOUND; 627 return ok == 1 ? 0 : ok; 628 } 629 630 static int 631 do_file(int agent_fd, int deleting, int key_only, char *file, int qflag, 632 const char *skprovider, struct dest_constraint **dest_constraints, 633 size_t ndest_constraints) 634 { 635 if (deleting) { 636 if (delete_file(agent_fd, file, key_only, qflag) == -1) 637 return -1; 638 } else { 639 if (add_file(agent_fd, file, key_only, qflag, skprovider, 640 dest_constraints, ndest_constraints) == -1) 641 return -1; 642 } 643 return 0; 644 } 645 646 /* Append string 's' to a NULL-terminated array of strings */ 647 static void 648 stringlist_append(char ***listp, const char *s) 649 { 650 size_t i = 0; 651 652 if (*listp == NULL) 653 *listp = xcalloc(2, sizeof(**listp)); 654 else { 655 for (i = 0; (*listp)[i] != NULL; i++) 656 ; /* count */ 657 *listp = xrecallocarray(*listp, i + 1, i + 2, sizeof(**listp)); 658 } 659 (*listp)[i] = xstrdup(s); 660 } 661 662 static void 663 parse_dest_constraint_hop(const char *s, struct dest_constraint_hop *dch, 664 char **hostkey_files) 665 { 666 char *user = NULL, *host, *os, *path; 667 size_t i; 668 struct hostkeys *hostkeys; 669 const struct hostkey_entry *hke; 670 int r, want_ca; 671 672 memset(dch, '\0', sizeof(*dch)); 673 os = xstrdup(s); 674 if ((host = strchr(os, '@')) == NULL) 675 host = os; 676 else { 677 *host++ = '\0'; 678 user = os; 679 } 680 cleanhostname(host); 681 /* Trivial case: username@ (all hosts) */ 682 if (*host == '\0') { 683 if (user == NULL) { 684 fatal("Invalid key destination constraint \"%s\": " 685 "does not specify user or host", s); 686 } 687 dch->user = xstrdup(user); 688 /* other fields left blank */ 689 free(os); 690 return; 691 } 692 if (hostkey_files == NULL) 693 fatal_f("no hostkey files"); 694 /* Otherwise we need to look up the keys for this hostname */ 695 hostkeys = init_hostkeys(); 696 for (i = 0; hostkey_files[i]; i++) { 697 path = tilde_expand_filename(hostkey_files[i], getuid()); 698 debug2_f("looking up host keys for \"%s\" in %s", host, path); 699 load_hostkeys(hostkeys, host, path, 0); 700 free(path); 701 } 702 dch->user = user == NULL ? NULL : xstrdup(user); 703 dch->hostname = xstrdup(host); 704 for (i = 0; i < hostkeys->num_entries; i++) { 705 hke = hostkeys->entries + i; 706 want_ca = hke->marker == MRK_CA; 707 if (hke->marker != MRK_NONE && !want_ca) 708 continue; 709 debug3_f("%s%s%s: adding %s %skey from %s:%lu as key %u", 710 user == NULL ? "": user, user == NULL ? "" : "@", 711 host, sshkey_type(hke->key), want_ca ? "CA " : "", 712 hke->file, hke->line, dch->nkeys); 713 dch->keys = xrecallocarray(dch->keys, dch->nkeys, 714 dch->nkeys + 1, sizeof(*dch->keys)); 715 dch->key_is_ca = xrecallocarray(dch->key_is_ca, dch->nkeys, 716 dch->nkeys + 1, sizeof(*dch->key_is_ca)); 717 if ((r = sshkey_from_private(hke->key, 718 &(dch->keys[dch->nkeys]))) != 0) 719 fatal_fr(r, "sshkey_from_private"); 720 dch->key_is_ca[dch->nkeys] = want_ca; 721 dch->nkeys++; 722 } 723 if (dch->nkeys == 0) 724 fatal("No host keys found for destination \"%s\"", host); 725 free_hostkeys(hostkeys); 726 free(os); 727 return; 728 } 729 730 static void 731 parse_dest_constraint(const char *s, struct dest_constraint ***dcp, 732 size_t *ndcp, char **hostkey_files) 733 { 734 struct dest_constraint *dc; 735 char *os, *cp; 736 737 dc = xcalloc(1, sizeof(*dc)); 738 os = xstrdup(s); 739 if ((cp = strchr(os, '>')) == NULL) { 740 /* initial hop; no 'from' hop specified */ 741 parse_dest_constraint_hop(os, &dc->to, hostkey_files); 742 } else { 743 /* two hops specified */ 744 *(cp++) = '\0'; 745 parse_dest_constraint_hop(os, &dc->from, hostkey_files); 746 parse_dest_constraint_hop(cp, &dc->to, hostkey_files); 747 if (dc->from.user != NULL) { 748 fatal("Invalid key constraint %s: cannot specify " 749 "user on 'from' host", os); 750 } 751 } 752 /* XXX eliminate or error on duplicates */ 753 debug2_f("constraint %zu: %s%s%s (%u keys) > %s%s%s (%u keys)", *ndcp, 754 dc->from.user ? dc->from.user : "", dc->from.user ? "@" : "", 755 dc->from.hostname ? dc->from.hostname : "(ORIGIN)", dc->from.nkeys, 756 dc->to.user ? dc->to.user : "", dc->to.user ? "@" : "", 757 dc->to.hostname ? dc->to.hostname : "(ANY)", dc->to.nkeys); 758 *dcp = xrecallocarray(*dcp, *ndcp, *ndcp + 1, sizeof(**dcp)); 759 (*dcp)[(*ndcp)++] = dc; 760 free(os); 761 } 762 763 764 static void 765 usage(void) 766 { 767 fprintf(stderr, 768 "usage: ssh-add [-cDdKkLlqvXx] [-E fingerprint_hash] [-H hostkey_file]\n" 769 " [-h destination_constraint] [-S provider] [-t life]\n" 770 #ifdef WITH_XMSS 771 " [-M maxsign] [-m minleft]\n" 772 #endif 773 " [file ...]\n" 774 " ssh-add -s pkcs11\n" 775 " ssh-add -e pkcs11\n" 776 " ssh-add -T pubkey ...\n" 777 ); 778 } 779 780 int 781 main(int argc, char **argv) 782 { 783 extern char *optarg; 784 extern int optind; 785 int agent_fd; 786 char *pkcs11provider = NULL, *skprovider = NULL; 787 char **dest_constraint_strings = NULL, **hostkey_files = NULL; 788 int r, i, ch, deleting = 0, ret = 0, key_only = 0, do_download = 0; 789 int xflag = 0, lflag = 0, Dflag = 0, qflag = 0, Tflag = 0; 790 SyslogFacility log_facility = SYSLOG_FACILITY_AUTH; 791 LogLevel log_level = SYSLOG_LEVEL_INFO; 792 struct dest_constraint **dest_constraints = NULL; 793 size_t ndest_constraints = 0; 794 795 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 796 sanitise_stdfd(); 797 798 #ifdef WITH_OPENSSL 799 OpenSSL_add_all_algorithms(); 800 #endif 801 log_init(__progname, log_level, log_facility, 1); 802 803 setvbuf(stdout, NULL, _IOLBF, 0); 804 805 /* First, get a connection to the authentication agent. */ 806 switch (r = ssh_get_authentication_socket(&agent_fd)) { 807 case 0: 808 break; 809 case SSH_ERR_AGENT_NOT_PRESENT: 810 fprintf(stderr, "Could not open a connection to your " 811 "authentication agent.\n"); 812 exit(2); 813 default: 814 fprintf(stderr, "Error connecting to agent: %s\n", ssh_err(r)); 815 exit(2); 816 } 817 818 skprovider = getenv("SSH_SK_PROVIDER"); 819 820 while ((ch = getopt(argc, argv, "vkKlLcdDTxXE:e:h:H:M:m:qs:S:t:")) != -1) { 821 switch (ch) { 822 case 'v': 823 if (log_level == SYSLOG_LEVEL_INFO) 824 log_level = SYSLOG_LEVEL_DEBUG1; 825 else if (log_level < SYSLOG_LEVEL_DEBUG3) 826 log_level++; 827 break; 828 case 'E': 829 fingerprint_hash = ssh_digest_alg_by_name(optarg); 830 if (fingerprint_hash == -1) 831 fatal("Invalid hash algorithm \"%s\"", optarg); 832 break; 833 case 'H': 834 stringlist_append(&hostkey_files, optarg); 835 break; 836 case 'h': 837 stringlist_append(&dest_constraint_strings, optarg); 838 break; 839 case 'k': 840 key_only = 1; 841 break; 842 case 'K': 843 do_download = 1; 844 break; 845 case 'l': 846 case 'L': 847 if (lflag != 0) 848 fatal("-%c flag already specified", lflag); 849 lflag = ch; 850 break; 851 case 'x': 852 case 'X': 853 if (xflag != 0) 854 fatal("-%c flag already specified", xflag); 855 xflag = ch; 856 break; 857 case 'c': 858 confirm = 1; 859 break; 860 case 'm': 861 minleft = (int)strtonum(optarg, 1, UINT_MAX, NULL); 862 if (minleft == 0) { 863 usage(); 864 ret = 1; 865 goto done; 866 } 867 break; 868 case 'M': 869 maxsign = (int)strtonum(optarg, 1, UINT_MAX, NULL); 870 if (maxsign == 0) { 871 usage(); 872 ret = 1; 873 goto done; 874 } 875 break; 876 case 'd': 877 deleting = 1; 878 break; 879 case 'D': 880 Dflag = 1; 881 break; 882 case 's': 883 pkcs11provider = optarg; 884 break; 885 case 'S': 886 skprovider = optarg; 887 break; 888 case 'e': 889 deleting = 1; 890 pkcs11provider = optarg; 891 break; 892 case 't': 893 if ((lifetime = convtime(optarg)) == -1 || 894 lifetime < 0 || (u_long)lifetime > UINT32_MAX) { 895 fprintf(stderr, "Invalid lifetime\n"); 896 ret = 1; 897 goto done; 898 } 899 break; 900 case 'q': 901 qflag = 1; 902 break; 903 case 'T': 904 Tflag = 1; 905 break; 906 default: 907 usage(); 908 ret = 1; 909 goto done; 910 } 911 } 912 log_init(__progname, log_level, log_facility, 1); 913 914 if ((xflag != 0) + (lflag != 0) + (Dflag != 0) > 1) 915 fatal("Invalid combination of actions"); 916 else if (xflag) { 917 if (lock_agent(agent_fd, xflag == 'x' ? 1 : 0) == -1) 918 ret = 1; 919 goto done; 920 } else if (lflag) { 921 if (list_identities(agent_fd, lflag == 'l' ? 1 : 0) == -1) 922 ret = 1; 923 goto done; 924 } else if (Dflag) { 925 if (delete_all(agent_fd, qflag) == -1) 926 ret = 1; 927 goto done; 928 } 929 930 if (skprovider == NULL) 931 skprovider = "internal"; 932 if (hostkey_files == NULL) { 933 /* use defaults from readconf.c */ 934 stringlist_append(&hostkey_files, _PATH_SSH_USER_HOSTFILE); 935 stringlist_append(&hostkey_files, _PATH_SSH_USER_HOSTFILE2); 936 stringlist_append(&hostkey_files, _PATH_SSH_SYSTEM_HOSTFILE); 937 stringlist_append(&hostkey_files, _PATH_SSH_SYSTEM_HOSTFILE2); 938 } 939 if (dest_constraint_strings != NULL) { 940 for (i = 0; dest_constraint_strings[i] != NULL; i++) { 941 parse_dest_constraint(dest_constraint_strings[i], 942 &dest_constraints, &ndest_constraints, hostkey_files); 943 } 944 } 945 946 argc -= optind; 947 argv += optind; 948 if (Tflag) { 949 if (argc <= 0) 950 fatal("no keys to test"); 951 for (r = i = 0; i < argc; i++) 952 r |= test_key(agent_fd, argv[i]); 953 ret = r == 0 ? 0 : 1; 954 goto done; 955 } 956 if (pkcs11provider != NULL) { 957 if (update_card(agent_fd, !deleting, pkcs11provider, 958 qflag, dest_constraints, ndest_constraints) == -1) 959 ret = 1; 960 goto done; 961 } 962 if (do_download) { 963 if (skprovider == NULL) 964 fatal("Cannot download keys without provider"); 965 if (load_resident_keys(agent_fd, skprovider, qflag, 966 dest_constraints, ndest_constraints) != 0) 967 ret = 1; 968 goto done; 969 } 970 if (argc == 0) { 971 char buf[PATH_MAX]; 972 struct passwd *pw; 973 struct stat st; 974 int count = 0; 975 976 if ((pw = getpwuid(getuid())) == NULL) { 977 fprintf(stderr, "No user found with uid %u\n", 978 (u_int)getuid()); 979 ret = 1; 980 goto done; 981 } 982 983 for (i = 0; default_files[i]; i++) { 984 snprintf(buf, sizeof(buf), "%s/%s", pw->pw_dir, 985 default_files[i]); 986 if (stat(buf, &st) == -1) 987 continue; 988 if (do_file(agent_fd, deleting, key_only, buf, 989 qflag, skprovider, 990 dest_constraints, ndest_constraints) == -1) 991 ret = 1; 992 else 993 count++; 994 } 995 if (count == 0) 996 ret = 1; 997 } else { 998 for (i = 0; i < argc; i++) { 999 if (do_file(agent_fd, deleting, key_only, 1000 argv[i], qflag, skprovider, 1001 dest_constraints, ndest_constraints) == -1) 1002 ret = 1; 1003 } 1004 } 1005 done: 1006 clear_pass(); 1007 ssh_close_authentication_socket(agent_fd); 1008 return ret; 1009 } 1010