1 /* $NetBSD: ssh-add.c,v 1.20 2019/10/12 18:32:22 christos Exp $ */ 2 /* $OpenBSD: ssh-add.c,v 1.141 2019/09/06 05:23:55 djm Exp $ */ 3 /* 4 * Author: Tatu Ylonen <ylo@cs.hut.fi> 5 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 6 * All rights reserved 7 * Adds an identity to the authentication server, or removes an identity. 8 * 9 * As far as I am concerned, the code I have written for this software 10 * can be used freely for any purpose. Any derived versions of this 11 * software must be clearly marked as such, and if the derived work is 12 * incompatible with the protocol description in the RFC file, it must be 13 * called by a name other than "ssh" or "Secure Shell". 14 * 15 * SSH2 implementation, 16 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 17 * 18 * Redistribution and use in source and binary forms, with or without 19 * modification, are permitted provided that the following conditions 20 * are met: 21 * 1. Redistributions of source code must retain the above copyright 22 * notice, this list of conditions and the following disclaimer. 23 * 2. Redistributions in binary form must reproduce the above copyright 24 * notice, this list of conditions and the following disclaimer in the 25 * documentation and/or other materials provided with the distribution. 26 * 27 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 28 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 29 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 30 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 31 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 32 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 33 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 34 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 35 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 36 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include "includes.h" 40 __RCSID("$NetBSD: ssh-add.c,v 1.20 2019/10/12 18:32:22 christos Exp $"); 41 #include <sys/types.h> 42 #include <sys/stat.h> 43 44 #ifdef WITH_OPENSSL 45 #include <openssl/evp.h> 46 #endif 47 48 #include <errno.h> 49 #include <fcntl.h> 50 #include <pwd.h> 51 #include <stdio.h> 52 #include <stdlib.h> 53 #include <string.h> 54 #include <unistd.h> 55 #include <limits.h> 56 57 #include "xmalloc.h" 58 #include "ssh.h" 59 #include "log.h" 60 #include "sshkey.h" 61 #include "sshbuf.h" 62 #include "authfd.h" 63 #include "authfile.h" 64 #include "pathnames.h" 65 #include "misc.h" 66 #include "ssherr.h" 67 #include "digest.h" 68 69 /* argv0 */ 70 extern char *__progname; 71 72 /* Default files to add */ 73 static const 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_ED25519, 78 _PATH_SSH_CLIENT_ID_XMSS, 79 NULL 80 }; 81 82 static int fingerprint_hash = SSH_FP_HASH_DEFAULT; 83 84 /* Default lifetime (0 == forever) */ 85 static int lifetime = 0; 86 87 /* User has to confirm key use */ 88 static int confirm = 0; 89 90 /* Maximum number of signatures (XMSS) */ 91 static u_int maxsign = 0; 92 static u_int minleft = 0; 93 94 /* we keep a cache of one passphrase */ 95 static char *pass = NULL; 96 static void 97 clear_pass(void) 98 { 99 if (pass) { 100 explicit_bzero(pass, strlen(pass)); 101 free(pass); 102 pass = NULL; 103 } 104 } 105 106 static int 107 delete_file(int agent_fd, const char *filename, int key_only, int qflag) 108 { 109 struct sshkey *public, *cert = NULL; 110 char *certpath = NULL, *comment = NULL; 111 int r, ret = -1; 112 113 if ((r = sshkey_load_public(filename, &public, &comment)) != 0) { 114 printf("Bad key file %s: %s\n", filename, ssh_err(r)); 115 return -1; 116 } 117 if ((r = ssh_remove_identity(agent_fd, public)) == 0) { 118 if (!qflag) { 119 fprintf(stderr, "Identity removed: %s (%s)\n", 120 filename, comment); 121 } 122 ret = 0; 123 } else 124 fprintf(stderr, "Could not remove identity \"%s\": %s\n", 125 filename, ssh_err(r)); 126 127 if (key_only) 128 goto out; 129 130 /* Now try to delete the corresponding certificate too */ 131 free(comment); 132 comment = NULL; 133 xasprintf(&certpath, "%s-cert.pub", filename); 134 if ((r = sshkey_load_public(certpath, &cert, &comment)) != 0) { 135 if (r != SSH_ERR_SYSTEM_ERROR || errno != ENOENT) 136 error("Failed to load certificate \"%s\": %s", 137 certpath, ssh_err(r)); 138 goto out; 139 } 140 141 if (!sshkey_equal_public(cert, public)) 142 fatal("Certificate %s does not match private key %s", 143 certpath, filename); 144 145 if ((r = ssh_remove_identity(agent_fd, cert)) == 0) { 146 if (!qflag) { 147 fprintf(stderr, "Identity removed: %s (%s)\n", 148 certpath, comment); 149 } 150 ret = 0; 151 } else 152 fprintf(stderr, "Could not remove identity \"%s\": %s\n", 153 certpath, ssh_err(r)); 154 155 out: 156 sshkey_free(cert); 157 sshkey_free(public); 158 free(certpath); 159 free(comment); 160 161 return ret; 162 } 163 164 /* Send a request to remove all identities. */ 165 static int 166 delete_all(int agent_fd, int qflag) 167 { 168 int ret = -1; 169 170 /* 171 * Since the agent might be forwarded, old or non-OpenSSH, when asked 172 * to remove all keys, attempt to remove both protocol v.1 and v.2 173 * keys. 174 */ 175 if (ssh_remove_all_identities(agent_fd, 2) == 0) 176 ret = 0; 177 /* ignore error-code for ssh1 */ 178 ssh_remove_all_identities(agent_fd, 1); 179 180 if (ret != 0) 181 fprintf(stderr, "Failed to remove all identities.\n"); 182 else if (!qflag) 183 fprintf(stderr, "All identities removed.\n"); 184 185 return ret; 186 } 187 188 static int 189 add_file(int agent_fd, const char *filename, int key_only, int qflag) 190 { 191 struct sshkey *private, *cert; 192 char *comment = NULL; 193 char msg[1024], *certpath = NULL; 194 int r, fd, ret = -1; 195 size_t i; 196 u_int32_t left; 197 struct sshbuf *keyblob; 198 struct ssh_identitylist *idlist; 199 200 if (strcmp(filename, "-") == 0) { 201 fd = STDIN_FILENO; 202 filename = "(stdin)"; 203 } else if ((fd = open(filename, O_RDONLY)) == -1) { 204 perror(filename); 205 return -1; 206 } 207 208 /* 209 * Since we'll try to load a keyfile multiple times, permission errors 210 * will occur multiple times, so check perms first and bail if wrong. 211 */ 212 if (fd != STDIN_FILENO) { 213 if (sshkey_perm_ok(fd, filename) != 0) { 214 close(fd); 215 return -1; 216 } 217 } 218 if ((keyblob = sshbuf_new()) == NULL) 219 fatal("%s: sshbuf_new failed", __func__); 220 if ((r = sshkey_load_file(fd, keyblob)) != 0) { 221 fprintf(stderr, "Error loading key \"%s\": %s\n", 222 filename, ssh_err(r)); 223 sshbuf_free(keyblob); 224 close(fd); 225 return -1; 226 } 227 close(fd); 228 229 /* At first, try empty passphrase */ 230 if ((r = sshkey_parse_private_fileblob(keyblob, "", &private, 231 &comment)) != 0 && r != SSH_ERR_KEY_WRONG_PASSPHRASE) { 232 fprintf(stderr, "Error loading key \"%s\": %s\n", 233 filename, ssh_err(r)); 234 goto fail_load; 235 } 236 /* try last */ 237 if (private == NULL && pass != NULL) { 238 if ((r = sshkey_parse_private_fileblob(keyblob, pass, &private, 239 &comment)) != 0 && r != SSH_ERR_KEY_WRONG_PASSPHRASE) { 240 fprintf(stderr, "Error loading key \"%s\": %s\n", 241 filename, ssh_err(r)); 242 goto fail_load; 243 } 244 } 245 if (private == NULL) { 246 /* clear passphrase since it did not work */ 247 clear_pass(); 248 snprintf(msg, sizeof msg, "Enter passphrase for %s%s: ", 249 filename, confirm ? " (will confirm each use)" : ""); 250 for (;;) { 251 pass = read_passphrase(msg, RP_ALLOW_STDIN); 252 if (strcmp(pass, "") == 0) 253 goto fail_load; 254 if ((r = sshkey_parse_private_fileblob(keyblob, pass, 255 &private, &comment)) == 0) 256 break; 257 else if (r != SSH_ERR_KEY_WRONG_PASSPHRASE) { 258 fprintf(stderr, 259 "Error loading key \"%s\": %s\n", 260 filename, ssh_err(r)); 261 fail_load: 262 clear_pass(); 263 sshbuf_free(keyblob); 264 return -1; 265 } 266 clear_pass(); 267 snprintf(msg, sizeof msg, 268 "Bad passphrase, try again for %s%s: ", filename, 269 confirm ? " (will confirm each use)" : ""); 270 } 271 } 272 if (comment == NULL || *comment == '\0') 273 comment = xstrdup(filename); 274 sshbuf_free(keyblob); 275 276 /* For XMSS */ 277 if ((r = sshkey_set_filename(private, filename)) != 0) { 278 fprintf(stderr, "Could not add filename to private key: %s (%s)\n", 279 filename, comment); 280 goto out; 281 } 282 if (maxsign && minleft && 283 (r = ssh_fetch_identitylist(agent_fd, &idlist)) == 0) { 284 for (i = 0; i < idlist->nkeys; i++) { 285 if (!sshkey_equal_public(idlist->keys[i], private)) 286 continue; 287 left = sshkey_signatures_left(idlist->keys[i]); 288 if (left < minleft) { 289 fprintf(stderr, 290 "Only %d signatures left.\n", left); 291 break; 292 } 293 fprintf(stderr, "Skipping update: "); 294 if (left == minleft) { 295 fprintf(stderr, 296 "required signatures left (%d).\n", left); 297 } else { 298 fprintf(stderr, 299 "more signatures left (%d) than" 300 " required (%d).\n", left, minleft); 301 } 302 ssh_free_identitylist(idlist); 303 goto out; 304 } 305 ssh_free_identitylist(idlist); 306 } 307 308 if ((r = ssh_add_identity_constrained(agent_fd, private, comment, 309 lifetime, confirm, maxsign)) == 0) { 310 ret = 0; 311 if (!qflag) { 312 fprintf(stderr, "Identity added: %s (%s)\n", 313 filename, comment); 314 if (lifetime != 0) { 315 fprintf(stderr, 316 "Lifetime set to %d seconds\n", lifetime); 317 } 318 if (confirm != 0) { 319 fprintf(stderr, "The user must confirm " 320 "each use of the key\n"); 321 } 322 } 323 } else { 324 fprintf(stderr, "Could not add identity \"%s\": %s\n", 325 filename, ssh_err(r)); 326 } 327 328 /* Skip trying to load the cert if requested */ 329 if (key_only) 330 goto out; 331 332 /* Now try to add the certificate flavour too */ 333 xasprintf(&certpath, "%s-cert.pub", filename); 334 if ((r = sshkey_load_public(certpath, &cert, NULL)) != 0) { 335 if (r != SSH_ERR_SYSTEM_ERROR || errno != ENOENT) 336 error("Failed to load certificate \"%s\": %s", 337 certpath, ssh_err(r)); 338 goto out; 339 } 340 341 if (!sshkey_equal_public(cert, private)) { 342 error("Certificate %s does not match private key %s", 343 certpath, filename); 344 sshkey_free(cert); 345 goto out; 346 } 347 348 /* Graft with private bits */ 349 if ((r = sshkey_to_certified(private)) != 0) { 350 error("%s: sshkey_to_certified: %s", __func__, ssh_err(r)); 351 sshkey_free(cert); 352 goto out; 353 } 354 if ((r = sshkey_cert_copy(cert, private)) != 0) { 355 error("%s: sshkey_cert_copy: %s", __func__, ssh_err(r)); 356 sshkey_free(cert); 357 goto out; 358 } 359 sshkey_free(cert); 360 361 if ((r = ssh_add_identity_constrained(agent_fd, private, comment, 362 lifetime, confirm, maxsign)) != 0) { 363 error("Certificate %s (%s) add failed: %s", certpath, 364 private->cert->key_id, ssh_err(r)); 365 goto out; 366 } 367 /* success */ 368 if (!qflag) { 369 fprintf(stderr, "Certificate added: %s (%s)\n", certpath, 370 private->cert->key_id); 371 if (lifetime != 0) { 372 fprintf(stderr, "Lifetime set to %d seconds\n", 373 lifetime); 374 } 375 if (confirm != 0) { 376 fprintf(stderr, "The user must confirm each use " 377 "of the key\n"); 378 } 379 } 380 381 out: 382 free(certpath); 383 free(comment); 384 sshkey_free(private); 385 386 return ret; 387 } 388 389 static int 390 update_card(int agent_fd, int add, const char *id, int qflag) 391 { 392 char *pin = NULL; 393 int r, ret = -1; 394 395 if (add) { 396 if ((pin = read_passphrase("Enter passphrase for PKCS#11: ", 397 RP_ALLOW_STDIN)) == NULL) 398 return -1; 399 } 400 401 if ((r = ssh_update_card(agent_fd, add, id, pin == NULL ? "" : pin, 402 lifetime, confirm)) == 0) { 403 ret = 0; 404 if (!qflag) { 405 fprintf(stderr, "Card %s: %s\n", 406 add ? "added" : "removed", id); 407 } 408 } else { 409 fprintf(stderr, "Could not %s card \"%s\": %s\n", 410 add ? "add" : "remove", id, ssh_err(r)); 411 ret = -1; 412 } 413 free(pin); 414 return ret; 415 } 416 417 static int 418 test_key(int agent_fd, const char *filename) 419 { 420 struct sshkey *key = NULL; 421 u_char *sig = NULL; 422 size_t slen = 0; 423 int r, ret = -1; 424 u_char data[1024]; 425 426 if ((r = sshkey_load_public(filename, &key, NULL)) != 0) { 427 error("Couldn't read public key %s: %s", filename, ssh_err(r)); 428 return -1; 429 } 430 arc4random_buf(data, sizeof(data)); 431 if ((r = ssh_agent_sign(agent_fd, key, &sig, &slen, data, sizeof(data), 432 NULL, 0)) != 0) { 433 error("Agent signature failed for %s: %s", 434 filename, ssh_err(r)); 435 goto done; 436 } 437 if ((r = sshkey_verify(key, sig, slen, data, sizeof(data), 438 NULL, 0)) != 0) { 439 error("Signature verification failed for %s: %s", 440 filename, ssh_err(r)); 441 goto done; 442 } 443 /* success */ 444 ret = 0; 445 done: 446 free(sig); 447 sshkey_free(key); 448 return ret; 449 } 450 451 static int 452 list_identities(int agent_fd, int do_fp) 453 { 454 char *fp; 455 int r; 456 struct ssh_identitylist *idlist; 457 u_int32_t left; 458 size_t i; 459 460 if ((r = ssh_fetch_identitylist(agent_fd, &idlist)) != 0) { 461 if (r != SSH_ERR_AGENT_NO_IDENTITIES) 462 fprintf(stderr, "error fetching identities: %s\n", 463 ssh_err(r)); 464 else 465 printf("The agent has no identities.\n"); 466 return -1; 467 } 468 for (i = 0; i < idlist->nkeys; i++) { 469 if (do_fp) { 470 fp = sshkey_fingerprint(idlist->keys[i], 471 fingerprint_hash, SSH_FP_DEFAULT); 472 printf("%u %s %s (%s)\n", sshkey_size(idlist->keys[i]), 473 fp == NULL ? "(null)" : fp, idlist->comments[i], 474 sshkey_type(idlist->keys[i])); 475 free(fp); 476 } else { 477 if ((r = sshkey_write(idlist->keys[i], stdout)) != 0) { 478 fprintf(stderr, "sshkey_write: %s\n", 479 ssh_err(r)); 480 continue; 481 } 482 fprintf(stdout, " %s", idlist->comments[i]); 483 left = sshkey_signatures_left(idlist->keys[i]); 484 if (left > 0) 485 fprintf(stdout, 486 " [signatures left %d]", left); 487 fprintf(stdout, "\n"); 488 } 489 } 490 ssh_free_identitylist(idlist); 491 return 0; 492 } 493 494 static int 495 lock_agent(int agent_fd, int lock) 496 { 497 char prompt[100], *p1, *p2; 498 int r, passok = 1, ret = -1; 499 500 strlcpy(prompt, "Enter lock password: ", sizeof(prompt)); 501 p1 = read_passphrase(prompt, RP_ALLOW_STDIN); 502 if (lock) { 503 strlcpy(prompt, "Again: ", sizeof prompt); 504 p2 = read_passphrase(prompt, RP_ALLOW_STDIN); 505 if (strcmp(p1, p2) != 0) { 506 fprintf(stderr, "Passwords do not match.\n"); 507 passok = 0; 508 } 509 explicit_bzero(p2, strlen(p2)); 510 free(p2); 511 } 512 if (passok) { 513 if ((r = ssh_lock_agent(agent_fd, lock, p1)) == 0) { 514 fprintf(stderr, "Agent %slocked.\n", lock ? "" : "un"); 515 ret = 0; 516 } else { 517 fprintf(stderr, "Failed to %slock agent: %s\n", 518 lock ? "" : "un", ssh_err(r)); 519 } 520 } 521 explicit_bzero(p1, strlen(p1)); 522 free(p1); 523 return (ret); 524 } 525 526 static int 527 do_file(int agent_fd, int deleting, int key_only, char *file, int qflag) 528 { 529 if (deleting) { 530 if (delete_file(agent_fd, file, key_only, qflag) == -1) 531 return -1; 532 } else { 533 if (add_file(agent_fd, file, key_only, qflag) == -1) 534 return -1; 535 } 536 return 0; 537 } 538 539 static void 540 usage(void) 541 { 542 fprintf(stderr, "usage: %s [options] [file ...]\n", __progname); 543 fprintf(stderr, "Options:\n"); 544 fprintf(stderr, " -l List fingerprints of all identities.\n"); 545 fprintf(stderr, " -E hash Specify hash algorithm used for fingerprints.\n"); 546 fprintf(stderr, " -L List public key parameters of all identities.\n"); 547 fprintf(stderr, " -k Load only keys and not certificates.\n"); 548 fprintf(stderr, " -c Require confirmation to sign using identities\n"); 549 fprintf(stderr, " -m minleft Maxsign is only changed if less than minleft are left (for XMSS)\n"); 550 fprintf(stderr, " -M maxsign Maximum number of signatures allowed (for XMSS)\n"); 551 fprintf(stderr, " -t life Set lifetime (in seconds) when adding identities.\n"); 552 fprintf(stderr, " -d Delete identity.\n"); 553 fprintf(stderr, " -D Delete all identities.\n"); 554 fprintf(stderr, " -x Lock agent.\n"); 555 fprintf(stderr, " -X Unlock agent.\n"); 556 fprintf(stderr, " -s pkcs11 Add keys from PKCS#11 provider.\n"); 557 fprintf(stderr, " -e pkcs11 Remove keys provided by PKCS#11 provider.\n"); 558 fprintf(stderr, " -T pubkey Test if ssh-agent can access matching private key.\n"); 559 fprintf(stderr, " -q Be quiet after a successful operation.\n"); 560 fprintf(stderr, " -v Be more verbose.\n"); 561 } 562 563 int 564 main(int argc, char **argv) 565 { 566 extern char *optarg; 567 extern int optind; 568 int agent_fd; 569 char *pkcs11provider = NULL; 570 int r, i, ch, deleting = 0, ret = 0, key_only = 0; 571 int xflag = 0, lflag = 0, Dflag = 0, qflag = 0, Tflag = 0; 572 SyslogFacility log_facility = SYSLOG_FACILITY_AUTH; 573 LogLevel log_level = SYSLOG_LEVEL_INFO; 574 575 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 576 sanitise_stdfd(); 577 578 #ifdef WITH_OPENSSL 579 OpenSSL_add_all_algorithms(); 580 #endif 581 log_init(__progname, log_level, log_facility, 1); 582 583 setvbuf(stdout, NULL, _IOLBF, 0); 584 585 /* First, get a connection to the authentication agent. */ 586 switch (r = ssh_get_authentication_socket(&agent_fd)) { 587 case 0: 588 break; 589 case SSH_ERR_AGENT_NOT_PRESENT: 590 fprintf(stderr, "Could not open a connection to your " 591 "authentication agent.\n"); 592 exit(2); 593 default: 594 fprintf(stderr, "Error connecting to agent: %s\n", ssh_err(r)); 595 exit(2); 596 } 597 598 while ((ch = getopt(argc, argv, "vklLcdDTxXE:e:M:m:qs:t:")) != -1) { 599 switch (ch) { 600 case 'v': 601 if (log_level == SYSLOG_LEVEL_INFO) 602 log_level = SYSLOG_LEVEL_DEBUG1; 603 else if (log_level < SYSLOG_LEVEL_DEBUG3) 604 log_level++; 605 break; 606 case 'E': 607 fingerprint_hash = ssh_digest_alg_by_name(optarg); 608 if (fingerprint_hash == -1) 609 fatal("Invalid hash algorithm \"%s\"", optarg); 610 break; 611 case 'k': 612 key_only = 1; 613 break; 614 case 'l': 615 case 'L': 616 if (lflag != 0) 617 fatal("-%c flag already specified", lflag); 618 lflag = ch; 619 break; 620 case 'x': 621 case 'X': 622 if (xflag != 0) 623 fatal("-%c flag already specified", xflag); 624 xflag = ch; 625 break; 626 case 'c': 627 confirm = 1; 628 break; 629 case 'm': 630 minleft = (int)strtonum(optarg, 1, UINT_MAX, NULL); 631 if (minleft == 0) { 632 usage(); 633 ret = 1; 634 goto done; 635 } 636 break; 637 case 'M': 638 maxsign = (int)strtonum(optarg, 1, UINT_MAX, NULL); 639 if (maxsign == 0) { 640 usage(); 641 ret = 1; 642 goto done; 643 } 644 break; 645 case 'd': 646 deleting = 1; 647 break; 648 case 'D': 649 Dflag = 1; 650 break; 651 case 's': 652 pkcs11provider = optarg; 653 break; 654 case 'e': 655 deleting = 1; 656 pkcs11provider = optarg; 657 break; 658 case 't': 659 if ((lifetime = convtime(optarg)) == -1) { 660 fprintf(stderr, "Invalid lifetime\n"); 661 ret = 1; 662 goto done; 663 } 664 break; 665 case 'q': 666 qflag = 1; 667 break; 668 case 'T': 669 Tflag = 1; 670 break; 671 default: 672 usage(); 673 ret = 1; 674 goto done; 675 } 676 } 677 log_init(__progname, log_level, log_facility, 1); 678 679 if ((xflag != 0) + (lflag != 0) + (Dflag != 0) > 1) 680 fatal("Invalid combination of actions"); 681 else if (xflag) { 682 if (lock_agent(agent_fd, xflag == 'x' ? 1 : 0) == -1) 683 ret = 1; 684 goto done; 685 } else if (lflag) { 686 if (list_identities(agent_fd, lflag == 'l' ? 1 : 0) == -1) 687 ret = 1; 688 goto done; 689 } else if (Dflag) { 690 if (delete_all(agent_fd, qflag) == -1) 691 ret = 1; 692 goto done; 693 } 694 695 argc -= optind; 696 argv += optind; 697 if (Tflag) { 698 if (argc <= 0) 699 fatal("no keys to test"); 700 for (r = i = 0; i < argc; i++) 701 r |= test_key(agent_fd, argv[i]); 702 ret = r == 0 ? 0 : 1; 703 goto done; 704 } 705 if (pkcs11provider != NULL) { 706 if (update_card(agent_fd, !deleting, pkcs11provider, 707 qflag) == -1) 708 ret = 1; 709 goto done; 710 } 711 if (argc == 0) { 712 char buf[PATH_MAX]; 713 struct passwd *pw; 714 struct stat st; 715 int count = 0; 716 717 if ((pw = getpwuid(getuid())) == NULL) { 718 fprintf(stderr, "No user found with uid %u\n", 719 (u_int)getuid()); 720 ret = 1; 721 goto done; 722 } 723 724 for (i = 0; default_files[i]; i++) { 725 snprintf(buf, sizeof(buf), "%s/%s", pw->pw_dir, 726 default_files[i]); 727 if (stat(buf, &st) == -1) 728 continue; 729 if (do_file(agent_fd, deleting, key_only, buf, 730 qflag) == -1) 731 ret = 1; 732 else 733 count++; 734 } 735 if (count == 0) 736 ret = 1; 737 } else { 738 for (i = 0; i < argc; i++) { 739 if (do_file(agent_fd, deleting, key_only, 740 argv[i], qflag) == -1) 741 ret = 1; 742 } 743 } 744 clear_pass(); 745 746 done: 747 ssh_close_authentication_socket(agent_fd); 748 return ret; 749 } 750