1 /* $OpenBSD: ssh-add.c,v 1.156 2020/06/26 05:04:07 djm 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 68 /* argv0 */ 69 extern char *__progname; 70 71 /* Default files to add */ 72 static char *default_files[] = { 73 _PATH_SSH_CLIENT_ID_RSA, 74 _PATH_SSH_CLIENT_ID_DSA, 75 _PATH_SSH_CLIENT_ID_ECDSA, 76 _PATH_SSH_CLIENT_ID_ECDSA_SK, 77 _PATH_SSH_CLIENT_ID_ED25519, 78 _PATH_SSH_CLIENT_ID_ED25519_SK, 79 _PATH_SSH_CLIENT_ID_XMSS, 80 NULL 81 }; 82 83 static int fingerprint_hash = SSH_FP_HASH_DEFAULT; 84 85 /* Default lifetime (0 == forever) */ 86 static long lifetime = 0; 87 88 /* User has to confirm key use */ 89 static int confirm = 0; 90 91 /* Maximum number of signatures (XMSS) */ 92 static u_int maxsign = 0; 93 static u_int minleft = 0; 94 95 /* we keep a cache of one passphrase */ 96 static char *pass = NULL; 97 static void 98 clear_pass(void) 99 { 100 if (pass) { 101 freezero(pass, strlen(pass)); 102 pass = NULL; 103 } 104 } 105 106 static int 107 delete_one(int agent_fd, const struct sshkey *key, const char *comment, 108 const char *path, int qflag) 109 { 110 int r; 111 112 if ((r = ssh_remove_identity(agent_fd, key)) != 0) { 113 fprintf(stderr, "Could not remove identity \"%s\": %s\n", 114 path, ssh_err(r)); 115 return r; 116 } 117 if (!qflag) { 118 fprintf(stderr, "Identity removed: %s %s (%s)\n", path, 119 sshkey_type(key), comment); 120 } 121 return 0; 122 } 123 124 static int 125 delete_stdin(int agent_fd, int qflag) 126 { 127 char *line = NULL, *cp; 128 size_t linesize = 0; 129 struct sshkey *key = NULL; 130 int lnum = 0, r, ret = -1; 131 132 while (getline(&line, &linesize, stdin) != -1) { 133 lnum++; 134 sshkey_free(key); 135 key = NULL; 136 line[strcspn(line, "\n")] = '\0'; 137 cp = line + strspn(line, " \t"); 138 if (*cp == '#' || *cp == '\0') 139 continue; 140 if ((key = sshkey_new(KEY_UNSPEC)) == NULL) 141 fatal("%s: sshkey_new", __func__); 142 if ((r = sshkey_read(key, &cp)) != 0) { 143 error("(stdin):%d: invalid key: %s", lnum, ssh_err(r)); 144 continue; 145 } 146 if (delete_one(agent_fd, key, cp, "(stdin)", qflag) == 0) 147 ret = 0; 148 } 149 sshkey_free(key); 150 free(line); 151 return ret; 152 } 153 154 static int 155 delete_file(int agent_fd, const char *filename, int key_only, int qflag) 156 { 157 struct sshkey *public, *cert = NULL; 158 char *certpath = NULL, *comment = NULL; 159 int r, ret = -1; 160 161 if (strcmp(filename, "-") == 0) 162 return delete_stdin(agent_fd, qflag); 163 164 if ((r = sshkey_load_public(filename, &public, &comment)) != 0) { 165 printf("Bad key file %s: %s\n", filename, ssh_err(r)); 166 return -1; 167 } 168 if (delete_one(agent_fd, public, comment, filename, qflag) == 0) 169 ret = 0; 170 171 if (key_only) 172 goto out; 173 174 /* Now try to delete the corresponding certificate too */ 175 free(comment); 176 comment = NULL; 177 xasprintf(&certpath, "%s-cert.pub", filename); 178 if ((r = sshkey_load_public(certpath, &cert, &comment)) != 0) { 179 if (r != SSH_ERR_SYSTEM_ERROR || errno != ENOENT) 180 error("Failed to load certificate \"%s\": %s", 181 certpath, ssh_err(r)); 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 skprovider = NULL; /* Don't send constraint for other keys */ 346 else if (skprovider == NULL) { 347 fprintf(stderr, "Cannot load authenticator-hosted key %s " 348 "without provider\n", filename); 349 goto out; 350 } 351 352 if ((r = ssh_add_identity_constrained(agent_fd, private, comment, 353 lifetime, confirm, maxsign, skprovider)) == 0) { 354 ret = 0; 355 if (!qflag) { 356 fprintf(stderr, "Identity added: %s (%s)\n", 357 filename, comment); 358 if (lifetime != 0) { 359 fprintf(stderr, 360 "Lifetime set to %ld seconds\n", lifetime); 361 } 362 if (confirm != 0) { 363 fprintf(stderr, "The user must confirm " 364 "each use of the key\n"); 365 } 366 } 367 } else { 368 fprintf(stderr, "Could not add identity \"%s\": %s\n", 369 filename, ssh_err(r)); 370 } 371 372 /* Skip trying to load the cert if requested */ 373 if (key_only) 374 goto out; 375 376 /* Now try to add the certificate flavour too */ 377 xasprintf(&certpath, "%s-cert.pub", filename); 378 if ((r = sshkey_load_public(certpath, &cert, NULL)) != 0) { 379 if (r != SSH_ERR_SYSTEM_ERROR || errno != ENOENT) 380 error("Failed to load certificate \"%s\": %s", 381 certpath, ssh_err(r)); 382 goto out; 383 } 384 385 if (!sshkey_equal_public(cert, private)) { 386 error("Certificate %s does not match private key %s", 387 certpath, filename); 388 sshkey_free(cert); 389 goto out; 390 } 391 392 /* Graft with private bits */ 393 if ((r = sshkey_to_certified(private)) != 0) { 394 error("%s: sshkey_to_certified: %s", __func__, ssh_err(r)); 395 sshkey_free(cert); 396 goto out; 397 } 398 if ((r = sshkey_cert_copy(cert, private)) != 0) { 399 error("%s: sshkey_cert_copy: %s", __func__, ssh_err(r)); 400 sshkey_free(cert); 401 goto out; 402 } 403 sshkey_free(cert); 404 405 if ((r = ssh_add_identity_constrained(agent_fd, private, comment, 406 lifetime, confirm, maxsign, skprovider)) != 0) { 407 error("Certificate %s (%s) add failed: %s", certpath, 408 private->cert->key_id, ssh_err(r)); 409 goto out; 410 } 411 /* success */ 412 if (!qflag) { 413 fprintf(stderr, "Certificate added: %s (%s)\n", certpath, 414 private->cert->key_id); 415 if (lifetime != 0) { 416 fprintf(stderr, "Lifetime set to %ld seconds\n", 417 lifetime); 418 } 419 if (confirm != 0) { 420 fprintf(stderr, "The user must confirm each use " 421 "of the key\n"); 422 } 423 } 424 425 out: 426 free(certpath); 427 free(comment); 428 sshkey_free(private); 429 430 return ret; 431 } 432 433 static int 434 update_card(int agent_fd, int add, const char *id, int qflag) 435 { 436 char *pin = NULL; 437 int r, ret = -1; 438 439 if (add) { 440 if ((pin = read_passphrase("Enter passphrase for PKCS#11: ", 441 RP_ALLOW_STDIN)) == NULL) 442 return -1; 443 } 444 445 if ((r = ssh_update_card(agent_fd, add, id, pin == NULL ? "" : pin, 446 lifetime, confirm)) == 0) { 447 ret = 0; 448 if (!qflag) { 449 fprintf(stderr, "Card %s: %s\n", 450 add ? "added" : "removed", id); 451 } 452 } else { 453 fprintf(stderr, "Could not %s card \"%s\": %s\n", 454 add ? "add" : "remove", id, ssh_err(r)); 455 ret = -1; 456 } 457 free(pin); 458 return ret; 459 } 460 461 static int 462 test_key(int agent_fd, const char *filename) 463 { 464 struct sshkey *key = NULL; 465 u_char *sig = NULL; 466 size_t slen = 0; 467 int r, ret = -1; 468 char data[1024]; 469 470 if ((r = sshkey_load_public(filename, &key, NULL)) != 0) { 471 error("Couldn't read public key %s: %s", filename, ssh_err(r)); 472 return -1; 473 } 474 arc4random_buf(data, sizeof(data)); 475 if ((r = ssh_agent_sign(agent_fd, key, &sig, &slen, data, sizeof(data), 476 NULL, 0)) != 0) { 477 error("Agent signature failed for %s: %s", 478 filename, ssh_err(r)); 479 goto done; 480 } 481 if ((r = sshkey_verify(key, sig, slen, data, sizeof(data), 482 NULL, 0, NULL)) != 0) { 483 error("Signature verification failed for %s: %s", 484 filename, ssh_err(r)); 485 goto done; 486 } 487 /* success */ 488 ret = 0; 489 done: 490 free(sig); 491 sshkey_free(key); 492 return ret; 493 } 494 495 static int 496 list_identities(int agent_fd, int do_fp) 497 { 498 char *fp; 499 int r; 500 struct ssh_identitylist *idlist; 501 u_int32_t left; 502 size_t i; 503 504 if ((r = ssh_fetch_identitylist(agent_fd, &idlist)) != 0) { 505 if (r != SSH_ERR_AGENT_NO_IDENTITIES) 506 fprintf(stderr, "error fetching identities: %s\n", 507 ssh_err(r)); 508 else 509 printf("The agent has no identities.\n"); 510 return -1; 511 } 512 for (i = 0; i < idlist->nkeys; i++) { 513 if (do_fp) { 514 fp = sshkey_fingerprint(idlist->keys[i], 515 fingerprint_hash, SSH_FP_DEFAULT); 516 printf("%u %s %s (%s)\n", sshkey_size(idlist->keys[i]), 517 fp == NULL ? "(null)" : fp, idlist->comments[i], 518 sshkey_type(idlist->keys[i])); 519 free(fp); 520 } else { 521 if ((r = sshkey_write(idlist->keys[i], stdout)) != 0) { 522 fprintf(stderr, "sshkey_write: %s\n", 523 ssh_err(r)); 524 continue; 525 } 526 fprintf(stdout, " %s", idlist->comments[i]); 527 left = sshkey_signatures_left(idlist->keys[i]); 528 if (left > 0) 529 fprintf(stdout, 530 " [signatures left %d]", left); 531 fprintf(stdout, "\n"); 532 } 533 } 534 ssh_free_identitylist(idlist); 535 return 0; 536 } 537 538 static int 539 lock_agent(int agent_fd, int lock) 540 { 541 char prompt[100], *p1, *p2; 542 int r, passok = 1, ret = -1; 543 544 strlcpy(prompt, "Enter lock password: ", sizeof(prompt)); 545 p1 = read_passphrase(prompt, RP_ALLOW_STDIN); 546 if (lock) { 547 strlcpy(prompt, "Again: ", sizeof prompt); 548 p2 = read_passphrase(prompt, RP_ALLOW_STDIN); 549 if (strcmp(p1, p2) != 0) { 550 fprintf(stderr, "Passwords do not match.\n"); 551 passok = 0; 552 } 553 freezero(p2, strlen(p2)); 554 } 555 if (passok) { 556 if ((r = ssh_lock_agent(agent_fd, lock, p1)) == 0) { 557 fprintf(stderr, "Agent %slocked.\n", lock ? "" : "un"); 558 ret = 0; 559 } else { 560 fprintf(stderr, "Failed to %slock agent: %s\n", 561 lock ? "" : "un", ssh_err(r)); 562 } 563 } 564 freezero(p1, strlen(p1)); 565 return (ret); 566 } 567 568 static int 569 load_resident_keys(int agent_fd, const char *skprovider, int qflag) 570 { 571 struct sshkey **keys; 572 size_t nkeys, i; 573 int r, ok = 0; 574 char *fp; 575 576 pass = read_passphrase("Enter PIN for authenticator: ", RP_ALLOW_STDIN); 577 if ((r = sshsk_load_resident(skprovider, NULL, pass, 578 &keys, &nkeys)) != 0) { 579 error("Unable to load resident keys: %s", ssh_err(r)); 580 return r; 581 } 582 for (i = 0; i < nkeys; i++) { 583 if ((fp = sshkey_fingerprint(keys[i], 584 fingerprint_hash, SSH_FP_DEFAULT)) == NULL) 585 fatal("%s: sshkey_fingerprint failed", __func__); 586 if ((r = ssh_add_identity_constrained(agent_fd, keys[i], "", 587 lifetime, confirm, maxsign, skprovider)) != 0) { 588 error("Unable to add key %s %s", 589 sshkey_type(keys[i]), fp); 590 free(fp); 591 ok = r; 592 continue; 593 } 594 if (ok == 0) 595 ok = 1; 596 if (!qflag) { 597 fprintf(stderr, "Resident identity added: %s %s\n", 598 sshkey_type(keys[i]), fp); 599 if (lifetime != 0) { 600 fprintf(stderr, 601 "Lifetime set to %ld seconds\n", lifetime); 602 } 603 if (confirm != 0) { 604 fprintf(stderr, "The user must confirm " 605 "each use of the key\n"); 606 } 607 } 608 free(fp); 609 sshkey_free(keys[i]); 610 } 611 free(keys); 612 if (nkeys == 0) 613 return SSH_ERR_KEY_NOT_FOUND; 614 return ok == 1 ? 0 : ok; 615 } 616 617 static int 618 do_file(int agent_fd, int deleting, int key_only, char *file, int qflag, 619 const char *skprovider) 620 { 621 if (deleting) { 622 if (delete_file(agent_fd, file, key_only, qflag) == -1) 623 return -1; 624 } else { 625 if (add_file(agent_fd, file, key_only, qflag, skprovider) == -1) 626 return -1; 627 } 628 return 0; 629 } 630 631 static void 632 usage(void) 633 { 634 fprintf(stderr, 635 "usage: ssh-add [-cDdKkLlqvXx] [-E fingerprint_hash] [-S provider] [-t life]\n" 636 #ifdef WITH_XMSS 637 " [-M maxsign] [-m minleft]\n" 638 #endif 639 " [file ...]\n" 640 " ssh-add -s pkcs11\n" 641 " ssh-add -e pkcs11\n" 642 " ssh-add -T pubkey ...\n" 643 ); 644 } 645 646 int 647 main(int argc, char **argv) 648 { 649 extern char *optarg; 650 extern int optind; 651 int agent_fd; 652 char *pkcs11provider = NULL, *skprovider = NULL; 653 int r, i, ch, deleting = 0, ret = 0, key_only = 0, do_download = 0; 654 int xflag = 0, lflag = 0, Dflag = 0, qflag = 0, Tflag = 0; 655 SyslogFacility log_facility = SYSLOG_FACILITY_AUTH; 656 LogLevel log_level = SYSLOG_LEVEL_INFO; 657 658 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 659 sanitise_stdfd(); 660 661 #ifdef WITH_OPENSSL 662 OpenSSL_add_all_algorithms(); 663 #endif 664 log_init(__progname, log_level, log_facility, 1); 665 666 setvbuf(stdout, NULL, _IOLBF, 0); 667 668 /* First, get a connection to the authentication agent. */ 669 switch (r = ssh_get_authentication_socket(&agent_fd)) { 670 case 0: 671 break; 672 case SSH_ERR_AGENT_NOT_PRESENT: 673 fprintf(stderr, "Could not open a connection to your " 674 "authentication agent.\n"); 675 exit(2); 676 default: 677 fprintf(stderr, "Error connecting to agent: %s\n", ssh_err(r)); 678 exit(2); 679 } 680 681 skprovider = getenv("SSH_SK_PROVIDER"); 682 683 while ((ch = getopt(argc, argv, "vkKlLcdDTxXE:e:M:m:qs:S:t:")) != -1) { 684 switch (ch) { 685 case 'v': 686 if (log_level == SYSLOG_LEVEL_INFO) 687 log_level = SYSLOG_LEVEL_DEBUG1; 688 else if (log_level < SYSLOG_LEVEL_DEBUG3) 689 log_level++; 690 break; 691 case 'E': 692 fingerprint_hash = ssh_digest_alg_by_name(optarg); 693 if (fingerprint_hash == -1) 694 fatal("Invalid hash algorithm \"%s\"", optarg); 695 break; 696 case 'k': 697 key_only = 1; 698 break; 699 case 'K': 700 do_download = 1; 701 break; 702 case 'l': 703 case 'L': 704 if (lflag != 0) 705 fatal("-%c flag already specified", lflag); 706 lflag = ch; 707 break; 708 case 'x': 709 case 'X': 710 if (xflag != 0) 711 fatal("-%c flag already specified", xflag); 712 xflag = ch; 713 break; 714 case 'c': 715 confirm = 1; 716 break; 717 case 'm': 718 minleft = (int)strtonum(optarg, 1, UINT_MAX, NULL); 719 if (minleft == 0) { 720 usage(); 721 ret = 1; 722 goto done; 723 } 724 break; 725 case 'M': 726 maxsign = (int)strtonum(optarg, 1, UINT_MAX, NULL); 727 if (maxsign == 0) { 728 usage(); 729 ret = 1; 730 goto done; 731 } 732 break; 733 case 'd': 734 deleting = 1; 735 break; 736 case 'D': 737 Dflag = 1; 738 break; 739 case 's': 740 pkcs11provider = optarg; 741 break; 742 case 'S': 743 skprovider = optarg; 744 break; 745 case 'e': 746 deleting = 1; 747 pkcs11provider = optarg; 748 break; 749 case 't': 750 if ((lifetime = convtime(optarg)) == -1 || 751 lifetime < 0 || (u_long)lifetime > UINT32_MAX) { 752 fprintf(stderr, "Invalid lifetime\n"); 753 ret = 1; 754 goto done; 755 } 756 break; 757 case 'q': 758 qflag = 1; 759 break; 760 case 'T': 761 Tflag = 1; 762 break; 763 default: 764 usage(); 765 ret = 1; 766 goto done; 767 } 768 } 769 log_init(__progname, log_level, log_facility, 1); 770 771 if ((xflag != 0) + (lflag != 0) + (Dflag != 0) > 1) 772 fatal("Invalid combination of actions"); 773 else if (xflag) { 774 if (lock_agent(agent_fd, xflag == 'x' ? 1 : 0) == -1) 775 ret = 1; 776 goto done; 777 } else if (lflag) { 778 if (list_identities(agent_fd, lflag == 'l' ? 1 : 0) == -1) 779 ret = 1; 780 goto done; 781 } else if (Dflag) { 782 if (delete_all(agent_fd, qflag) == -1) 783 ret = 1; 784 goto done; 785 } 786 787 if (skprovider == NULL) 788 skprovider = "internal"; 789 790 argc -= optind; 791 argv += optind; 792 if (Tflag) { 793 if (argc <= 0) 794 fatal("no keys to test"); 795 for (r = i = 0; i < argc; i++) 796 r |= test_key(agent_fd, argv[i]); 797 ret = r == 0 ? 0 : 1; 798 goto done; 799 } 800 if (pkcs11provider != NULL) { 801 if (update_card(agent_fd, !deleting, pkcs11provider, 802 qflag) == -1) 803 ret = 1; 804 goto done; 805 } 806 if (do_download) { 807 if (skprovider == NULL) 808 fatal("Cannot download keys without provider"); 809 if (load_resident_keys(agent_fd, skprovider, qflag) != 0) 810 ret = 1; 811 goto done; 812 } 813 if (argc == 0) { 814 char buf[PATH_MAX]; 815 struct passwd *pw; 816 struct stat st; 817 int count = 0; 818 819 if ((pw = getpwuid(getuid())) == NULL) { 820 fprintf(stderr, "No user found with uid %u\n", 821 (u_int)getuid()); 822 ret = 1; 823 goto done; 824 } 825 826 for (i = 0; default_files[i]; i++) { 827 snprintf(buf, sizeof(buf), "%s/%s", pw->pw_dir, 828 default_files[i]); 829 if (stat(buf, &st) == -1) 830 continue; 831 if (do_file(agent_fd, deleting, key_only, buf, 832 qflag, skprovider) == -1) 833 ret = 1; 834 else 835 count++; 836 } 837 if (count == 0) 838 ret = 1; 839 } else { 840 for (i = 0; i < argc; i++) { 841 if (do_file(agent_fd, deleting, key_only, 842 argv[i], qflag, skprovider) == -1) 843 ret = 1; 844 } 845 } 846 done: 847 clear_pass(); 848 ssh_close_authentication_socket(agent_fd); 849 return ret; 850 } 851