1 /* $OpenBSD: ssh-add.c,v 1.159 2021/01/11 02:12:58 dtucker 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 69 /* argv0 */ 70 extern char *__progname; 71 72 /* Default files to add */ 73 static char *default_files[] = { 74 _PATH_SSH_CLIENT_ID_RSA, 75 _PATH_SSH_CLIENT_ID_DSA, 76 _PATH_SSH_CLIENT_ID_ECDSA, 77 _PATH_SSH_CLIENT_ID_ECDSA_SK, 78 _PATH_SSH_CLIENT_ID_ED25519, 79 _PATH_SSH_CLIENT_ID_ED25519_SK, 80 _PATH_SSH_CLIENT_ID_XMSS, 81 NULL 82 }; 83 84 static int fingerprint_hash = SSH_FP_HASH_DEFAULT; 85 86 /* Default lifetime (0 == forever) */ 87 static int lifetime = 0; 88 89 /* User has to confirm key use */ 90 static int confirm = 0; 91 92 /* Maximum number of signatures (XMSS) */ 93 static u_int maxsign = 0; 94 static u_int minleft = 0; 95 96 /* we keep a cache of one passphrase */ 97 static char *pass = NULL; 98 static void 99 clear_pass(void) 100 { 101 if (pass) { 102 freezero(pass, strlen(pass)); 103 pass = NULL; 104 } 105 } 106 107 static int 108 delete_one(int agent_fd, const struct sshkey *key, const char *comment, 109 const char *path, int qflag) 110 { 111 int r; 112 113 if ((r = ssh_remove_identity(agent_fd, key)) != 0) { 114 fprintf(stderr, "Could not remove identity \"%s\": %s\n", 115 path, ssh_err(r)); 116 return r; 117 } 118 if (!qflag) { 119 fprintf(stderr, "Identity removed: %s %s (%s)\n", path, 120 sshkey_type(key), comment); 121 } 122 return 0; 123 } 124 125 static int 126 delete_stdin(int agent_fd, int qflag) 127 { 128 char *line = NULL, *cp; 129 size_t linesize = 0; 130 struct sshkey *key = NULL; 131 int lnum = 0, r, ret = -1; 132 133 while (getline(&line, &linesize, stdin) != -1) { 134 lnum++; 135 sshkey_free(key); 136 key = NULL; 137 line[strcspn(line, "\n")] = '\0'; 138 cp = line + strspn(line, " \t"); 139 if (*cp == '#' || *cp == '\0') 140 continue; 141 if ((key = sshkey_new(KEY_UNSPEC)) == NULL) 142 fatal_f("sshkey_new"); 143 if ((r = sshkey_read(key, &cp)) != 0) { 144 error_r(r, "(stdin):%d: invalid key", lnum); 145 continue; 146 } 147 if (delete_one(agent_fd, key, cp, "(stdin)", qflag) == 0) 148 ret = 0; 149 } 150 sshkey_free(key); 151 free(line); 152 return ret; 153 } 154 155 static int 156 delete_file(int agent_fd, const char *filename, int key_only, int qflag) 157 { 158 struct sshkey *public, *cert = NULL; 159 char *certpath = NULL, *comment = NULL; 160 int r, ret = -1; 161 162 if (strcmp(filename, "-") == 0) 163 return delete_stdin(agent_fd, qflag); 164 165 if ((r = sshkey_load_public(filename, &public, &comment)) != 0) { 166 printf("Bad key file %s: %s\n", filename, ssh_err(r)); 167 return -1; 168 } 169 if (delete_one(agent_fd, public, comment, filename, qflag) == 0) 170 ret = 0; 171 172 if (key_only) 173 goto out; 174 175 /* Now try to delete the corresponding certificate too */ 176 free(comment); 177 comment = NULL; 178 xasprintf(&certpath, "%s-cert.pub", filename); 179 if ((r = sshkey_load_public(certpath, &cert, &comment)) != 0) { 180 if (r != SSH_ERR_SYSTEM_ERROR || errno != ENOENT) 181 error_r(r, "Failed to load certificate \"%s\"", certpath); 182 goto out; 183 } 184 185 if (!sshkey_equal_public(cert, public)) 186 fatal("Certificate %s does not match private key %s", 187 certpath, filename); 188 189 if (delete_one(agent_fd, cert, comment, certpath, qflag) == 0) 190 ret = 0; 191 192 out: 193 sshkey_free(cert); 194 sshkey_free(public); 195 free(certpath); 196 free(comment); 197 198 return ret; 199 } 200 201 /* Send a request to remove all identities. */ 202 static int 203 delete_all(int agent_fd, int qflag) 204 { 205 int ret = -1; 206 207 /* 208 * Since the agent might be forwarded, old or non-OpenSSH, when asked 209 * to remove all keys, attempt to remove both protocol v.1 and v.2 210 * keys. 211 */ 212 if (ssh_remove_all_identities(agent_fd, 2) == 0) 213 ret = 0; 214 /* ignore error-code for ssh1 */ 215 ssh_remove_all_identities(agent_fd, 1); 216 217 if (ret != 0) 218 fprintf(stderr, "Failed to remove all identities.\n"); 219 else if (!qflag) 220 fprintf(stderr, "All identities removed.\n"); 221 222 return ret; 223 } 224 225 static int 226 add_file(int agent_fd, const char *filename, int key_only, int qflag, 227 const char *skprovider) 228 { 229 struct sshkey *private, *cert; 230 char *comment = NULL; 231 char msg[1024], *certpath = NULL; 232 int r, fd, ret = -1; 233 size_t i; 234 u_int32_t left; 235 struct sshbuf *keyblob; 236 struct ssh_identitylist *idlist; 237 238 if (strcmp(filename, "-") == 0) { 239 fd = STDIN_FILENO; 240 filename = "(stdin)"; 241 } else if ((fd = open(filename, O_RDONLY)) == -1) { 242 perror(filename); 243 return -1; 244 } 245 246 /* 247 * Since we'll try to load a keyfile multiple times, permission errors 248 * will occur multiple times, so check perms first and bail if wrong. 249 */ 250 if (fd != STDIN_FILENO) { 251 if (sshkey_perm_ok(fd, filename) != 0) { 252 close(fd); 253 return -1; 254 } 255 } 256 if ((r = sshbuf_load_fd(fd, &keyblob)) != 0) { 257 fprintf(stderr, "Error loading key \"%s\": %s\n", 258 filename, ssh_err(r)); 259 sshbuf_free(keyblob); 260 close(fd); 261 return -1; 262 } 263 close(fd); 264 265 /* At first, try empty passphrase */ 266 if ((r = sshkey_parse_private_fileblob(keyblob, "", &private, 267 &comment)) != 0 && r != SSH_ERR_KEY_WRONG_PASSPHRASE) { 268 fprintf(stderr, "Error loading key \"%s\": %s\n", 269 filename, ssh_err(r)); 270 goto fail_load; 271 } 272 /* try last */ 273 if (private == NULL && pass != NULL) { 274 if ((r = sshkey_parse_private_fileblob(keyblob, pass, &private, 275 &comment)) != 0 && r != SSH_ERR_KEY_WRONG_PASSPHRASE) { 276 fprintf(stderr, "Error loading key \"%s\": %s\n", 277 filename, ssh_err(r)); 278 goto fail_load; 279 } 280 } 281 if (private == NULL) { 282 /* clear passphrase since it did not work */ 283 clear_pass(); 284 snprintf(msg, sizeof msg, "Enter passphrase for %s%s: ", 285 filename, confirm ? " (will confirm each use)" : ""); 286 for (;;) { 287 pass = read_passphrase(msg, RP_ALLOW_STDIN); 288 if (strcmp(pass, "") == 0) 289 goto fail_load; 290 if ((r = sshkey_parse_private_fileblob(keyblob, pass, 291 &private, &comment)) == 0) 292 break; 293 else if (r != SSH_ERR_KEY_WRONG_PASSPHRASE) { 294 fprintf(stderr, 295 "Error loading key \"%s\": %s\n", 296 filename, ssh_err(r)); 297 fail_load: 298 clear_pass(); 299 sshbuf_free(keyblob); 300 return -1; 301 } 302 clear_pass(); 303 snprintf(msg, sizeof msg, 304 "Bad passphrase, try again for %s%s: ", filename, 305 confirm ? " (will confirm each use)" : ""); 306 } 307 } 308 if (comment == NULL || *comment == '\0') 309 comment = xstrdup(filename); 310 sshbuf_free(keyblob); 311 312 /* For XMSS */ 313 if ((r = sshkey_set_filename(private, filename)) != 0) { 314 fprintf(stderr, "Could not add filename to private key: %s (%s)\n", 315 filename, comment); 316 goto out; 317 } 318 if (maxsign && minleft && 319 (r = ssh_fetch_identitylist(agent_fd, &idlist)) == 0) { 320 for (i = 0; i < idlist->nkeys; i++) { 321 if (!sshkey_equal_public(idlist->keys[i], private)) 322 continue; 323 left = sshkey_signatures_left(idlist->keys[i]); 324 if (left < minleft) { 325 fprintf(stderr, 326 "Only %d signatures left.\n", left); 327 break; 328 } 329 fprintf(stderr, "Skipping update: "); 330 if (left == minleft) { 331 fprintf(stderr, 332 "required signatures left (%d).\n", left); 333 } else { 334 fprintf(stderr, 335 "more signatures left (%d) than" 336 " required (%d).\n", left, minleft); 337 } 338 ssh_free_identitylist(idlist); 339 goto out; 340 } 341 ssh_free_identitylist(idlist); 342 } 343 344 if (sshkey_is_sk(private)) { 345 if (skprovider == NULL) { 346 fprintf(stderr, "Cannot load FIDO key %s " 347 "without provider\n", filename); 348 goto out; 349 } 350 if ((private->sk_flags & SSH_SK_USER_VERIFICATION_REQD) != 0) { 351 fprintf(stderr, "FIDO verify-required key %s is not " 352 "currently supported by ssh-agent\n", filename); 353 goto out; 354 } 355 } else { 356 /* Don't send provider constraint for other keys */ 357 skprovider = NULL; 358 } 359 360 if ((r = ssh_add_identity_constrained(agent_fd, private, comment, 361 lifetime, confirm, maxsign, skprovider)) == 0) { 362 ret = 0; 363 if (!qflag) { 364 fprintf(stderr, "Identity added: %s (%s)\n", 365 filename, comment); 366 if (lifetime != 0) { 367 fprintf(stderr, 368 "Lifetime set to %d seconds\n", lifetime); 369 } 370 if (confirm != 0) { 371 fprintf(stderr, "The user must confirm " 372 "each use of the key\n"); 373 } 374 } 375 } else { 376 fprintf(stderr, "Could not add identity \"%s\": %s\n", 377 filename, ssh_err(r)); 378 } 379 380 /* Skip trying to load the cert if requested */ 381 if (key_only) 382 goto out; 383 384 /* Now try to add the certificate flavour too */ 385 xasprintf(&certpath, "%s-cert.pub", filename); 386 if ((r = sshkey_load_public(certpath, &cert, NULL)) != 0) { 387 if (r != SSH_ERR_SYSTEM_ERROR || errno != ENOENT) 388 error_r(r, "Failed to load certificate \"%s\"", certpath); 389 goto out; 390 } 391 392 if (!sshkey_equal_public(cert, private)) { 393 error("Certificate %s does not match private key %s", 394 certpath, filename); 395 sshkey_free(cert); 396 goto out; 397 } 398 399 /* Graft with private bits */ 400 if ((r = sshkey_to_certified(private)) != 0) { 401 error_fr(r, "sshkey_to_certified"); 402 sshkey_free(cert); 403 goto out; 404 } 405 if ((r = sshkey_cert_copy(cert, private)) != 0) { 406 error_fr(r, "sshkey_cert_copy"); 407 sshkey_free(cert); 408 goto out; 409 } 410 sshkey_free(cert); 411 412 if ((r = ssh_add_identity_constrained(agent_fd, private, comment, 413 lifetime, confirm, maxsign, skprovider)) != 0) { 414 error_r(r, "Certificate %s (%s) add failed", certpath, 415 private->cert->key_id); 416 goto out; 417 } 418 /* success */ 419 if (!qflag) { 420 fprintf(stderr, "Certificate added: %s (%s)\n", certpath, 421 private->cert->key_id); 422 if (lifetime != 0) { 423 fprintf(stderr, "Lifetime set to %d seconds\n", 424 lifetime); 425 } 426 if (confirm != 0) { 427 fprintf(stderr, "The user must confirm each use " 428 "of the key\n"); 429 } 430 } 431 432 out: 433 free(certpath); 434 free(comment); 435 sshkey_free(private); 436 437 return ret; 438 } 439 440 static int 441 update_card(int agent_fd, int add, const char *id, int qflag) 442 { 443 char *pin = NULL; 444 int r, ret = -1; 445 446 if (add) { 447 if ((pin = read_passphrase("Enter passphrase for PKCS#11: ", 448 RP_ALLOW_STDIN)) == NULL) 449 return -1; 450 } 451 452 if ((r = ssh_update_card(agent_fd, add, id, pin == NULL ? "" : pin, 453 lifetime, confirm)) == 0) { 454 ret = 0; 455 if (!qflag) { 456 fprintf(stderr, "Card %s: %s\n", 457 add ? "added" : "removed", id); 458 } 459 } else { 460 fprintf(stderr, "Could not %s card \"%s\": %s\n", 461 add ? "add" : "remove", id, ssh_err(r)); 462 ret = -1; 463 } 464 free(pin); 465 return ret; 466 } 467 468 static int 469 test_key(int agent_fd, const char *filename) 470 { 471 struct sshkey *key = NULL; 472 u_char *sig = NULL; 473 size_t slen = 0; 474 int r, ret = -1; 475 char data[1024]; 476 477 if ((r = sshkey_load_public(filename, &key, NULL)) != 0) { 478 error_r(r, "Couldn't read public key %s", filename); 479 return -1; 480 } 481 arc4random_buf(data, sizeof(data)); 482 if ((r = ssh_agent_sign(agent_fd, key, &sig, &slen, data, sizeof(data), 483 NULL, 0)) != 0) { 484 error_r(r, "Agent signature failed for %s", filename); 485 goto done; 486 } 487 if ((r = sshkey_verify(key, sig, slen, data, sizeof(data), 488 NULL, 0, NULL)) != 0) { 489 error_r(r, "Signature verification failed for %s", filename); 490 goto done; 491 } 492 /* success */ 493 ret = 0; 494 done: 495 free(sig); 496 sshkey_free(key); 497 return ret; 498 } 499 500 static int 501 list_identities(int agent_fd, int do_fp) 502 { 503 char *fp; 504 int r; 505 struct ssh_identitylist *idlist; 506 u_int32_t left; 507 size_t i; 508 509 if ((r = ssh_fetch_identitylist(agent_fd, &idlist)) != 0) { 510 if (r != SSH_ERR_AGENT_NO_IDENTITIES) 511 fprintf(stderr, "error fetching identities: %s\n", 512 ssh_err(r)); 513 else 514 printf("The agent has no identities.\n"); 515 return -1; 516 } 517 for (i = 0; i < idlist->nkeys; i++) { 518 if (do_fp) { 519 fp = sshkey_fingerprint(idlist->keys[i], 520 fingerprint_hash, SSH_FP_DEFAULT); 521 printf("%u %s %s (%s)\n", sshkey_size(idlist->keys[i]), 522 fp == NULL ? "(null)" : fp, idlist->comments[i], 523 sshkey_type(idlist->keys[i])); 524 free(fp); 525 } else { 526 if ((r = sshkey_write(idlist->keys[i], stdout)) != 0) { 527 fprintf(stderr, "sshkey_write: %s\n", 528 ssh_err(r)); 529 continue; 530 } 531 fprintf(stdout, " %s", idlist->comments[i]); 532 left = sshkey_signatures_left(idlist->keys[i]); 533 if (left > 0) 534 fprintf(stdout, 535 " [signatures left %d]", left); 536 fprintf(stdout, "\n"); 537 } 538 } 539 ssh_free_identitylist(idlist); 540 return 0; 541 } 542 543 static int 544 lock_agent(int agent_fd, int lock) 545 { 546 char prompt[100], *p1, *p2; 547 int r, passok = 1, ret = -1; 548 549 strlcpy(prompt, "Enter lock password: ", sizeof(prompt)); 550 p1 = read_passphrase(prompt, RP_ALLOW_STDIN); 551 if (lock) { 552 strlcpy(prompt, "Again: ", sizeof prompt); 553 p2 = read_passphrase(prompt, RP_ALLOW_STDIN); 554 if (strcmp(p1, p2) != 0) { 555 fprintf(stderr, "Passwords do not match.\n"); 556 passok = 0; 557 } 558 freezero(p2, strlen(p2)); 559 } 560 if (passok) { 561 if ((r = ssh_lock_agent(agent_fd, lock, p1)) == 0) { 562 fprintf(stderr, "Agent %slocked.\n", lock ? "" : "un"); 563 ret = 0; 564 } else { 565 fprintf(stderr, "Failed to %slock agent: %s\n", 566 lock ? "" : "un", ssh_err(r)); 567 } 568 } 569 freezero(p1, strlen(p1)); 570 return (ret); 571 } 572 573 static int 574 load_resident_keys(int agent_fd, const char *skprovider, int qflag) 575 { 576 struct sshkey **keys; 577 size_t nkeys, i; 578 int r, ok = 0; 579 char *fp; 580 581 pass = read_passphrase("Enter PIN for authenticator: ", RP_ALLOW_STDIN); 582 if ((r = sshsk_load_resident(skprovider, NULL, pass, 583 &keys, &nkeys)) != 0) { 584 error_r(r, "Unable to load resident keys"); 585 return r; 586 } 587 for (i = 0; i < nkeys; i++) { 588 if ((fp = sshkey_fingerprint(keys[i], 589 fingerprint_hash, SSH_FP_DEFAULT)) == NULL) 590 fatal_f("sshkey_fingerprint failed"); 591 if ((r = ssh_add_identity_constrained(agent_fd, keys[i], "", 592 lifetime, confirm, maxsign, skprovider)) != 0) { 593 error("Unable to add key %s %s", 594 sshkey_type(keys[i]), fp); 595 free(fp); 596 ok = r; 597 continue; 598 } 599 if (ok == 0) 600 ok = 1; 601 if (!qflag) { 602 fprintf(stderr, "Resident identity added: %s %s\n", 603 sshkey_type(keys[i]), fp); 604 if (lifetime != 0) { 605 fprintf(stderr, 606 "Lifetime set to %d seconds\n", lifetime); 607 } 608 if (confirm != 0) { 609 fprintf(stderr, "The user must confirm " 610 "each use of the key\n"); 611 } 612 } 613 free(fp); 614 sshkey_free(keys[i]); 615 } 616 free(keys); 617 if (nkeys == 0) 618 return SSH_ERR_KEY_NOT_FOUND; 619 return ok == 1 ? 0 : ok; 620 } 621 622 static int 623 do_file(int agent_fd, int deleting, int key_only, char *file, int qflag, 624 const char *skprovider) 625 { 626 if (deleting) { 627 if (delete_file(agent_fd, file, key_only, qflag) == -1) 628 return -1; 629 } else { 630 if (add_file(agent_fd, file, key_only, qflag, skprovider) == -1) 631 return -1; 632 } 633 return 0; 634 } 635 636 static void 637 usage(void) 638 { 639 fprintf(stderr, 640 "usage: ssh-add [-cDdKkLlqvXx] [-E fingerprint_hash] [-S provider] [-t life]\n" 641 #ifdef WITH_XMSS 642 " [-M maxsign] [-m minleft]\n" 643 #endif 644 " [file ...]\n" 645 " ssh-add -s pkcs11\n" 646 " ssh-add -e pkcs11\n" 647 " ssh-add -T pubkey ...\n" 648 ); 649 } 650 651 int 652 main(int argc, char **argv) 653 { 654 extern char *optarg; 655 extern int optind; 656 int agent_fd; 657 char *pkcs11provider = NULL, *skprovider = NULL; 658 int r, i, ch, deleting = 0, ret = 0, key_only = 0, do_download = 0; 659 int xflag = 0, lflag = 0, Dflag = 0, qflag = 0, Tflag = 0; 660 SyslogFacility log_facility = SYSLOG_FACILITY_AUTH; 661 LogLevel log_level = SYSLOG_LEVEL_INFO; 662 663 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 664 sanitise_stdfd(); 665 666 #ifdef WITH_OPENSSL 667 OpenSSL_add_all_algorithms(); 668 #endif 669 log_init(__progname, log_level, log_facility, 1); 670 671 setvbuf(stdout, NULL, _IOLBF, 0); 672 673 /* First, get a connection to the authentication agent. */ 674 switch (r = ssh_get_authentication_socket(&agent_fd)) { 675 case 0: 676 break; 677 case SSH_ERR_AGENT_NOT_PRESENT: 678 fprintf(stderr, "Could not open a connection to your " 679 "authentication agent.\n"); 680 exit(2); 681 default: 682 fprintf(stderr, "Error connecting to agent: %s\n", ssh_err(r)); 683 exit(2); 684 } 685 686 skprovider = getenv("SSH_SK_PROVIDER"); 687 688 while ((ch = getopt(argc, argv, "vkKlLcdDTxXE:e:M:m:qs:S:t:")) != -1) { 689 switch (ch) { 690 case 'v': 691 if (log_level == SYSLOG_LEVEL_INFO) 692 log_level = SYSLOG_LEVEL_DEBUG1; 693 else if (log_level < SYSLOG_LEVEL_DEBUG3) 694 log_level++; 695 break; 696 case 'E': 697 fingerprint_hash = ssh_digest_alg_by_name(optarg); 698 if (fingerprint_hash == -1) 699 fatal("Invalid hash algorithm \"%s\"", optarg); 700 break; 701 case 'k': 702 key_only = 1; 703 break; 704 case 'K': 705 do_download = 1; 706 break; 707 case 'l': 708 case 'L': 709 if (lflag != 0) 710 fatal("-%c flag already specified", lflag); 711 lflag = ch; 712 break; 713 case 'x': 714 case 'X': 715 if (xflag != 0) 716 fatal("-%c flag already specified", xflag); 717 xflag = ch; 718 break; 719 case 'c': 720 confirm = 1; 721 break; 722 case 'm': 723 minleft = (int)strtonum(optarg, 1, UINT_MAX, NULL); 724 if (minleft == 0) { 725 usage(); 726 ret = 1; 727 goto done; 728 } 729 break; 730 case 'M': 731 maxsign = (int)strtonum(optarg, 1, UINT_MAX, NULL); 732 if (maxsign == 0) { 733 usage(); 734 ret = 1; 735 goto done; 736 } 737 break; 738 case 'd': 739 deleting = 1; 740 break; 741 case 'D': 742 Dflag = 1; 743 break; 744 case 's': 745 pkcs11provider = optarg; 746 break; 747 case 'S': 748 skprovider = optarg; 749 break; 750 case 'e': 751 deleting = 1; 752 pkcs11provider = optarg; 753 break; 754 case 't': 755 if ((lifetime = convtime(optarg)) == -1 || 756 lifetime < 0 || (u_long)lifetime > UINT32_MAX) { 757 fprintf(stderr, "Invalid lifetime\n"); 758 ret = 1; 759 goto done; 760 } 761 break; 762 case 'q': 763 qflag = 1; 764 break; 765 case 'T': 766 Tflag = 1; 767 break; 768 default: 769 usage(); 770 ret = 1; 771 goto done; 772 } 773 } 774 log_init(__progname, log_level, log_facility, 1); 775 776 if ((xflag != 0) + (lflag != 0) + (Dflag != 0) > 1) 777 fatal("Invalid combination of actions"); 778 else if (xflag) { 779 if (lock_agent(agent_fd, xflag == 'x' ? 1 : 0) == -1) 780 ret = 1; 781 goto done; 782 } else if (lflag) { 783 if (list_identities(agent_fd, lflag == 'l' ? 1 : 0) == -1) 784 ret = 1; 785 goto done; 786 } else if (Dflag) { 787 if (delete_all(agent_fd, qflag) == -1) 788 ret = 1; 789 goto done; 790 } 791 792 if (skprovider == NULL) 793 skprovider = "internal"; 794 795 argc -= optind; 796 argv += optind; 797 if (Tflag) { 798 if (argc <= 0) 799 fatal("no keys to test"); 800 for (r = i = 0; i < argc; i++) 801 r |= test_key(agent_fd, argv[i]); 802 ret = r == 0 ? 0 : 1; 803 goto done; 804 } 805 if (pkcs11provider != NULL) { 806 if (update_card(agent_fd, !deleting, pkcs11provider, 807 qflag) == -1) 808 ret = 1; 809 goto done; 810 } 811 if (do_download) { 812 if (skprovider == NULL) 813 fatal("Cannot download keys without provider"); 814 if (load_resident_keys(agent_fd, skprovider, qflag) != 0) 815 ret = 1; 816 goto done; 817 } 818 if (argc == 0) { 819 char buf[PATH_MAX]; 820 struct passwd *pw; 821 struct stat st; 822 int count = 0; 823 824 if ((pw = getpwuid(getuid())) == NULL) { 825 fprintf(stderr, "No user found with uid %u\n", 826 (u_int)getuid()); 827 ret = 1; 828 goto done; 829 } 830 831 for (i = 0; default_files[i]; i++) { 832 snprintf(buf, sizeof(buf), "%s/%s", pw->pw_dir, 833 default_files[i]); 834 if (stat(buf, &st) == -1) 835 continue; 836 if (do_file(agent_fd, deleting, key_only, buf, 837 qflag, skprovider) == -1) 838 ret = 1; 839 else 840 count++; 841 } 842 if (count == 0) 843 ret = 1; 844 } else { 845 for (i = 0; i < argc; i++) { 846 if (do_file(agent_fd, deleting, key_only, 847 argv[i], qflag, skprovider) == -1) 848 ret = 1; 849 } 850 } 851 done: 852 clear_pass(); 853 ssh_close_authentication_socket(agent_fd); 854 return ret; 855 } 856