vendor/openssh: upgrade from 8.0p1 to 8.3p1
[dragonfly.git] / crypto / openssh / ssh-add.c
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 }