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