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