]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - crypto/openssh/ssh-add.c
ssh: update to OpenSSH 9.1p1
[FreeBSD/FreeBSD.git] / crypto / openssh / ssh-add.c
1 /* $OpenBSD: ssh-add.c,v 1.166 2022/06/18 02:17:16 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 #include "sk-api.h"
71 #include "hostfile.h"
72
73 /* argv0 */
74 extern char *__progname;
75
76 /* Default files to add */
77 static char *default_files[] = {
78 #ifdef WITH_OPENSSL
79         _PATH_SSH_CLIENT_ID_RSA,
80 #ifdef OPENSSL_HAS_ECC
81         _PATH_SSH_CLIENT_ID_ECDSA,
82         _PATH_SSH_CLIENT_ID_ECDSA_SK,
83 #endif
84 #endif /* WITH_OPENSSL */
85         _PATH_SSH_CLIENT_ID_ED25519,
86         _PATH_SSH_CLIENT_ID_ED25519_SK,
87         _PATH_SSH_CLIENT_ID_XMSS,
88         _PATH_SSH_CLIENT_ID_DSA,
89         NULL
90 };
91
92 static int fingerprint_hash = SSH_FP_HASH_DEFAULT;
93
94 /* Default lifetime (0 == forever) */
95 static int lifetime = 0;
96
97 /* User has to confirm key use */
98 static int confirm = 0;
99
100 /* Maximum number of signatures (XMSS) */
101 static u_int maxsign = 0;
102 static u_int minleft = 0;
103
104 /* we keep a cache of one passphrase */
105 static char *pass = NULL;
106 static void
107 clear_pass(void)
108 {
109         if (pass) {
110                 freezero(pass, strlen(pass));
111                 pass = NULL;
112         }
113 }
114
115 static int
116 delete_one(int agent_fd, const struct sshkey *key, const char *comment,
117     const char *path, int qflag)
118 {
119         int r;
120
121         if ((r = ssh_remove_identity(agent_fd, key)) != 0) {
122                 fprintf(stderr, "Could not remove identity \"%s\": %s\n",
123                     path, ssh_err(r));
124                 return r;
125         }
126         if (!qflag) {
127                 fprintf(stderr, "Identity removed: %s %s (%s)\n", path,
128                     sshkey_type(key), comment ? comment : "no comment");
129         }
130         return 0;
131 }
132
133 static int
134 delete_stdin(int agent_fd, int qflag)
135 {
136         char *line = NULL, *cp;
137         size_t linesize = 0;
138         struct sshkey *key = NULL;
139         int lnum = 0, r, ret = -1;
140
141         while (getline(&line, &linesize, stdin) != -1) {
142                 lnum++;
143                 sshkey_free(key);
144                 key = NULL;
145                 line[strcspn(line, "\n")] = '\0';
146                 cp = line + strspn(line, " \t");
147                 if (*cp == '#' || *cp == '\0')
148                         continue;
149                 if ((key = sshkey_new(KEY_UNSPEC)) == NULL)
150                         fatal_f("sshkey_new");
151                 if ((r = sshkey_read(key, &cp)) != 0) {
152                         error_r(r, "(stdin):%d: invalid key", lnum);
153                         continue;
154                 }
155                 if (delete_one(agent_fd, key, cp, "(stdin)", qflag) == 0)
156                         ret = 0;
157         }
158         sshkey_free(key);
159         free(line);
160         return ret;
161 }
162
163 static int
164 delete_file(int agent_fd, const char *filename, int key_only, int qflag)
165 {
166         struct sshkey *public, *cert = NULL;
167         char *certpath = NULL, *comment = NULL;
168         int r, ret = -1;
169
170         if (strcmp(filename, "-") == 0)
171                 return delete_stdin(agent_fd, qflag);
172
173         if ((r = sshkey_load_public(filename, &public,  &comment)) != 0) {
174                 printf("Bad key file %s: %s\n", filename, ssh_err(r));
175                 return -1;
176         }
177         if (delete_one(agent_fd, public, comment, filename, qflag) == 0)
178                 ret = 0;
179
180         if (key_only)
181                 goto out;
182
183         /* Now try to delete the corresponding certificate too */
184         free(comment);
185         comment = NULL;
186         xasprintf(&certpath, "%s-cert.pub", filename);
187         if ((r = sshkey_load_public(certpath, &cert, &comment)) != 0) {
188                 if (r != SSH_ERR_SYSTEM_ERROR || errno != ENOENT)
189                         error_r(r, "Failed to load certificate \"%s\"", certpath);
190                 goto out;
191         }
192
193         if (!sshkey_equal_public(cert, public))
194                 fatal("Certificate %s does not match private key %s",
195                     certpath, filename);
196
197         if (delete_one(agent_fd, cert, comment, certpath, qflag) == 0)
198                 ret = 0;
199
200  out:
201         sshkey_free(cert);
202         sshkey_free(public);
203         free(certpath);
204         free(comment);
205
206         return ret;
207 }
208
209 /* Send a request to remove all identities. */
210 static int
211 delete_all(int agent_fd, int qflag)
212 {
213         int ret = -1;
214
215         /*
216          * Since the agent might be forwarded, old or non-OpenSSH, when asked
217          * to remove all keys, attempt to remove both protocol v.1 and v.2
218          * keys.
219          */
220         if (ssh_remove_all_identities(agent_fd, 2) == 0)
221                 ret = 0;
222         /* ignore error-code for ssh1 */
223         ssh_remove_all_identities(agent_fd, 1);
224
225         if (ret != 0)
226                 fprintf(stderr, "Failed to remove all identities.\n");
227         else if (!qflag)
228                 fprintf(stderr, "All identities removed.\n");
229
230         return ret;
231 }
232
233 static int
234 add_file(int agent_fd, const char *filename, int key_only, int qflag,
235     const char *skprovider, struct dest_constraint **dest_constraints,
236     size_t ndest_constraints)
237 {
238         struct sshkey *private, *cert;
239         char *comment = NULL;
240         char msg[1024], *certpath = NULL;
241         int r, fd, ret = -1;
242         size_t i;
243         u_int32_t left;
244         struct sshbuf *keyblob;
245         struct ssh_identitylist *idlist;
246
247         if (strcmp(filename, "-") == 0) {
248                 fd = STDIN_FILENO;
249                 filename = "(stdin)";
250         } else if ((fd = open(filename, O_RDONLY)) == -1) {
251                 perror(filename);
252                 return -1;
253         }
254
255         /*
256          * Since we'll try to load a keyfile multiple times, permission errors
257          * will occur multiple times, so check perms first and bail if wrong.
258          */
259         if (fd != STDIN_FILENO) {
260                 if (sshkey_perm_ok(fd, filename) != 0) {
261                         close(fd);
262                         return -1;
263                 }
264         }
265         if ((r = sshbuf_load_fd(fd, &keyblob)) != 0) {
266                 fprintf(stderr, "Error loading key \"%s\": %s\n",
267                     filename, ssh_err(r));
268                 sshbuf_free(keyblob);
269                 close(fd);
270                 return -1;
271         }
272         close(fd);
273
274         /* At first, try empty passphrase */
275         if ((r = sshkey_parse_private_fileblob(keyblob, "", &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         /* try last */
282         if (private == NULL && pass != NULL) {
283                 if ((r = sshkey_parse_private_fileblob(keyblob, pass, &private,
284                     &comment)) != 0 && r != SSH_ERR_KEY_WRONG_PASSPHRASE) {
285                         fprintf(stderr, "Error loading key \"%s\": %s\n",
286                             filename, ssh_err(r));
287                         goto fail_load;
288                 }
289         }
290         if (private == NULL) {
291                 /* clear passphrase since it did not work */
292                 clear_pass();
293                 snprintf(msg, sizeof msg, "Enter passphrase for %s%s: ",
294                     filename, confirm ? " (will confirm each use)" : "");
295                 for (;;) {
296                         pass = read_passphrase(msg, RP_ALLOW_STDIN);
297                         if (strcmp(pass, "") == 0)
298                                 goto fail_load;
299                         if ((r = sshkey_parse_private_fileblob(keyblob, pass,
300                             &private, &comment)) == 0)
301                                 break;
302                         else if (r != SSH_ERR_KEY_WRONG_PASSPHRASE) {
303                                 fprintf(stderr,
304                                     "Error loading key \"%s\": %s\n",
305                                     filename, ssh_err(r));
306  fail_load:
307                                 clear_pass();
308                                 sshbuf_free(keyblob);
309                                 return -1;
310                         }
311                         clear_pass();
312                         snprintf(msg, sizeof msg,
313                             "Bad passphrase, try again for %s%s: ", filename,
314                             confirm ? " (will confirm each use)" : "");
315                 }
316         }
317         if (comment == NULL || *comment == '\0')
318                 comment = xstrdup(filename);
319         sshbuf_free(keyblob);
320
321         /* For XMSS */
322         if ((r = sshkey_set_filename(private, filename)) != 0) {
323                 fprintf(stderr, "Could not add filename to private key: %s (%s)\n",
324                     filename, comment);
325                 goto out;
326         }
327         if (maxsign && minleft &&
328             (r = ssh_fetch_identitylist(agent_fd, &idlist)) == 0) {
329                 for (i = 0; i < idlist->nkeys; i++) {
330                         if (!sshkey_equal_public(idlist->keys[i], private))
331                                 continue;
332                         left = sshkey_signatures_left(idlist->keys[i]);
333                         if (left < minleft) {
334                                 fprintf(stderr,
335                                     "Only %d signatures left.\n", left);
336                                 break;
337                         }
338                         fprintf(stderr, "Skipping update: ");
339                         if (left == minleft) {
340                                 fprintf(stderr,
341                                     "required signatures left (%d).\n", left);
342                         } else {
343                                 fprintf(stderr,
344                                     "more signatures left (%d) than"
345                                     " required (%d).\n", left, minleft);
346                         }
347                         ssh_free_identitylist(idlist);
348                         goto out;
349                 }
350                 ssh_free_identitylist(idlist);
351         }
352
353         if (sshkey_is_sk(private)) {
354                 if (skprovider == NULL) {
355                         fprintf(stderr, "Cannot load FIDO key %s "
356                             "without provider\n", filename);
357                         goto out;
358                 }
359         } else {
360                 /* Don't send provider constraint for other keys */
361                 skprovider = NULL;
362         }
363
364         if ((r = ssh_add_identity_constrained(agent_fd, private, comment,
365             lifetime, confirm, maxsign, skprovider,
366             dest_constraints, ndest_constraints)) == 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 %d 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_r(r, "Failed to load certificate \"%s\"", certpath);
394                 goto out;
395         }
396
397         if (!sshkey_equal_public(cert, private)) {
398                 error("Certificate %s does not match private key %s",
399                     certpath, filename);
400                 sshkey_free(cert);
401                 goto out;
402         }
403
404         /* Graft with private bits */
405         if ((r = sshkey_to_certified(private)) != 0) {
406                 error_fr(r, "sshkey_to_certified");
407                 sshkey_free(cert);
408                 goto out;
409         }
410         if ((r = sshkey_cert_copy(cert, private)) != 0) {
411                 error_fr(r, "sshkey_cert_copy");
412                 sshkey_free(cert);
413                 goto out;
414         }
415         sshkey_free(cert);
416
417         if ((r = ssh_add_identity_constrained(agent_fd, private, comment,
418             lifetime, confirm, maxsign, skprovider,
419             dest_constraints, ndest_constraints)) != 0) {
420                 error_r(r, "Certificate %s (%s) add failed", certpath,
421                     private->cert->key_id);
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 %d 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     struct dest_constraint **dest_constraints, size_t ndest_constraints)
449 {
450         char *pin = NULL;
451         int r, ret = -1;
452
453         if (add) {
454                 if ((pin = read_passphrase("Enter passphrase for PKCS#11: ",
455                     RP_ALLOW_STDIN)) == NULL)
456                         return -1;
457         }
458
459         if ((r = ssh_update_card(agent_fd, add, id, pin == NULL ? "" : pin,
460             lifetime, confirm, dest_constraints, ndest_constraints)) == 0) {
461                 ret = 0;
462                 if (!qflag) {
463                         fprintf(stderr, "Card %s: %s\n",
464                             add ? "added" : "removed", id);
465                 }
466         } else {
467                 fprintf(stderr, "Could not %s card \"%s\": %s\n",
468                     add ? "add" : "remove", id, ssh_err(r));
469                 ret = -1;
470         }
471         free(pin);
472         return ret;
473 }
474
475 static int
476 test_key(int agent_fd, const char *filename)
477 {
478         struct sshkey *key = NULL;
479         u_char *sig = NULL;
480         size_t slen = 0;
481         int r, ret = -1;
482         char data[1024];
483
484         if ((r = sshkey_load_public(filename, &key, NULL)) != 0) {
485                 error_r(r, "Couldn't read public key %s", filename);
486                 return -1;
487         }
488         arc4random_buf(data, sizeof(data));
489         if ((r = ssh_agent_sign(agent_fd, key, &sig, &slen, data, sizeof(data),
490             NULL, 0)) != 0) {
491                 error_r(r, "Agent signature failed for %s", filename);
492                 goto done;
493         }
494         if ((r = sshkey_verify(key, sig, slen, data, sizeof(data),
495             NULL, 0, NULL)) != 0) {
496                 error_r(r, "Signature verification failed for %s", filename);
497                 goto done;
498         }
499         /* success */
500         ret = 0;
501  done:
502         free(sig);
503         sshkey_free(key);
504         return ret;
505 }
506
507 static int
508 list_identities(int agent_fd, int do_fp)
509 {
510         char *fp;
511         int r;
512         struct ssh_identitylist *idlist;
513         u_int32_t left;
514         size_t i;
515
516         if ((r = ssh_fetch_identitylist(agent_fd, &idlist)) != 0) {
517                 if (r != SSH_ERR_AGENT_NO_IDENTITIES)
518                         fprintf(stderr, "error fetching identities: %s\n",
519                             ssh_err(r));
520                 else
521                         printf("The agent has no identities.\n");
522                 return -1;
523         }
524         for (i = 0; i < idlist->nkeys; i++) {
525                 if (do_fp) {
526                         fp = sshkey_fingerprint(idlist->keys[i],
527                             fingerprint_hash, SSH_FP_DEFAULT);
528                         printf("%u %s %s (%s)\n", sshkey_size(idlist->keys[i]),
529                             fp == NULL ? "(null)" : fp, idlist->comments[i],
530                             sshkey_type(idlist->keys[i]));
531                         free(fp);
532                 } else {
533                         if ((r = sshkey_write(idlist->keys[i], stdout)) != 0) {
534                                 fprintf(stderr, "sshkey_write: %s\n",
535                                     ssh_err(r));
536                                 continue;
537                         }
538                         fprintf(stdout, " %s", idlist->comments[i]);
539                         left = sshkey_signatures_left(idlist->keys[i]);
540                         if (left > 0)
541                                 fprintf(stdout,
542                                     " [signatures left %d]", left);
543                         fprintf(stdout, "\n");
544                 }
545         }
546         ssh_free_identitylist(idlist);
547         return 0;
548 }
549
550 static int
551 lock_agent(int agent_fd, int lock)
552 {
553         char prompt[100], *p1, *p2;
554         int r, passok = 1, ret = -1;
555
556         strlcpy(prompt, "Enter lock password: ", sizeof(prompt));
557         p1 = read_passphrase(prompt, RP_ALLOW_STDIN);
558         if (lock) {
559                 strlcpy(prompt, "Again: ", sizeof prompt);
560                 p2 = read_passphrase(prompt, RP_ALLOW_STDIN);
561                 if (strcmp(p1, p2) != 0) {
562                         fprintf(stderr, "Passwords do not match.\n");
563                         passok = 0;
564                 }
565                 freezero(p2, strlen(p2));
566         }
567         if (passok) {
568                 if ((r = ssh_lock_agent(agent_fd, lock, p1)) == 0) {
569                         fprintf(stderr, "Agent %slocked.\n", lock ? "" : "un");
570                         ret = 0;
571                 } else {
572                         fprintf(stderr, "Failed to %slock agent: %s\n",
573                             lock ? "" : "un", ssh_err(r));
574                 }
575         }
576         freezero(p1, strlen(p1));
577         return (ret);
578 }
579
580 static int
581 load_resident_keys(int agent_fd, const char *skprovider, int qflag,
582     struct dest_constraint **dest_constraints, size_t ndest_constraints)
583 {
584         struct sshsk_resident_key **srks;
585         size_t nsrks, i;
586         struct sshkey *key;
587         int r, ok = 0;
588         char *fp;
589
590         pass = read_passphrase("Enter PIN for authenticator: ", RP_ALLOW_STDIN);
591         if ((r = sshsk_load_resident(skprovider, NULL, pass, 0,
592             &srks, &nsrks)) != 0) {
593                 error_r(r, "Unable to load resident keys");
594                 return r;
595         }
596         for (i = 0; i < nsrks; i++) {
597                 key = srks[i]->key;
598                 if ((fp = sshkey_fingerprint(key,
599                     fingerprint_hash, SSH_FP_DEFAULT)) == NULL)
600                         fatal_f("sshkey_fingerprint failed");
601                 if ((r = ssh_add_identity_constrained(agent_fd, key, "",
602                     lifetime, confirm, maxsign, skprovider,
603                     dest_constraints, ndest_constraints)) != 0) {
604                         error("Unable to add key %s %s",
605                             sshkey_type(key), fp);
606                         free(fp);
607                         ok = r;
608                         continue;
609                 }
610                 if (ok == 0)
611                         ok = 1;
612                 if (!qflag) {
613                         fprintf(stderr, "Resident identity added: %s %s\n",
614                             sshkey_type(key), fp);
615                         if (lifetime != 0) {
616                                 fprintf(stderr,
617                                     "Lifetime set to %d seconds\n", lifetime);
618                         }
619                         if (confirm != 0) {
620                                 fprintf(stderr, "The user must confirm "
621                                     "each use of the key\n");
622                         }
623                 }
624                 free(fp);
625         }
626         sshsk_free_resident_keys(srks, nsrks);
627         if (nsrks == 0)
628                 return SSH_ERR_KEY_NOT_FOUND;
629         return ok == 1 ? 0 : ok;
630 }
631
632 static int
633 do_file(int agent_fd, int deleting, int key_only, char *file, int qflag,
634     const char *skprovider, struct dest_constraint **dest_constraints,
635     size_t ndest_constraints)
636 {
637         if (deleting) {
638                 if (delete_file(agent_fd, file, key_only, qflag) == -1)
639                         return -1;
640         } else {
641                 if (add_file(agent_fd, file, key_only, qflag, skprovider,
642                     dest_constraints, ndest_constraints) == -1)
643                         return -1;
644         }
645         return 0;
646 }
647
648 /* Append string 's' to a NULL-terminated array of strings */
649 static void
650 stringlist_append(char ***listp, const char *s)
651 {
652         size_t i = 0;
653
654         if (*listp == NULL)
655                 *listp = xcalloc(2, sizeof(**listp));
656         else {
657                 for (i = 0; (*listp)[i] != NULL; i++)
658                         ; /* count */
659                 *listp = xrecallocarray(*listp, i + 1, i + 2, sizeof(**listp));
660         }
661         (*listp)[i] = xstrdup(s);
662 }
663
664 static void
665 parse_dest_constraint_hop(const char *s, struct dest_constraint_hop *dch,
666     char **hostkey_files)
667 {
668         char *user = NULL, *host, *os, *path;
669         size_t i;
670         struct hostkeys *hostkeys;
671         const struct hostkey_entry *hke;
672         int r, want_ca;
673
674         memset(dch, '\0', sizeof(*dch));
675         os = xstrdup(s);
676         if ((host = strchr(os, '@')) == NULL)
677                 host = os;
678         else {
679                 *host++ = '\0';
680                 user = os;
681         }
682         cleanhostname(host);
683         /* Trivial case: username@ (all hosts) */
684         if (*host == '\0') {
685                 if (user == NULL) {
686                         fatal("Invalid key destination constraint \"%s\": "
687                             "does not specify user or host", s);
688                 }
689                 dch->user = xstrdup(user);
690                 /* other fields left blank */
691                 free(os);
692                 return;
693         }
694         if (hostkey_files == NULL)
695                 fatal_f("no hostkey files");
696         /* Otherwise we need to look up the keys for this hostname */
697         hostkeys = init_hostkeys();
698         for (i = 0; hostkey_files[i]; i++) {
699                 path = tilde_expand_filename(hostkey_files[i], getuid());
700                 debug2_f("looking up host keys for \"%s\" in %s", host, path);
701                 load_hostkeys(hostkeys, host, path, 0);
702                 free(path);
703         }
704         dch->user = user == NULL ? NULL : xstrdup(user);
705         dch->hostname = xstrdup(host);
706         for (i = 0; i < hostkeys->num_entries; i++) {
707                 hke = hostkeys->entries + i;
708                 want_ca = hke->marker == MRK_CA;
709                 if (hke->marker != MRK_NONE && !want_ca)
710                         continue;
711                 debug3_f("%s%s%s: adding %s %skey from %s:%lu as key %u",
712                     user == NULL ? "": user, user == NULL ? "" : "@",
713                     host, sshkey_type(hke->key), want_ca ? "CA " : "",
714                     hke->file, hke->line, dch->nkeys);
715                 dch->keys = xrecallocarray(dch->keys, dch->nkeys,
716                     dch->nkeys + 1, sizeof(*dch->keys));
717                 dch->key_is_ca = xrecallocarray(dch->key_is_ca, dch->nkeys,
718                     dch->nkeys + 1, sizeof(*dch->key_is_ca));
719                 if ((r = sshkey_from_private(hke->key,
720                     &(dch->keys[dch->nkeys]))) != 0)
721                         fatal_fr(r, "sshkey_from_private");
722                 dch->key_is_ca[dch->nkeys] = want_ca;
723                 dch->nkeys++;
724         }
725         if (dch->nkeys == 0)
726                 fatal("No host keys found for destination \"%s\"", host);
727         free_hostkeys(hostkeys);
728         free(os);
729         return;
730 }
731
732 static void
733 parse_dest_constraint(const char *s, struct dest_constraint ***dcp,
734     size_t *ndcp, char **hostkey_files)
735 {
736         struct dest_constraint *dc;
737         char *os, *cp;
738
739         dc = xcalloc(1, sizeof(*dc));
740         os = xstrdup(s);
741         if ((cp = strchr(os, '>')) == NULL) {
742                 /* initial hop; no 'from' hop specified */
743                 parse_dest_constraint_hop(os, &dc->to, hostkey_files);
744         } else {
745                 /* two hops specified */
746                 *(cp++) = '\0';
747                 parse_dest_constraint_hop(os, &dc->from, hostkey_files);
748                 parse_dest_constraint_hop(cp, &dc->to, hostkey_files);
749                 if (dc->from.user != NULL) {
750                         fatal("Invalid key constraint %s: cannot specify "
751                             "user on 'from' host", os);
752                 }
753         }
754         /* XXX eliminate or error on duplicates */
755         debug2_f("constraint %zu: %s%s%s (%u keys) > %s%s%s (%u keys)", *ndcp,
756             dc->from.user ? dc->from.user : "", dc->from.user ? "@" : "",
757             dc->from.hostname ? dc->from.hostname : "(ORIGIN)", dc->from.nkeys,
758             dc->to.user ? dc->to.user : "", dc->to.user ? "@" : "",
759             dc->to.hostname ? dc->to.hostname : "(ANY)", dc->to.nkeys);
760         *dcp = xrecallocarray(*dcp, *ndcp, *ndcp + 1, sizeof(**dcp));
761         (*dcp)[(*ndcp)++] = dc;
762         free(os);
763 }
764
765
766 static void
767 usage(void)
768 {
769         fprintf(stderr,
770 "usage: ssh-add [-cDdKkLlqvXx] [-E fingerprint_hash] [-H hostkey_file]\n"
771 "               [-h destination_constraint] [-S provider] [-t life]\n"
772 #ifdef WITH_XMSS
773 "               [-M maxsign] [-m minleft]\n"
774 #endif
775 "               [file ...]\n"
776 "       ssh-add -s pkcs11\n"
777 "       ssh-add -e pkcs11\n"
778 "       ssh-add -T pubkey ...\n"
779         );
780 }
781
782 int
783 main(int argc, char **argv)
784 {
785         extern char *optarg;
786         extern int optind;
787         int agent_fd;
788         char *pkcs11provider = NULL, *skprovider = NULL;
789         char **dest_constraint_strings = NULL, **hostkey_files = NULL;
790         int r, i, ch, deleting = 0, ret = 0, key_only = 0, do_download = 0;
791         int xflag = 0, lflag = 0, Dflag = 0, qflag = 0, Tflag = 0;
792         SyslogFacility log_facility = SYSLOG_FACILITY_AUTH;
793         LogLevel log_level = SYSLOG_LEVEL_INFO;
794         struct dest_constraint **dest_constraints = NULL;
795         size_t ndest_constraints = 0;
796
797         /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
798         sanitise_stdfd();
799
800         __progname = ssh_get_progname(argv[0]);
801         seed_rng();
802
803         log_init(__progname, log_level, log_facility, 1);
804
805         setvbuf(stdout, NULL, _IOLBF, 0);
806
807         /* First, get a connection to the authentication agent. */
808         switch (r = ssh_get_authentication_socket(&agent_fd)) {
809         case 0:
810                 break;
811         case SSH_ERR_AGENT_NOT_PRESENT:
812                 fprintf(stderr, "Could not open a connection to your "
813                     "authentication agent.\n");
814                 exit(2);
815         default:
816                 fprintf(stderr, "Error connecting to agent: %s\n", ssh_err(r));
817                 exit(2);
818         }
819
820         skprovider = getenv("SSH_SK_PROVIDER");
821
822         while ((ch = getopt(argc, argv, "vkKlLcdDTxXE:e:h:H:M:m:qs:S:t:")) != -1) {
823                 switch (ch) {
824                 case 'v':
825                         if (log_level == SYSLOG_LEVEL_INFO)
826                                 log_level = SYSLOG_LEVEL_DEBUG1;
827                         else if (log_level < SYSLOG_LEVEL_DEBUG3)
828                                 log_level++;
829                         break;
830                 case 'E':
831                         fingerprint_hash = ssh_digest_alg_by_name(optarg);
832                         if (fingerprint_hash == -1)
833                                 fatal("Invalid hash algorithm \"%s\"", optarg);
834                         break;
835                 case 'H':
836                         stringlist_append(&hostkey_files, optarg);
837                         break;
838                 case 'h':
839                         stringlist_append(&dest_constraint_strings, optarg);
840                         break;
841                 case 'k':
842                         key_only = 1;
843                         break;
844                 case 'K':
845                         do_download = 1;
846                         break;
847                 case 'l':
848                 case 'L':
849                         if (lflag != 0)
850                                 fatal("-%c flag already specified", lflag);
851                         lflag = ch;
852                         break;
853                 case 'x':
854                 case 'X':
855                         if (xflag != 0)
856                                 fatal("-%c flag already specified", xflag);
857                         xflag = ch;
858                         break;
859                 case 'c':
860                         confirm = 1;
861                         break;
862                 case 'm':
863                         minleft = (int)strtonum(optarg, 1, UINT_MAX, NULL);
864                         if (minleft == 0) {
865                                 usage();
866                                 ret = 1;
867                                 goto done;
868                         }
869                         break;
870                 case 'M':
871                         maxsign = (int)strtonum(optarg, 1, UINT_MAX, NULL);
872                         if (maxsign == 0) {
873                                 usage();
874                                 ret = 1;
875                                 goto done;
876                         }
877                         break;
878                 case 'd':
879                         deleting = 1;
880                         break;
881                 case 'D':
882                         Dflag = 1;
883                         break;
884                 case 's':
885                         pkcs11provider = optarg;
886                         break;
887                 case 'S':
888                         skprovider = optarg;
889                         break;
890                 case 'e':
891                         deleting = 1;
892                         pkcs11provider = optarg;
893                         break;
894                 case 't':
895                         if ((lifetime = convtime(optarg)) == -1 ||
896                             lifetime < 0 || (u_long)lifetime > UINT32_MAX) {
897                                 fprintf(stderr, "Invalid lifetime\n");
898                                 ret = 1;
899                                 goto done;
900                         }
901                         break;
902                 case 'q':
903                         qflag = 1;
904                         break;
905                 case 'T':
906                         Tflag = 1;
907                         break;
908                 default:
909                         usage();
910                         ret = 1;
911                         goto done;
912                 }
913         }
914         log_init(__progname, log_level, log_facility, 1);
915
916         if ((xflag != 0) + (lflag != 0) + (Dflag != 0) > 1)
917                 fatal("Invalid combination of actions");
918         else if (xflag) {
919                 if (lock_agent(agent_fd, xflag == 'x' ? 1 : 0) == -1)
920                         ret = 1;
921                 goto done;
922         } else if (lflag) {
923                 if (list_identities(agent_fd, lflag == 'l' ? 1 : 0) == -1)
924                         ret = 1;
925                 goto done;
926         } else if (Dflag) {
927                 if (delete_all(agent_fd, qflag) == -1)
928                         ret = 1;
929                 goto done;
930         }
931
932 #ifdef ENABLE_SK_INTERNAL
933         if (skprovider == NULL)
934                 skprovider = "internal";
935 #endif
936
937         if (hostkey_files == NULL) {
938                 /* use defaults from readconf.c */
939                 stringlist_append(&hostkey_files, _PATH_SSH_USER_HOSTFILE);
940                 stringlist_append(&hostkey_files, _PATH_SSH_USER_HOSTFILE2);
941                 stringlist_append(&hostkey_files, _PATH_SSH_SYSTEM_HOSTFILE);
942                 stringlist_append(&hostkey_files, _PATH_SSH_SYSTEM_HOSTFILE2);
943         }
944         if (dest_constraint_strings != NULL) {
945                 for (i = 0; dest_constraint_strings[i] != NULL; i++) {
946                         parse_dest_constraint(dest_constraint_strings[i],
947                           &dest_constraints, &ndest_constraints, hostkey_files);
948                 }
949         }
950
951         argc -= optind;
952         argv += optind;
953         if (Tflag) {
954                 if (argc <= 0)
955                         fatal("no keys to test");
956                 for (r = i = 0; i < argc; i++)
957                         r |= test_key(agent_fd, argv[i]);
958                 ret = r == 0 ? 0 : 1;
959                 goto done;
960         }
961         if (pkcs11provider != NULL) {
962                 if (update_card(agent_fd, !deleting, pkcs11provider,
963                     qflag, dest_constraints, ndest_constraints) == -1)
964                         ret = 1;
965                 goto done;
966         }
967         if (do_download) {
968                 if (skprovider == NULL)
969                         fatal("Cannot download keys without provider");
970                 if (load_resident_keys(agent_fd, skprovider, qflag,
971                     dest_constraints, ndest_constraints) != 0)
972                         ret = 1;
973                 goto done;
974         }
975         if (argc == 0) {
976                 char buf[PATH_MAX];
977                 struct passwd *pw;
978                 struct stat st;
979                 int count = 0;
980
981                 if ((pw = getpwuid(getuid())) == NULL) {
982                         fprintf(stderr, "No user found with uid %u\n",
983                             (u_int)getuid());
984                         ret = 1;
985                         goto done;
986                 }
987
988                 for (i = 0; default_files[i]; i++) {
989                         snprintf(buf, sizeof(buf), "%s/%s", pw->pw_dir,
990                             default_files[i]);
991                         if (stat(buf, &st) == -1)
992                                 continue;
993                         if (do_file(agent_fd, deleting, key_only, buf,
994                             qflag, skprovider,
995                             dest_constraints, ndest_constraints) == -1)
996                                 ret = 1;
997                         else
998                                 count++;
999                 }
1000                 if (count == 0)
1001                         ret = 1;
1002         } else {
1003                 for (i = 0; i < argc; i++) {
1004                         if (do_file(agent_fd, deleting, key_only,
1005                             argv[i], qflag, skprovider,
1006                             dest_constraints, ndest_constraints) == -1)
1007                                 ret = 1;
1008                 }
1009         }
1010 done:
1011         clear_pass();
1012         ssh_close_authentication_socket(agent_fd);
1013         return ret;
1014 }