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