1 /* $OpenBSD: ssh-add.c,v 1.173 2024/09/06 02:30:44 djm Exp $ */
3 * Author: Tatu Ylonen <ylo@cs.hut.fi>
4 * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
6 * Adds an identity to the authentication server, or removes an identity.
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".
14 * SSH2 implementation,
15 * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved.
17 * Redistribution and use in source and binary forms, with or without
18 * modification, are permitted provided that the following conditions
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.
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.
40 #include <sys/types.h>
44 # include <openssl/evp.h>
45 # include "openbsd-compat/openssl-compat.h"
65 #include "pathnames.h"
74 extern char *__progname
;
76 /* Default files to add */
77 static char *default_files
[] = {
79 _PATH_SSH_CLIENT_ID_RSA
,
80 #ifdef OPENSSL_HAS_ECC
81 _PATH_SSH_CLIENT_ID_ECDSA
,
82 _PATH_SSH_CLIENT_ID_ECDSA_SK
,
84 #endif /* WITH_OPENSSL */
85 _PATH_SSH_CLIENT_ID_ED25519
,
86 _PATH_SSH_CLIENT_ID_ED25519_SK
,
87 _PATH_SSH_CLIENT_ID_XMSS
,
89 _PATH_SSH_CLIENT_ID_DSA
,
94 static int fingerprint_hash
= SSH_FP_HASH_DEFAULT
;
96 /* Default lifetime (0 == forever) */
97 static int lifetime
= 0;
99 /* User has to confirm key use */
100 static int confirm
= 0;
102 /* Maximum number of signatures (XMSS) */
103 static u_int maxsign
= 0;
104 static u_int minleft
= 0;
106 /* we keep a cache of one passphrase */
107 static char *pass
= NULL
;
112 freezero(pass
, strlen(pass
));
118 delete_one(int agent_fd
, const struct sshkey
*key
, const char *comment
,
119 const char *path
, int qflag
)
123 if ((r
= ssh_remove_identity(agent_fd
, key
)) != 0) {
124 fprintf(stderr
, "Could not remove identity \"%s\": %s\n",
129 fprintf(stderr
, "Identity removed: %s %s (%s)\n", path
,
130 sshkey_type(key
), comment
? comment
: "no comment");
136 delete_stdin(int agent_fd
, int qflag
, int key_only
, int cert_only
)
138 char *line
= NULL
, *cp
;
140 struct sshkey
*key
= NULL
;
141 int lnum
= 0, r
, ret
= -1;
143 while (getline(&line
, &linesize
, stdin
) != -1) {
147 line
[strcspn(line
, "\n")] = '\0';
148 cp
= line
+ strspn(line
, " \t");
149 if (*cp
== '#' || *cp
== '\0')
151 if ((key
= sshkey_new(KEY_UNSPEC
)) == NULL
)
152 fatal_f("sshkey_new");
153 if ((r
= sshkey_read(key
, &cp
)) != 0) {
154 error_r(r
, "(stdin):%d: invalid key", lnum
);
157 if ((!key_only
&& !cert_only
) ||
158 (key_only
&& !sshkey_is_cert(key
)) ||
159 (cert_only
&& sshkey_is_cert(key
))) {
160 if (delete_one(agent_fd
, key
, cp
,
161 "(stdin)", qflag
) == 0)
171 delete_file(int agent_fd
, const char *filename
, int key_only
,
172 int cert_only
, int qflag
)
174 struct sshkey
*public, *cert
= NULL
;
175 char *certpath
= NULL
, *comment
= NULL
;
178 if (strcmp(filename
, "-") == 0)
179 return delete_stdin(agent_fd
, qflag
, key_only
, cert_only
);
181 if ((r
= sshkey_load_public(filename
, &public, &comment
)) != 0) {
182 printf("Bad key file %s: %s\n", filename
, ssh_err(r
));
185 if ((!key_only
&& !cert_only
) ||
186 (key_only
&& !sshkey_is_cert(public)) ||
187 (cert_only
&& sshkey_is_cert(public))) {
188 if (delete_one(agent_fd
, public, comment
, filename
, qflag
) == 0)
195 /* Now try to delete the corresponding certificate too */
198 xasprintf(&certpath
, "%s-cert.pub", filename
);
199 if ((r
= sshkey_load_public(certpath
, &cert
, &comment
)) != 0) {
200 if (r
!= SSH_ERR_SYSTEM_ERROR
|| errno
!= ENOENT
)
201 error_r(r
, "Failed to load certificate \"%s\"", certpath
);
205 if (!sshkey_equal_public(cert
, public))
206 fatal("Certificate %s does not match private key %s",
209 if (delete_one(agent_fd
, cert
, comment
, certpath
, qflag
) == 0)
221 /* Send a request to remove all identities. */
223 delete_all(int agent_fd
, int qflag
)
228 * Since the agent might be forwarded, old or non-OpenSSH, when asked
229 * to remove all keys, attempt to remove both protocol v.1 and v.2
232 if (ssh_remove_all_identities(agent_fd
, 2) == 0)
234 /* ignore error-code for ssh1 */
235 ssh_remove_all_identities(agent_fd
, 1);
238 fprintf(stderr
, "Failed to remove all identities.\n");
240 fprintf(stderr
, "All identities removed.\n");
246 add_file(int agent_fd
, const char *filename
, int key_only
, int cert_only
,
247 int qflag
, const char *skprovider
,
248 struct dest_constraint
**dest_constraints
,
249 size_t ndest_constraints
)
251 struct sshkey
*private, *cert
;
252 char *comment
= NULL
;
253 char msg
[1024], *certpath
= NULL
;
257 struct sshbuf
*keyblob
;
258 struct ssh_identitylist
*idlist
;
260 if (strcmp(filename
, "-") == 0) {
262 filename
= "(stdin)";
263 } else if ((fd
= open(filename
, O_RDONLY
)) == -1) {
269 * Since we'll try to load a keyfile multiple times, permission errors
270 * will occur multiple times, so check perms first and bail if wrong.
272 if (fd
!= STDIN_FILENO
) {
273 if (sshkey_perm_ok(fd
, filename
) != 0) {
278 if ((r
= sshbuf_load_fd(fd
, &keyblob
)) != 0) {
279 fprintf(stderr
, "Error loading key \"%s\": %s\n",
280 filename
, ssh_err(r
));
281 sshbuf_free(keyblob
);
287 /* At first, try empty passphrase */
288 if ((r
= sshkey_parse_private_fileblob(keyblob
, "", &private,
289 &comment
)) != 0 && r
!= SSH_ERR_KEY_WRONG_PASSPHRASE
) {
290 fprintf(stderr
, "Error loading key \"%s\": %s\n",
291 filename
, ssh_err(r
));
295 if (private == NULL
&& pass
!= NULL
) {
296 if ((r
= sshkey_parse_private_fileblob(keyblob
, pass
, &private,
297 &comment
)) != 0 && r
!= SSH_ERR_KEY_WRONG_PASSPHRASE
) {
298 fprintf(stderr
, "Error loading key \"%s\": %s\n",
299 filename
, ssh_err(r
));
303 if (private == NULL
) {
304 /* clear passphrase since it did not work */
306 snprintf(msg
, sizeof msg
, "Enter passphrase for %s%s: ",
307 filename
, confirm
? " (will confirm each use)" : "");
309 pass
= read_passphrase(msg
, RP_ALLOW_STDIN
);
310 if (strcmp(pass
, "") == 0)
312 if ((r
= sshkey_parse_private_fileblob(keyblob
, pass
,
313 &private, &comment
)) == 0)
315 else if (r
!= SSH_ERR_KEY_WRONG_PASSPHRASE
) {
317 "Error loading key \"%s\": %s\n",
318 filename
, ssh_err(r
));
321 sshbuf_free(keyblob
);
325 snprintf(msg
, sizeof msg
,
326 "Bad passphrase, try again for %s%s: ", filename
,
327 confirm
? " (will confirm each use)" : "");
330 if (comment
== NULL
|| *comment
== '\0')
331 comment
= xstrdup(filename
);
332 sshbuf_free(keyblob
);
335 if ((r
= sshkey_set_filename(private, filename
)) != 0) {
336 fprintf(stderr
, "Could not add filename to private key: %s (%s)\n",
340 if (maxsign
&& minleft
&&
341 (r
= ssh_fetch_identitylist(agent_fd
, &idlist
)) == 0) {
342 for (i
= 0; i
< idlist
->nkeys
; i
++) {
343 if (!sshkey_equal_public(idlist
->keys
[i
], private))
345 left
= sshkey_signatures_left(idlist
->keys
[i
]);
346 if (left
< minleft
) {
348 "Only %d signatures left.\n", left
);
351 fprintf(stderr
, "Skipping update: ");
352 if (left
== minleft
) {
354 "required signatures left (%d).\n", left
);
357 "more signatures left (%d) than"
358 " required (%d).\n", left
, minleft
);
360 ssh_free_identitylist(idlist
);
363 ssh_free_identitylist(idlist
);
366 if (sshkey_is_sk(private)) {
367 if (skprovider
== NULL
) {
368 fprintf(stderr
, "Cannot load FIDO key %s "
369 "without provider\n", filename
);
373 /* Don't send provider constraint for other keys */
378 (r
= ssh_add_identity_constrained(agent_fd
, private, comment
,
379 lifetime
, confirm
, maxsign
, skprovider
,
380 dest_constraints
, ndest_constraints
)) == 0) {
383 fprintf(stderr
, "Identity added: %s (%s)\n",
387 "Lifetime set to %d seconds\n", lifetime
);
390 fprintf(stderr
, "The user must confirm "
391 "each use of the key\n");
395 fprintf(stderr
, "Could not add identity \"%s\": %s\n",
396 filename
, ssh_err(r
));
399 /* Skip trying to load the cert if requested */
403 /* Now try to add the certificate flavour too */
404 xasprintf(&certpath
, "%s-cert.pub", filename
);
405 if ((r
= sshkey_load_public(certpath
, &cert
, NULL
)) != 0) {
406 if (r
!= SSH_ERR_SYSTEM_ERROR
|| errno
!= ENOENT
)
407 error_r(r
, "Failed to load certificate \"%s\"",
412 if (!sshkey_equal_public(cert
, private)) {
413 error("Certificate %s does not match private key %s",
419 /* Graft with private bits */
420 if ((r
= sshkey_to_certified(private)) != 0) {
421 error_fr(r
, "sshkey_to_certified");
425 if ((r
= sshkey_cert_copy(cert
, private)) != 0) {
426 error_fr(r
, "sshkey_cert_copy");
432 if ((r
= ssh_add_identity_constrained(agent_fd
, private, comment
,
433 lifetime
, confirm
, maxsign
, skprovider
,
434 dest_constraints
, ndest_constraints
)) != 0) {
435 error_r(r
, "Certificate %s (%s) add failed", certpath
,
436 private->cert
->key_id
);
441 fprintf(stderr
, "Certificate added: %s (%s)\n", certpath
,
442 private->cert
->key_id
);
444 fprintf(stderr
, "Lifetime set to %d seconds\n",
448 fprintf(stderr
, "The user must confirm each use "
456 sshkey_free(private);
462 update_card(int agent_fd
, int add
, const char *id
, int qflag
,
463 int key_only
, int cert_only
,
464 struct dest_constraint
**dest_constraints
, size_t ndest_constraints
,
465 struct sshkey
**certs
, size_t ncerts
)
474 if ((pin
= read_passphrase("Enter passphrase for PKCS#11: ",
475 RP_ALLOW_STDIN
)) == NULL
)
479 if ((r
= ssh_update_card(agent_fd
, add
, id
, pin
== NULL
? "" : pin
,
480 lifetime
, confirm
, dest_constraints
, ndest_constraints
,
481 cert_only
, certs
, ncerts
)) == 0) {
484 fprintf(stderr
, "Card %s: %s\n",
485 add
? "added" : "removed", id
);
488 fprintf(stderr
, "Could not %s card \"%s\": %s\n",
489 add
? "add" : "remove", id
, ssh_err(r
));
497 test_key(int agent_fd
, const char *filename
)
499 struct sshkey
*key
= NULL
;
501 const char *alg
= NULL
;
506 if ((r
= sshkey_load_public(filename
, &key
, NULL
)) != 0) {
507 error_r(r
, "Couldn't read public key %s", filename
);
510 if (sshkey_type_plain(key
->type
) == KEY_RSA
)
511 alg
= "rsa-sha2-256";
512 arc4random_buf(data
, sizeof(data
));
513 if ((r
= ssh_agent_sign(agent_fd
, key
, &sig
, &slen
, data
, sizeof(data
),
515 error_r(r
, "Agent signature failed for %s", filename
);
518 if ((r
= sshkey_verify(key
, sig
, slen
, data
, sizeof(data
),
519 alg
, 0, NULL
)) != 0) {
520 error_r(r
, "Signature verification failed for %s", filename
);
532 list_identities(int agent_fd
, int do_fp
)
536 struct ssh_identitylist
*idlist
;
540 if ((r
= ssh_fetch_identitylist(agent_fd
, &idlist
)) != 0) {
541 if (r
!= SSH_ERR_AGENT_NO_IDENTITIES
)
542 fprintf(stderr
, "error fetching identities: %s\n",
545 printf("The agent has no identities.\n");
548 for (i
= 0; i
< idlist
->nkeys
; i
++) {
550 fp
= sshkey_fingerprint(idlist
->keys
[i
],
551 fingerprint_hash
, SSH_FP_DEFAULT
);
552 printf("%u %s %s (%s)\n", sshkey_size(idlist
->keys
[i
]),
553 fp
== NULL
? "(null)" : fp
, idlist
->comments
[i
],
554 sshkey_type(idlist
->keys
[i
]));
557 if ((r
= sshkey_write(idlist
->keys
[i
], stdout
)) != 0) {
558 fprintf(stderr
, "sshkey_write: %s\n",
562 fprintf(stdout
, " %s", idlist
->comments
[i
]);
563 left
= sshkey_signatures_left(idlist
->keys
[i
]);
566 " [signatures left %d]", left
);
567 fprintf(stdout
, "\n");
570 ssh_free_identitylist(idlist
);
575 lock_agent(int agent_fd
, int lock
)
577 char prompt
[100], *p1
, *p2
;
578 int r
, passok
= 1, ret
= -1;
580 strlcpy(prompt
, "Enter lock password: ", sizeof(prompt
));
581 p1
= read_passphrase(prompt
, RP_ALLOW_STDIN
);
583 strlcpy(prompt
, "Again: ", sizeof prompt
);
584 p2
= read_passphrase(prompt
, RP_ALLOW_STDIN
);
585 if (strcmp(p1
, p2
) != 0) {
586 fprintf(stderr
, "Passwords do not match.\n");
589 freezero(p2
, strlen(p2
));
592 if ((r
= ssh_lock_agent(agent_fd
, lock
, p1
)) == 0) {
593 fprintf(stderr
, "Agent %slocked.\n", lock
? "" : "un");
596 fprintf(stderr
, "Failed to %slock agent: %s\n",
597 lock
? "" : "un", ssh_err(r
));
600 freezero(p1
, strlen(p1
));
605 load_resident_keys(int agent_fd
, const char *skprovider
, int qflag
,
606 struct dest_constraint
**dest_constraints
, size_t ndest_constraints
)
608 struct sshsk_resident_key
**srks
;
614 pass
= read_passphrase("Enter PIN for authenticator: ", RP_ALLOW_STDIN
);
615 if ((r
= sshsk_load_resident(skprovider
, NULL
, pass
, 0,
616 &srks
, &nsrks
)) != 0) {
617 error_r(r
, "Unable to load resident keys");
620 for (i
= 0; i
< nsrks
; i
++) {
622 if ((fp
= sshkey_fingerprint(key
,
623 fingerprint_hash
, SSH_FP_DEFAULT
)) == NULL
)
624 fatal_f("sshkey_fingerprint failed");
625 if ((r
= ssh_add_identity_constrained(agent_fd
, key
, "",
626 lifetime
, confirm
, maxsign
, skprovider
,
627 dest_constraints
, ndest_constraints
)) != 0) {
628 error("Unable to add key %s %s",
629 sshkey_type(key
), fp
);
637 fprintf(stderr
, "Resident identity added: %s %s\n",
638 sshkey_type(key
), fp
);
641 "Lifetime set to %d seconds\n", lifetime
);
644 fprintf(stderr
, "The user must confirm "
645 "each use of the key\n");
650 sshsk_free_resident_keys(srks
, nsrks
);
652 return SSH_ERR_KEY_NOT_FOUND
;
653 return ok
== 1 ? 0 : ok
;
657 do_file(int agent_fd
, int deleting
, int key_only
, int cert_only
,
658 char *file
, int qflag
, const char *skprovider
,
659 struct dest_constraint
**dest_constraints
, size_t ndest_constraints
)
662 if (delete_file(agent_fd
, file
, key_only
,
663 cert_only
, qflag
) == -1)
666 if (add_file(agent_fd
, file
, key_only
, cert_only
, qflag
,
667 skprovider
, dest_constraints
, ndest_constraints
) == -1)
673 /* Append string 's' to a NULL-terminated array of strings */
675 stringlist_append(char ***listp
, const char *s
)
680 *listp
= xcalloc(2, sizeof(**listp
));
682 for (i
= 0; (*listp
)[i
] != NULL
; i
++)
684 *listp
= xrecallocarray(*listp
, i
+ 1, i
+ 2, sizeof(**listp
));
686 (*listp
)[i
] = xstrdup(s
);
690 parse_dest_constraint_hop(const char *s
, struct dest_constraint_hop
*dch
,
691 char **hostkey_files
)
693 char *user
= NULL
, *host
, *os
, *path
;
695 struct hostkeys
*hostkeys
;
696 const struct hostkey_entry
*hke
;
699 memset(dch
, '\0', sizeof(*dch
));
701 if ((host
= strrchr(os
, '@')) == NULL
)
708 /* Trivial case: username@ (all hosts) */
711 fatal("Invalid key destination constraint \"%s\": "
712 "does not specify user or host", s
);
714 dch
->user
= xstrdup(user
);
715 /* other fields left blank */
719 if (hostkey_files
== NULL
)
720 fatal_f("no hostkey files");
721 /* Otherwise we need to look up the keys for this hostname */
722 hostkeys
= init_hostkeys();
723 for (i
= 0; hostkey_files
[i
]; i
++) {
724 path
= tilde_expand_filename(hostkey_files
[i
], getuid());
725 debug2_f("looking up host keys for \"%s\" in %s", host
, path
);
726 load_hostkeys(hostkeys
, host
, path
, 0);
729 dch
->user
= user
== NULL
? NULL
: xstrdup(user
);
730 dch
->hostname
= xstrdup(host
);
731 for (i
= 0; i
< hostkeys
->num_entries
; i
++) {
732 hke
= hostkeys
->entries
+ i
;
733 want_ca
= hke
->marker
== MRK_CA
;
734 if (hke
->marker
!= MRK_NONE
&& !want_ca
)
736 debug3_f("%s%s%s: adding %s %skey from %s:%lu as key %u",
737 user
== NULL
? "": user
, user
== NULL
? "" : "@",
738 host
, sshkey_type(hke
->key
), want_ca
? "CA " : "",
739 hke
->file
, hke
->line
, dch
->nkeys
);
740 dch
->keys
= xrecallocarray(dch
->keys
, dch
->nkeys
,
741 dch
->nkeys
+ 1, sizeof(*dch
->keys
));
742 dch
->key_is_ca
= xrecallocarray(dch
->key_is_ca
, dch
->nkeys
,
743 dch
->nkeys
+ 1, sizeof(*dch
->key_is_ca
));
744 if ((r
= sshkey_from_private(hke
->key
,
745 &(dch
->keys
[dch
->nkeys
]))) != 0)
746 fatal_fr(r
, "sshkey_from_private");
747 dch
->key_is_ca
[dch
->nkeys
] = want_ca
;
751 fatal("No host keys found for destination \"%s\"", host
);
752 free_hostkeys(hostkeys
);
758 parse_dest_constraint(const char *s
, struct dest_constraint
***dcp
,
759 size_t *ndcp
, char **hostkey_files
)
761 struct dest_constraint
*dc
;
764 dc
= xcalloc(1, sizeof(*dc
));
766 if ((cp
= strchr(os
, '>')) == NULL
) {
767 /* initial hop; no 'from' hop specified */
768 parse_dest_constraint_hop(os
, &dc
->to
, hostkey_files
);
770 /* two hops specified */
772 parse_dest_constraint_hop(os
, &dc
->from
, hostkey_files
);
773 parse_dest_constraint_hop(cp
, &dc
->to
, hostkey_files
);
774 if (dc
->from
.user
!= NULL
) {
775 fatal("Invalid key constraint %s: cannot specify "
776 "user on 'from' host", os
);
779 /* XXX eliminate or error on duplicates */
780 debug2_f("constraint %zu: %s%s%s (%u keys) > %s%s%s (%u keys)", *ndcp
,
781 dc
->from
.user
? dc
->from
.user
: "", dc
->from
.user
? "@" : "",
782 dc
->from
.hostname
? dc
->from
.hostname
: "(ORIGIN)", dc
->from
.nkeys
,
783 dc
->to
.user
? dc
->to
.user
: "", dc
->to
.user
? "@" : "",
784 dc
->to
.hostname
? dc
->to
.hostname
: "(ANY)", dc
->to
.nkeys
);
785 *dcp
= xrecallocarray(*dcp
, *ndcp
, *ndcp
+ 1, sizeof(**dcp
));
786 (*dcp
)[(*ndcp
)++] = dc
;
795 "usage: ssh-add [-CcDdKkLlqvXx] [-E fingerprint_hash] [-H hostkey_file]\n"
796 " [-h destination_constraint] [-S provider] [-t life]\n"
798 " [-M maxsign] [-m minleft]\n"
801 " ssh-add -s pkcs11 [-Cv] [certificate ...]\n"
802 " ssh-add -e pkcs11\n"
803 " ssh-add -T pubkey ...\n"
808 main(int argc
, char **argv
)
813 char *pkcs11provider
= NULL
, *skprovider
= NULL
;
814 char **dest_constraint_strings
= NULL
, **hostkey_files
= NULL
;
815 int r
, i
, ch
, deleting
= 0, ret
= 0, key_only
= 0, cert_only
= 0;
816 int do_download
= 0, xflag
= 0, lflag
= 0, Dflag
= 0;
817 int qflag
= 0, Tflag
= 0;
818 SyslogFacility log_facility
= SYSLOG_FACILITY_AUTH
;
819 LogLevel log_level
= SYSLOG_LEVEL_INFO
;
820 struct sshkey
*k
, **certs
= NULL
;
821 struct dest_constraint
**dest_constraints
= NULL
;
822 size_t ndest_constraints
= 0, ncerts
= 0;
824 /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */
827 __progname
= ssh_get_progname(argv
[0]);
830 log_init(__progname
, log_level
, log_facility
, 1);
832 setvbuf(stdout
, NULL
, _IOLBF
, 0);
834 /* First, get a connection to the authentication agent. */
835 switch (r
= ssh_get_authentication_socket(&agent_fd
)) {
838 case SSH_ERR_AGENT_NOT_PRESENT
:
839 fprintf(stderr
, "Could not open a connection to your "
840 "authentication agent.\n");
843 fprintf(stderr
, "Error connecting to agent: %s\n", ssh_err(r
));
847 skprovider
= getenv("SSH_SK_PROVIDER");
849 while ((ch
= getopt(argc
, argv
, "vkKlLCcdDTxXE:e:h:H:M:m:qs:S:t:")) != -1) {
852 if (log_level
== SYSLOG_LEVEL_INFO
)
853 log_level
= SYSLOG_LEVEL_DEBUG1
;
854 else if (log_level
< SYSLOG_LEVEL_DEBUG3
)
858 fingerprint_hash
= ssh_digest_alg_by_name(optarg
);
859 if (fingerprint_hash
== -1)
860 fatal("Invalid hash algorithm \"%s\"", optarg
);
863 stringlist_append(&hostkey_files
, optarg
);
866 stringlist_append(&dest_constraint_strings
, optarg
);
880 fatal("-%c flag already specified", lflag
);
886 fatal("-%c flag already specified", xflag
);
893 minleft
= (u_int
)strtonum(optarg
, 1, UINT_MAX
, NULL
);
901 maxsign
= (u_int
)strtonum(optarg
, 1, UINT_MAX
, NULL
);
915 pkcs11provider
= optarg
;
922 pkcs11provider
= optarg
;
925 if ((lifetime
= convtime(optarg
)) == -1 ||
926 lifetime
< 0 || (u_long
)lifetime
> UINT32_MAX
) {
927 fprintf(stderr
, "Invalid lifetime\n");
944 log_init(__progname
, log_level
, log_facility
, 1);
946 if ((xflag
!= 0) + (lflag
!= 0) + (Dflag
!= 0) > 1)
947 fatal("Invalid combination of actions");
949 if (lock_agent(agent_fd
, xflag
== 'x' ? 1 : 0) == -1)
953 if (list_identities(agent_fd
, lflag
== 'l' ? 1 : 0) == -1)
957 if (delete_all(agent_fd
, qflag
) == -1)
962 #ifdef ENABLE_SK_INTERNAL
963 if (skprovider
== NULL
)
964 skprovider
= "internal";
967 if (hostkey_files
== NULL
) {
968 /* use defaults from readconf.c */
969 stringlist_append(&hostkey_files
, _PATH_SSH_USER_HOSTFILE
);
970 stringlist_append(&hostkey_files
, _PATH_SSH_USER_HOSTFILE2
);
971 stringlist_append(&hostkey_files
, _PATH_SSH_SYSTEM_HOSTFILE
);
972 stringlist_append(&hostkey_files
, _PATH_SSH_SYSTEM_HOSTFILE2
);
974 if (dest_constraint_strings
!= NULL
) {
975 for (i
= 0; dest_constraint_strings
[i
] != NULL
; i
++) {
976 parse_dest_constraint(dest_constraint_strings
[i
],
977 &dest_constraints
, &ndest_constraints
, hostkey_files
);
985 fatal("no keys to test");
986 for (r
= i
= 0; i
< argc
; i
++)
987 r
|= test_key(agent_fd
, argv
[i
]);
988 ret
= r
== 0 ? 0 : 1;
991 if (pkcs11provider
!= NULL
) {
992 for (i
= 0; i
< argc
; i
++) {
993 if ((r
= sshkey_load_public(argv
[i
], &k
, NULL
)) != 0)
994 fatal_fr(r
, "load certificate %s", argv
[i
]);
995 certs
= xrecallocarray(certs
, ncerts
, ncerts
+ 1,
997 debug2("%s: %s", argv
[i
], sshkey_ssh_name(k
));
1000 debug2_f("loaded %zu certificates", ncerts
);
1001 if (update_card(agent_fd
, !deleting
, pkcs11provider
,
1002 qflag
, key_only
, cert_only
,
1003 dest_constraints
, ndest_constraints
,
1004 certs
, ncerts
) == -1)
1009 if (skprovider
== NULL
)
1010 fatal("Cannot download keys without provider");
1011 if (load_resident_keys(agent_fd
, skprovider
, qflag
,
1012 dest_constraints
, ndest_constraints
) != 0)
1022 if ((pw
= getpwuid(getuid())) == NULL
) {
1023 fprintf(stderr
, "No user found with uid %u\n",
1029 for (i
= 0; default_files
[i
]; i
++) {
1030 snprintf(buf
, sizeof(buf
), "%s/%s", pw
->pw_dir
,
1032 if (stat(buf
, &st
) == -1)
1034 if (do_file(agent_fd
, deleting
, key_only
, cert_only
,
1035 buf
, qflag
, skprovider
,
1036 dest_constraints
, ndest_constraints
) == -1)
1044 for (i
= 0; i
< argc
; i
++) {
1045 if (do_file(agent_fd
, deleting
, key_only
, cert_only
,
1046 argv
[i
], qflag
, skprovider
,
1047 dest_constraints
, ndest_constraints
) == -1)
1053 ssh_close_authentication_socket(agent_fd
);