1*0cbfa66cSDaniel Fojt /* $OpenBSD: ssh-add.c,v 1.155 2020/03/16 02:17:02 dtucker Exp $ */ 218de8d7fSPeter Avalos /* 318de8d7fSPeter Avalos * Author: Tatu Ylonen <ylo@cs.hut.fi> 418de8d7fSPeter Avalos * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland 518de8d7fSPeter Avalos * All rights reserved 618de8d7fSPeter Avalos * Adds an identity to the authentication server, or removes an identity. 718de8d7fSPeter Avalos * 818de8d7fSPeter Avalos * As far as I am concerned, the code I have written for this software 918de8d7fSPeter Avalos * can be used freely for any purpose. Any derived versions of this 1018de8d7fSPeter Avalos * software must be clearly marked as such, and if the derived work is 1118de8d7fSPeter Avalos * incompatible with the protocol description in the RFC file, it must be 1218de8d7fSPeter Avalos * called by a name other than "ssh" or "Secure Shell". 1318de8d7fSPeter Avalos * 1418de8d7fSPeter Avalos * SSH2 implementation, 1518de8d7fSPeter Avalos * Copyright (c) 2000, 2001 Markus Friedl. All rights reserved. 1618de8d7fSPeter Avalos * 1718de8d7fSPeter Avalos * Redistribution and use in source and binary forms, with or without 1818de8d7fSPeter Avalos * modification, are permitted provided that the following conditions 1918de8d7fSPeter Avalos * are met: 2018de8d7fSPeter Avalos * 1. Redistributions of source code must retain the above copyright 2118de8d7fSPeter Avalos * notice, this list of conditions and the following disclaimer. 2218de8d7fSPeter Avalos * 2. Redistributions in binary form must reproduce the above copyright 2318de8d7fSPeter Avalos * notice, this list of conditions and the following disclaimer in the 2418de8d7fSPeter Avalos * documentation and/or other materials provided with the distribution. 2518de8d7fSPeter Avalos * 2618de8d7fSPeter Avalos * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 2718de8d7fSPeter Avalos * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2818de8d7fSPeter Avalos * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2918de8d7fSPeter Avalos * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 3018de8d7fSPeter Avalos * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 3118de8d7fSPeter Avalos * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 3218de8d7fSPeter Avalos * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 3318de8d7fSPeter Avalos * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 3418de8d7fSPeter Avalos * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 3518de8d7fSPeter Avalos * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 3618de8d7fSPeter Avalos */ 3718de8d7fSPeter Avalos 3818de8d7fSPeter Avalos #include "includes.h" 3918de8d7fSPeter Avalos 4018de8d7fSPeter Avalos #include <sys/types.h> 4118de8d7fSPeter Avalos #include <sys/stat.h> 4218de8d7fSPeter Avalos 43*0cbfa66cSDaniel Fojt #ifdef WITH_OPENSSL 4418de8d7fSPeter Avalos # include <openssl/evp.h> 4518de8d7fSPeter Avalos # include "openbsd-compat/openssl-compat.h" 46*0cbfa66cSDaniel Fojt #endif 4718de8d7fSPeter Avalos 48e9778795SPeter Avalos #include <errno.h> 4918de8d7fSPeter Avalos #include <fcntl.h> 5018de8d7fSPeter Avalos #include <pwd.h> 5118de8d7fSPeter Avalos #include <stdarg.h> 5218de8d7fSPeter Avalos #include <stdio.h> 5318de8d7fSPeter Avalos #include <stdlib.h> 5418de8d7fSPeter Avalos #include <string.h> 5518de8d7fSPeter Avalos #include <unistd.h> 56e9778795SPeter Avalos #include <limits.h> 5718de8d7fSPeter Avalos 5818de8d7fSPeter Avalos #include "xmalloc.h" 5918de8d7fSPeter Avalos #include "ssh.h" 6018de8d7fSPeter Avalos #include "log.h" 61e9778795SPeter Avalos #include "sshkey.h" 62e9778795SPeter Avalos #include "sshbuf.h" 6318de8d7fSPeter Avalos #include "authfd.h" 6418de8d7fSPeter Avalos #include "authfile.h" 6518de8d7fSPeter Avalos #include "pathnames.h" 6618de8d7fSPeter Avalos #include "misc.h" 6736e94dc5SPeter Avalos #include "ssherr.h" 68e9778795SPeter Avalos #include "digest.h" 69*0cbfa66cSDaniel Fojt #include "ssh-sk.h" 7018de8d7fSPeter Avalos 7118de8d7fSPeter Avalos /* argv0 */ 7218de8d7fSPeter Avalos extern char *__progname; 7318de8d7fSPeter Avalos 7418de8d7fSPeter Avalos /* Default files to add */ 7518de8d7fSPeter Avalos static char *default_files[] = { 76e9778795SPeter Avalos #ifdef WITH_OPENSSL 7718de8d7fSPeter Avalos _PATH_SSH_CLIENT_ID_RSA, 7818de8d7fSPeter Avalos _PATH_SSH_CLIENT_ID_DSA, 799f304aafSPeter Avalos #ifdef OPENSSL_HAS_ECC 809f304aafSPeter Avalos _PATH_SSH_CLIENT_ID_ECDSA, 81*0cbfa66cSDaniel Fojt _PATH_SSH_CLIENT_ID_ECDSA_SK, 829f304aafSPeter Avalos #endif 83e9778795SPeter Avalos #endif /* WITH_OPENSSL */ 8436e94dc5SPeter Avalos _PATH_SSH_CLIENT_ID_ED25519, 85*0cbfa66cSDaniel Fojt _PATH_SSH_CLIENT_ID_ED25519_SK, 86664f4763Szrj _PATH_SSH_CLIENT_ID_XMSS, 8718de8d7fSPeter Avalos NULL 8818de8d7fSPeter Avalos }; 8918de8d7fSPeter Avalos 90e9778795SPeter Avalos static int fingerprint_hash = SSH_FP_HASH_DEFAULT; 91e9778795SPeter Avalos 9218de8d7fSPeter Avalos /* Default lifetime (0 == forever) */ 93*0cbfa66cSDaniel Fojt static long lifetime = 0; 9418de8d7fSPeter Avalos 9518de8d7fSPeter Avalos /* User has to confirm key use */ 9618de8d7fSPeter Avalos static int confirm = 0; 9718de8d7fSPeter Avalos 98664f4763Szrj /* Maximum number of signatures (XMSS) */ 99664f4763Szrj static u_int maxsign = 0; 100664f4763Szrj static u_int minleft = 0; 101664f4763Szrj 102e9778795SPeter Avalos /* we keep a cache of one passphrase */ 10318de8d7fSPeter Avalos static char *pass = NULL; 10418de8d7fSPeter Avalos static void 10518de8d7fSPeter Avalos clear_pass(void) 10618de8d7fSPeter Avalos { 10718de8d7fSPeter Avalos if (pass) { 108*0cbfa66cSDaniel Fojt freezero(pass, strlen(pass)); 10918de8d7fSPeter Avalos pass = NULL; 11018de8d7fSPeter Avalos } 11118de8d7fSPeter Avalos } 11218de8d7fSPeter Avalos 11318de8d7fSPeter Avalos static int 114ce74bacaSMatthew Dillon delete_file(int agent_fd, const char *filename, int key_only, int qflag) 11518de8d7fSPeter Avalos { 116e9778795SPeter Avalos struct sshkey *public, *cert = NULL; 11736e94dc5SPeter Avalos char *certpath = NULL, *comment = NULL; 118e9778795SPeter Avalos int r, ret = -1; 11918de8d7fSPeter Avalos 120e9778795SPeter Avalos if ((r = sshkey_load_public(filename, &public, &comment)) != 0) { 121e9778795SPeter Avalos printf("Bad key file %s: %s\n", filename, ssh_err(r)); 12218de8d7fSPeter Avalos return -1; 12318de8d7fSPeter Avalos } 124e9778795SPeter Avalos if ((r = ssh_remove_identity(agent_fd, public)) == 0) { 125ce74bacaSMatthew Dillon if (!qflag) { 126ce74bacaSMatthew Dillon fprintf(stderr, "Identity removed: %s (%s)\n", 127ce74bacaSMatthew Dillon filename, comment); 128ce74bacaSMatthew Dillon } 12918de8d7fSPeter Avalos ret = 0; 13018de8d7fSPeter Avalos } else 131e9778795SPeter Avalos fprintf(stderr, "Could not remove identity \"%s\": %s\n", 132e9778795SPeter Avalos filename, ssh_err(r)); 13318de8d7fSPeter Avalos 13436e94dc5SPeter Avalos if (key_only) 13536e94dc5SPeter Avalos goto out; 13636e94dc5SPeter Avalos 13736e94dc5SPeter Avalos /* Now try to delete the corresponding certificate too */ 13836e94dc5SPeter Avalos free(comment); 13936e94dc5SPeter Avalos comment = NULL; 14036e94dc5SPeter Avalos xasprintf(&certpath, "%s-cert.pub", filename); 141e9778795SPeter Avalos if ((r = sshkey_load_public(certpath, &cert, &comment)) != 0) { 142e9778795SPeter Avalos if (r != SSH_ERR_SYSTEM_ERROR || errno != ENOENT) 143e9778795SPeter Avalos error("Failed to load certificate \"%s\": %s", 144e9778795SPeter Avalos certpath, ssh_err(r)); 14536e94dc5SPeter Avalos goto out; 146e9778795SPeter Avalos } 147e9778795SPeter Avalos 148e9778795SPeter Avalos if (!sshkey_equal_public(cert, public)) 14936e94dc5SPeter Avalos fatal("Certificate %s does not match private key %s", 15036e94dc5SPeter Avalos certpath, filename); 15136e94dc5SPeter Avalos 152e9778795SPeter Avalos if ((r = ssh_remove_identity(agent_fd, cert)) == 0) { 153ce74bacaSMatthew Dillon if (!qflag) { 154ce74bacaSMatthew Dillon fprintf(stderr, "Identity removed: %s (%s)\n", 155ce74bacaSMatthew Dillon certpath, comment); 156ce74bacaSMatthew Dillon } 15736e94dc5SPeter Avalos ret = 0; 15836e94dc5SPeter Avalos } else 159e9778795SPeter Avalos fprintf(stderr, "Could not remove identity \"%s\": %s\n", 160e9778795SPeter Avalos certpath, ssh_err(r)); 16136e94dc5SPeter Avalos 16236e94dc5SPeter Avalos out: 163e9778795SPeter Avalos sshkey_free(cert); 164e9778795SPeter Avalos sshkey_free(public); 16536e94dc5SPeter Avalos free(certpath); 16636e94dc5SPeter Avalos free(comment); 16718de8d7fSPeter Avalos 16818de8d7fSPeter Avalos return ret; 16918de8d7fSPeter Avalos } 17018de8d7fSPeter Avalos 17118de8d7fSPeter Avalos /* Send a request to remove all identities. */ 17218de8d7fSPeter Avalos static int 173664f4763Szrj delete_all(int agent_fd, int qflag) 17418de8d7fSPeter Avalos { 17518de8d7fSPeter Avalos int ret = -1; 17618de8d7fSPeter Avalos 177ce74bacaSMatthew Dillon /* 178ce74bacaSMatthew Dillon * Since the agent might be forwarded, old or non-OpenSSH, when asked 179ce74bacaSMatthew Dillon * to remove all keys, attempt to remove both protocol v.1 and v.2 180ce74bacaSMatthew Dillon * keys. 181ce74bacaSMatthew Dillon */ 182e9778795SPeter Avalos if (ssh_remove_all_identities(agent_fd, 2) == 0) 18318de8d7fSPeter Avalos ret = 0; 184e9778795SPeter Avalos /* ignore error-code for ssh1 */ 185e9778795SPeter Avalos ssh_remove_all_identities(agent_fd, 1); 18618de8d7fSPeter Avalos 187664f4763Szrj if (ret != 0) 18818de8d7fSPeter Avalos fprintf(stderr, "Failed to remove all identities.\n"); 189664f4763Szrj else if (!qflag) 190664f4763Szrj fprintf(stderr, "All identities removed.\n"); 19118de8d7fSPeter Avalos 19218de8d7fSPeter Avalos return ret; 19318de8d7fSPeter Avalos } 19418de8d7fSPeter Avalos 19518de8d7fSPeter Avalos static int 196*0cbfa66cSDaniel Fojt add_file(int agent_fd, const char *filename, int key_only, int qflag, 197*0cbfa66cSDaniel Fojt const char *skprovider) 19818de8d7fSPeter Avalos { 199e9778795SPeter Avalos struct sshkey *private, *cert; 20018de8d7fSPeter Avalos char *comment = NULL; 20199e85e0dSPeter Avalos char msg[1024], *certpath = NULL; 202e9778795SPeter Avalos int r, fd, ret = -1; 203664f4763Szrj size_t i; 204664f4763Szrj u_int32_t left; 205e9778795SPeter Avalos struct sshbuf *keyblob; 206664f4763Szrj struct ssh_identitylist *idlist; 20718de8d7fSPeter Avalos 2081c188a7fSPeter Avalos if (strcmp(filename, "-") == 0) { 2091c188a7fSPeter Avalos fd = STDIN_FILENO; 2101c188a7fSPeter Avalos filename = "(stdin)"; 211*0cbfa66cSDaniel Fojt } else if ((fd = open(filename, O_RDONLY)) == -1) { 21218de8d7fSPeter Avalos perror(filename); 21318de8d7fSPeter Avalos return -1; 21418de8d7fSPeter Avalos } 21518de8d7fSPeter Avalos 21618de8d7fSPeter Avalos /* 21718de8d7fSPeter Avalos * Since we'll try to load a keyfile multiple times, permission errors 21818de8d7fSPeter Avalos * will occur multiple times, so check perms first and bail if wrong. 21918de8d7fSPeter Avalos */ 2201c188a7fSPeter Avalos if (fd != STDIN_FILENO) { 221e9778795SPeter Avalos if (sshkey_perm_ok(fd, filename) != 0) { 22218de8d7fSPeter Avalos close(fd); 22318de8d7fSPeter Avalos return -1; 2241c188a7fSPeter Avalos } 2251c188a7fSPeter Avalos } 226*0cbfa66cSDaniel Fojt if ((r = sshbuf_load_fd(fd, &keyblob)) != 0) { 227e9778795SPeter Avalos fprintf(stderr, "Error loading key \"%s\": %s\n", 228e9778795SPeter Avalos filename, ssh_err(r)); 229e9778795SPeter Avalos sshbuf_free(keyblob); 2301c188a7fSPeter Avalos close(fd); 2311c188a7fSPeter Avalos return -1; 2321c188a7fSPeter Avalos } 2331c188a7fSPeter Avalos close(fd); 23418de8d7fSPeter Avalos 23518de8d7fSPeter Avalos /* At first, try empty passphrase */ 236e9778795SPeter Avalos if ((r = sshkey_parse_private_fileblob(keyblob, "", &private, 237e9778795SPeter Avalos &comment)) != 0 && r != SSH_ERR_KEY_WRONG_PASSPHRASE) { 238e9778795SPeter Avalos fprintf(stderr, "Error loading key \"%s\": %s\n", 239e9778795SPeter Avalos filename, ssh_err(r)); 240e9778795SPeter Avalos goto fail_load; 241e9778795SPeter Avalos } 24236e94dc5SPeter Avalos /* try last */ 24336e94dc5SPeter Avalos if (private == NULL && pass != NULL) { 244e9778795SPeter Avalos if ((r = sshkey_parse_private_fileblob(keyblob, pass, &private, 245e9778795SPeter Avalos &comment)) != 0 && r != SSH_ERR_KEY_WRONG_PASSPHRASE) { 246e9778795SPeter Avalos fprintf(stderr, "Error loading key \"%s\": %s\n", 247e9778795SPeter Avalos filename, ssh_err(r)); 248e9778795SPeter Avalos goto fail_load; 24936e94dc5SPeter Avalos } 250e9778795SPeter Avalos } 25118de8d7fSPeter Avalos if (private == NULL) { 25218de8d7fSPeter Avalos /* clear passphrase since it did not work */ 25318de8d7fSPeter Avalos clear_pass(); 254e9778795SPeter Avalos snprintf(msg, sizeof msg, "Enter passphrase for %s%s: ", 255e9778795SPeter Avalos filename, confirm ? " (will confirm each use)" : ""); 25618de8d7fSPeter Avalos for (;;) { 25718de8d7fSPeter Avalos pass = read_passphrase(msg, RP_ALLOW_STDIN); 258e9778795SPeter Avalos if (strcmp(pass, "") == 0) 259e9778795SPeter Avalos goto fail_load; 260e9778795SPeter Avalos if ((r = sshkey_parse_private_fileblob(keyblob, pass, 261e9778795SPeter Avalos &private, &comment)) == 0) 262e9778795SPeter Avalos break; 263e9778795SPeter Avalos else if (r != SSH_ERR_KEY_WRONG_PASSPHRASE) { 264e9778795SPeter Avalos fprintf(stderr, 265e9778795SPeter Avalos "Error loading key \"%s\": %s\n", 266e9778795SPeter Avalos filename, ssh_err(r)); 267e9778795SPeter Avalos fail_load: 26818de8d7fSPeter Avalos clear_pass(); 269e9778795SPeter Avalos sshbuf_free(keyblob); 27018de8d7fSPeter Avalos return -1; 27118de8d7fSPeter Avalos } 27218de8d7fSPeter Avalos clear_pass(); 27318de8d7fSPeter Avalos snprintf(msg, sizeof msg, 274e9778795SPeter Avalos "Bad passphrase, try again for %s%s: ", filename, 275e9778795SPeter Avalos confirm ? " (will confirm each use)" : ""); 27618de8d7fSPeter Avalos } 27718de8d7fSPeter Avalos } 278e9778795SPeter Avalos if (comment == NULL || *comment == '\0') 279e9778795SPeter Avalos comment = xstrdup(filename); 280e9778795SPeter Avalos sshbuf_free(keyblob); 28118de8d7fSPeter Avalos 282664f4763Szrj /* For XMSS */ 283664f4763Szrj if ((r = sshkey_set_filename(private, filename)) != 0) { 284664f4763Szrj fprintf(stderr, "Could not add filename to private key: %s (%s)\n", 285664f4763Szrj filename, comment); 286664f4763Szrj goto out; 287664f4763Szrj } 288664f4763Szrj if (maxsign && minleft && 289664f4763Szrj (r = ssh_fetch_identitylist(agent_fd, &idlist)) == 0) { 290664f4763Szrj for (i = 0; i < idlist->nkeys; i++) { 291664f4763Szrj if (!sshkey_equal_public(idlist->keys[i], private)) 292664f4763Szrj continue; 293664f4763Szrj left = sshkey_signatures_left(idlist->keys[i]); 294664f4763Szrj if (left < minleft) { 295664f4763Szrj fprintf(stderr, 296664f4763Szrj "Only %d signatures left.\n", left); 297664f4763Szrj break; 298664f4763Szrj } 299664f4763Szrj fprintf(stderr, "Skipping update: "); 300664f4763Szrj if (left == minleft) { 301664f4763Szrj fprintf(stderr, 302664f4763Szrj "required signatures left (%d).\n", left); 303664f4763Szrj } else { 304664f4763Szrj fprintf(stderr, 305664f4763Szrj "more signatures left (%d) than" 306664f4763Szrj " required (%d).\n", left, minleft); 307664f4763Szrj } 308664f4763Szrj ssh_free_identitylist(idlist); 309664f4763Szrj goto out; 310664f4763Szrj } 311664f4763Szrj ssh_free_identitylist(idlist); 312664f4763Szrj } 313664f4763Szrj 314*0cbfa66cSDaniel Fojt if (!sshkey_is_sk(private)) 315*0cbfa66cSDaniel Fojt skprovider = NULL; /* Don't send constraint for other keys */ 316*0cbfa66cSDaniel Fojt else if (skprovider == NULL) { 317*0cbfa66cSDaniel Fojt fprintf(stderr, "Cannot load authenticator-hosted key %s " 318*0cbfa66cSDaniel Fojt "without provider\n", filename); 319*0cbfa66cSDaniel Fojt goto out; 320*0cbfa66cSDaniel Fojt } 321*0cbfa66cSDaniel Fojt 322e9778795SPeter Avalos if ((r = ssh_add_identity_constrained(agent_fd, private, comment, 323*0cbfa66cSDaniel Fojt lifetime, confirm, maxsign, skprovider)) == 0) { 32418de8d7fSPeter Avalos ret = 0; 325664f4763Szrj if (!qflag) { 326664f4763Szrj fprintf(stderr, "Identity added: %s (%s)\n", 327664f4763Szrj filename, comment); 328664f4763Szrj if (lifetime != 0) { 32918de8d7fSPeter Avalos fprintf(stderr, 330*0cbfa66cSDaniel Fojt "Lifetime set to %ld seconds\n", lifetime); 331664f4763Szrj } 332664f4763Szrj if (confirm != 0) { 333664f4763Szrj fprintf(stderr, "The user must confirm " 334664f4763Szrj "each use of the key\n"); 335664f4763Szrj } 336664f4763Szrj } 33718de8d7fSPeter Avalos } else { 338e9778795SPeter Avalos fprintf(stderr, "Could not add identity \"%s\": %s\n", 339e9778795SPeter Avalos filename, ssh_err(r)); 34018de8d7fSPeter Avalos } 34118de8d7fSPeter Avalos 34299e85e0dSPeter Avalos /* Skip trying to load the cert if requested */ 34399e85e0dSPeter Avalos if (key_only) 34499e85e0dSPeter Avalos goto out; 345856ea928SPeter Avalos 346856ea928SPeter Avalos /* Now try to add the certificate flavour too */ 347856ea928SPeter Avalos xasprintf(&certpath, "%s-cert.pub", filename); 348e9778795SPeter Avalos if ((r = sshkey_load_public(certpath, &cert, NULL)) != 0) { 349e9778795SPeter Avalos if (r != SSH_ERR_SYSTEM_ERROR || errno != ENOENT) 350e9778795SPeter Avalos error("Failed to load certificate \"%s\": %s", 351e9778795SPeter Avalos certpath, ssh_err(r)); 352856ea928SPeter Avalos goto out; 353e9778795SPeter Avalos } 354856ea928SPeter Avalos 355e9778795SPeter Avalos if (!sshkey_equal_public(cert, private)) { 356856ea928SPeter Avalos error("Certificate %s does not match private key %s", 357856ea928SPeter Avalos certpath, filename); 358e9778795SPeter Avalos sshkey_free(cert); 359856ea928SPeter Avalos goto out; 360856ea928SPeter Avalos } 361856ea928SPeter Avalos 362856ea928SPeter Avalos /* Graft with private bits */ 363e9778795SPeter Avalos if ((r = sshkey_to_certified(private)) != 0) { 364e9778795SPeter Avalos error("%s: sshkey_to_certified: %s", __func__, ssh_err(r)); 365e9778795SPeter Avalos sshkey_free(cert); 366856ea928SPeter Avalos goto out; 367856ea928SPeter Avalos } 368e9778795SPeter Avalos if ((r = sshkey_cert_copy(cert, private)) != 0) { 369ce74bacaSMatthew Dillon error("%s: sshkey_cert_copy: %s", __func__, ssh_err(r)); 370e9778795SPeter Avalos sshkey_free(cert); 371e9778795SPeter Avalos goto out; 372e9778795SPeter Avalos } 373e9778795SPeter Avalos sshkey_free(cert); 374856ea928SPeter Avalos 375e9778795SPeter Avalos if ((r = ssh_add_identity_constrained(agent_fd, private, comment, 376*0cbfa66cSDaniel Fojt lifetime, confirm, maxsign, skprovider)) != 0) { 377e9778795SPeter Avalos error("Certificate %s (%s) add failed: %s", certpath, 378e9778795SPeter Avalos private->cert->key_id, ssh_err(r)); 379e9778795SPeter Avalos goto out; 380856ea928SPeter Avalos } 381664f4763Szrj /* success */ 382664f4763Szrj if (!qflag) { 383856ea928SPeter Avalos fprintf(stderr, "Certificate added: %s (%s)\n", certpath, 384856ea928SPeter Avalos private->cert->key_id); 385664f4763Szrj if (lifetime != 0) { 386*0cbfa66cSDaniel Fojt fprintf(stderr, "Lifetime set to %ld seconds\n", 387664f4763Szrj lifetime); 388664f4763Szrj } 389664f4763Szrj if (confirm != 0) { 390664f4763Szrj fprintf(stderr, "The user must confirm each use " 391664f4763Szrj "of the key\n"); 392664f4763Szrj } 393664f4763Szrj } 394664f4763Szrj 395856ea928SPeter Avalos out: 39636e94dc5SPeter Avalos free(certpath); 39736e94dc5SPeter Avalos free(comment); 398e9778795SPeter Avalos sshkey_free(private); 39918de8d7fSPeter Avalos 40018de8d7fSPeter Avalos return ret; 40118de8d7fSPeter Avalos } 40218de8d7fSPeter Avalos 40318de8d7fSPeter Avalos static int 404664f4763Szrj update_card(int agent_fd, int add, const char *id, int qflag) 40518de8d7fSPeter Avalos { 40636e94dc5SPeter Avalos char *pin = NULL; 407e9778795SPeter Avalos int r, ret = -1; 40818de8d7fSPeter Avalos 40936e94dc5SPeter Avalos if (add) { 41036e94dc5SPeter Avalos if ((pin = read_passphrase("Enter passphrase for PKCS#11: ", 41136e94dc5SPeter Avalos RP_ALLOW_STDIN)) == NULL) 41218de8d7fSPeter Avalos return -1; 41336e94dc5SPeter Avalos } 41418de8d7fSPeter Avalos 415e9778795SPeter Avalos if ((r = ssh_update_card(agent_fd, add, id, pin == NULL ? "" : pin, 416e9778795SPeter Avalos lifetime, confirm)) == 0) { 417664f4763Szrj ret = 0; 418664f4763Szrj if (!qflag) { 41918de8d7fSPeter Avalos fprintf(stderr, "Card %s: %s\n", 42018de8d7fSPeter Avalos add ? "added" : "removed", id); 421664f4763Szrj } 42218de8d7fSPeter Avalos } else { 423e9778795SPeter Avalos fprintf(stderr, "Could not %s card \"%s\": %s\n", 424e9778795SPeter Avalos add ? "add" : "remove", id, ssh_err(r)); 42518de8d7fSPeter Avalos ret = -1; 42618de8d7fSPeter Avalos } 42736e94dc5SPeter Avalos free(pin); 42818de8d7fSPeter Avalos return ret; 42918de8d7fSPeter Avalos } 43018de8d7fSPeter Avalos 43118de8d7fSPeter Avalos static int 432664f4763Szrj test_key(int agent_fd, const char *filename) 433664f4763Szrj { 434664f4763Szrj struct sshkey *key = NULL; 435664f4763Szrj u_char *sig = NULL; 436664f4763Szrj size_t slen = 0; 437664f4763Szrj int r, ret = -1; 438664f4763Szrj char data[1024]; 439664f4763Szrj 440664f4763Szrj if ((r = sshkey_load_public(filename, &key, NULL)) != 0) { 441664f4763Szrj error("Couldn't read public key %s: %s", filename, ssh_err(r)); 442664f4763Szrj return -1; 443664f4763Szrj } 444664f4763Szrj arc4random_buf(data, sizeof(data)); 445664f4763Szrj if ((r = ssh_agent_sign(agent_fd, key, &sig, &slen, data, sizeof(data), 446664f4763Szrj NULL, 0)) != 0) { 447664f4763Szrj error("Agent signature failed for %s: %s", 448664f4763Szrj filename, ssh_err(r)); 449664f4763Szrj goto done; 450664f4763Szrj } 451664f4763Szrj if ((r = sshkey_verify(key, sig, slen, data, sizeof(data), 452*0cbfa66cSDaniel Fojt NULL, 0, NULL)) != 0) { 453664f4763Szrj error("Signature verification failed for %s: %s", 454664f4763Szrj filename, ssh_err(r)); 455664f4763Szrj goto done; 456664f4763Szrj } 457664f4763Szrj /* success */ 458664f4763Szrj ret = 0; 459664f4763Szrj done: 460664f4763Szrj free(sig); 461664f4763Szrj sshkey_free(key); 462664f4763Szrj return ret; 463664f4763Szrj } 464664f4763Szrj 465664f4763Szrj static int 466e9778795SPeter Avalos list_identities(int agent_fd, int do_fp) 46718de8d7fSPeter Avalos { 468e9778795SPeter Avalos char *fp; 469ce74bacaSMatthew Dillon int r; 470e9778795SPeter Avalos struct ssh_identitylist *idlist; 471664f4763Szrj u_int32_t left; 472e9778795SPeter Avalos size_t i; 47318de8d7fSPeter Avalos 474ce74bacaSMatthew Dillon if ((r = ssh_fetch_identitylist(agent_fd, &idlist)) != 0) { 475e9778795SPeter Avalos if (r != SSH_ERR_AGENT_NO_IDENTITIES) 476ce74bacaSMatthew Dillon fprintf(stderr, "error fetching identities: %s\n", 477ce74bacaSMatthew Dillon ssh_err(r)); 478ce74bacaSMatthew Dillon else 479ce74bacaSMatthew Dillon printf("The agent has no identities.\n"); 480ce74bacaSMatthew Dillon return -1; 481e9778795SPeter Avalos } 482e9778795SPeter Avalos for (i = 0; i < idlist->nkeys; i++) { 48318de8d7fSPeter Avalos if (do_fp) { 484e9778795SPeter Avalos fp = sshkey_fingerprint(idlist->keys[i], 485e9778795SPeter Avalos fingerprint_hash, SSH_FP_DEFAULT); 486ce74bacaSMatthew Dillon printf("%u %s %s (%s)\n", sshkey_size(idlist->keys[i]), 487ce74bacaSMatthew Dillon fp == NULL ? "(null)" : fp, idlist->comments[i], 488e9778795SPeter Avalos sshkey_type(idlist->keys[i])); 48936e94dc5SPeter Avalos free(fp); 49018de8d7fSPeter Avalos } else { 491ce74bacaSMatthew Dillon if ((r = sshkey_write(idlist->keys[i], stdout)) != 0) { 492e9778795SPeter Avalos fprintf(stderr, "sshkey_write: %s\n", 493e9778795SPeter Avalos ssh_err(r)); 494e9778795SPeter Avalos continue; 49518de8d7fSPeter Avalos } 496664f4763Szrj fprintf(stdout, " %s", idlist->comments[i]); 497664f4763Szrj left = sshkey_signatures_left(idlist->keys[i]); 498664f4763Szrj if (left > 0) 499664f4763Szrj fprintf(stdout, 500664f4763Szrj " [signatures left %d]", left); 501664f4763Szrj fprintf(stdout, "\n"); 50218de8d7fSPeter Avalos } 50318de8d7fSPeter Avalos } 504e9778795SPeter Avalos ssh_free_identitylist(idlist); 50518de8d7fSPeter Avalos return 0; 50618de8d7fSPeter Avalos } 50718de8d7fSPeter Avalos 50818de8d7fSPeter Avalos static int 509e9778795SPeter Avalos lock_agent(int agent_fd, int lock) 51018de8d7fSPeter Avalos { 51118de8d7fSPeter Avalos char prompt[100], *p1, *p2; 512e9778795SPeter Avalos int r, passok = 1, ret = -1; 51318de8d7fSPeter Avalos 51418de8d7fSPeter Avalos strlcpy(prompt, "Enter lock password: ", sizeof(prompt)); 51518de8d7fSPeter Avalos p1 = read_passphrase(prompt, RP_ALLOW_STDIN); 51618de8d7fSPeter Avalos if (lock) { 51718de8d7fSPeter Avalos strlcpy(prompt, "Again: ", sizeof prompt); 51818de8d7fSPeter Avalos p2 = read_passphrase(prompt, RP_ALLOW_STDIN); 51918de8d7fSPeter Avalos if (strcmp(p1, p2) != 0) { 52018de8d7fSPeter Avalos fprintf(stderr, "Passwords do not match.\n"); 52118de8d7fSPeter Avalos passok = 0; 52218de8d7fSPeter Avalos } 523*0cbfa66cSDaniel Fojt freezero(p2, strlen(p2)); 52418de8d7fSPeter Avalos } 525e9778795SPeter Avalos if (passok) { 526e9778795SPeter Avalos if ((r = ssh_lock_agent(agent_fd, lock, p1)) == 0) { 52718de8d7fSPeter Avalos fprintf(stderr, "Agent %slocked.\n", lock ? "" : "un"); 52818de8d7fSPeter Avalos ret = 0; 529e9778795SPeter Avalos } else { 530e9778795SPeter Avalos fprintf(stderr, "Failed to %slock agent: %s\n", 531e9778795SPeter Avalos lock ? "" : "un", ssh_err(r)); 532e9778795SPeter Avalos } 533e9778795SPeter Avalos } 534*0cbfa66cSDaniel Fojt freezero(p1, strlen(p1)); 53518de8d7fSPeter Avalos return (ret); 53618de8d7fSPeter Avalos } 53718de8d7fSPeter Avalos 53818de8d7fSPeter Avalos static int 539*0cbfa66cSDaniel Fojt load_resident_keys(int agent_fd, const char *skprovider, int qflag) 540*0cbfa66cSDaniel Fojt { 541*0cbfa66cSDaniel Fojt struct sshkey **keys; 542*0cbfa66cSDaniel Fojt size_t nkeys, i; 543*0cbfa66cSDaniel Fojt int r, ok = 0; 544*0cbfa66cSDaniel Fojt char *fp; 545*0cbfa66cSDaniel Fojt 546*0cbfa66cSDaniel Fojt pass = read_passphrase("Enter PIN for authenticator: ", RP_ALLOW_STDIN); 547*0cbfa66cSDaniel Fojt if ((r = sshsk_load_resident(skprovider, NULL, pass, 548*0cbfa66cSDaniel Fojt &keys, &nkeys)) != 0) { 549*0cbfa66cSDaniel Fojt error("Unable to load resident keys: %s", ssh_err(r)); 550*0cbfa66cSDaniel Fojt return r; 551*0cbfa66cSDaniel Fojt } 552*0cbfa66cSDaniel Fojt for (i = 0; i < nkeys; i++) { 553*0cbfa66cSDaniel Fojt if ((fp = sshkey_fingerprint(keys[i], 554*0cbfa66cSDaniel Fojt fingerprint_hash, SSH_FP_DEFAULT)) == NULL) 555*0cbfa66cSDaniel Fojt fatal("%s: sshkey_fingerprint failed", __func__); 556*0cbfa66cSDaniel Fojt if ((r = ssh_add_identity_constrained(agent_fd, keys[i], "", 557*0cbfa66cSDaniel Fojt lifetime, confirm, maxsign, skprovider)) != 0) { 558*0cbfa66cSDaniel Fojt error("Unable to add key %s %s", 559*0cbfa66cSDaniel Fojt sshkey_type(keys[i]), fp); 560*0cbfa66cSDaniel Fojt free(fp); 561*0cbfa66cSDaniel Fojt ok = r; 562*0cbfa66cSDaniel Fojt continue; 563*0cbfa66cSDaniel Fojt } 564*0cbfa66cSDaniel Fojt if (ok == 0) 565*0cbfa66cSDaniel Fojt ok = 1; 566*0cbfa66cSDaniel Fojt if (!qflag) { 567*0cbfa66cSDaniel Fojt fprintf(stderr, "Resident identity added: %s %s\n", 568*0cbfa66cSDaniel Fojt sshkey_type(keys[i]), fp); 569*0cbfa66cSDaniel Fojt if (lifetime != 0) { 570*0cbfa66cSDaniel Fojt fprintf(stderr, 571*0cbfa66cSDaniel Fojt "Lifetime set to %ld seconds\n", lifetime); 572*0cbfa66cSDaniel Fojt } 573*0cbfa66cSDaniel Fojt if (confirm != 0) { 574*0cbfa66cSDaniel Fojt fprintf(stderr, "The user must confirm " 575*0cbfa66cSDaniel Fojt "each use of the key\n"); 576*0cbfa66cSDaniel Fojt } 577*0cbfa66cSDaniel Fojt } 578*0cbfa66cSDaniel Fojt free(fp); 579*0cbfa66cSDaniel Fojt sshkey_free(keys[i]); 580*0cbfa66cSDaniel Fojt } 581*0cbfa66cSDaniel Fojt free(keys); 582*0cbfa66cSDaniel Fojt if (nkeys == 0) 583*0cbfa66cSDaniel Fojt return SSH_ERR_KEY_NOT_FOUND; 584*0cbfa66cSDaniel Fojt return ok == 1 ? 0 : ok; 585*0cbfa66cSDaniel Fojt } 586*0cbfa66cSDaniel Fojt 587*0cbfa66cSDaniel Fojt static int 588*0cbfa66cSDaniel Fojt do_file(int agent_fd, int deleting, int key_only, char *file, int qflag, 589*0cbfa66cSDaniel Fojt const char *skprovider) 59018de8d7fSPeter Avalos { 59118de8d7fSPeter Avalos if (deleting) { 592ce74bacaSMatthew Dillon if (delete_file(agent_fd, file, key_only, qflag) == -1) 59318de8d7fSPeter Avalos return -1; 59418de8d7fSPeter Avalos } else { 595*0cbfa66cSDaniel Fojt if (add_file(agent_fd, file, key_only, qflag, skprovider) == -1) 59618de8d7fSPeter Avalos return -1; 59718de8d7fSPeter Avalos } 59818de8d7fSPeter Avalos return 0; 59918de8d7fSPeter Avalos } 60018de8d7fSPeter Avalos 60118de8d7fSPeter Avalos static void 60218de8d7fSPeter Avalos usage(void) 60318de8d7fSPeter Avalos { 604*0cbfa66cSDaniel Fojt fprintf(stderr, 605*0cbfa66cSDaniel Fojt "usage: ssh-add [-cDdKkLlqvXx] [-E fingerprint_hash] [-S provider] [-t life]\n" 606*0cbfa66cSDaniel Fojt #ifdef WITH_XMSS 607*0cbfa66cSDaniel Fojt " [-M maxsign] [-m minleft]\n" 608*0cbfa66cSDaniel Fojt #endif 609*0cbfa66cSDaniel Fojt " [file ...]\n" 610*0cbfa66cSDaniel Fojt " ssh-add -s pkcs11\n" 611*0cbfa66cSDaniel Fojt " ssh-add -e pkcs11\n" 612*0cbfa66cSDaniel Fojt " ssh-add -T pubkey ...\n" 613*0cbfa66cSDaniel Fojt ); 61418de8d7fSPeter Avalos } 61518de8d7fSPeter Avalos 61618de8d7fSPeter Avalos int 61718de8d7fSPeter Avalos main(int argc, char **argv) 61818de8d7fSPeter Avalos { 61918de8d7fSPeter Avalos extern char *optarg; 62018de8d7fSPeter Avalos extern int optind; 621e9778795SPeter Avalos int agent_fd; 622*0cbfa66cSDaniel Fojt char *pkcs11provider = NULL, *skprovider = NULL; 623*0cbfa66cSDaniel Fojt int r, i, ch, deleting = 0, ret = 0, key_only = 0, do_download = 0; 624664f4763Szrj int xflag = 0, lflag = 0, Dflag = 0, qflag = 0, Tflag = 0; 625664f4763Szrj SyslogFacility log_facility = SYSLOG_FACILITY_AUTH; 626664f4763Szrj LogLevel log_level = SYSLOG_LEVEL_INFO; 62718de8d7fSPeter Avalos 62818de8d7fSPeter Avalos /* Ensure that fds 0, 1 and 2 are open or directed to /dev/null */ 62918de8d7fSPeter Avalos sanitise_stdfd(); 63018de8d7fSPeter Avalos 63118de8d7fSPeter Avalos __progname = ssh_get_progname(argv[0]); 63218de8d7fSPeter Avalos seed_rng(); 63318de8d7fSPeter Avalos 634664f4763Szrj log_init(__progname, log_level, log_facility, 1); 63518de8d7fSPeter Avalos 636e9778795SPeter Avalos setvbuf(stdout, NULL, _IOLBF, 0); 63736e94dc5SPeter Avalos 638e9778795SPeter Avalos /* First, get a connection to the authentication agent. */ 639e9778795SPeter Avalos switch (r = ssh_get_authentication_socket(&agent_fd)) { 640e9778795SPeter Avalos case 0: 641e9778795SPeter Avalos break; 642e9778795SPeter Avalos case SSH_ERR_AGENT_NOT_PRESENT: 643e9778795SPeter Avalos fprintf(stderr, "Could not open a connection to your " 644e9778795SPeter Avalos "authentication agent.\n"); 645e9778795SPeter Avalos exit(2); 646e9778795SPeter Avalos default: 647e9778795SPeter Avalos fprintf(stderr, "Error connecting to agent: %s\n", ssh_err(r)); 64818de8d7fSPeter Avalos exit(2); 64918de8d7fSPeter Avalos } 650e9778795SPeter Avalos 651*0cbfa66cSDaniel Fojt skprovider = getenv("SSH_SK_PROVIDER"); 652*0cbfa66cSDaniel Fojt 653*0cbfa66cSDaniel Fojt while ((ch = getopt(argc, argv, "vkKlLcdDTxXE:e:M:m:qs:S:t:")) != -1) { 65418de8d7fSPeter Avalos switch (ch) { 655664f4763Szrj case 'v': 656664f4763Szrj if (log_level == SYSLOG_LEVEL_INFO) 657664f4763Szrj log_level = SYSLOG_LEVEL_DEBUG1; 658664f4763Szrj else if (log_level < SYSLOG_LEVEL_DEBUG3) 659664f4763Szrj log_level++; 660664f4763Szrj break; 661e9778795SPeter Avalos case 'E': 662e9778795SPeter Avalos fingerprint_hash = ssh_digest_alg_by_name(optarg); 663e9778795SPeter Avalos if (fingerprint_hash == -1) 664e9778795SPeter Avalos fatal("Invalid hash algorithm \"%s\"", optarg); 665e9778795SPeter Avalos break; 66699e85e0dSPeter Avalos case 'k': 66799e85e0dSPeter Avalos key_only = 1; 66899e85e0dSPeter Avalos break; 669*0cbfa66cSDaniel Fojt case 'K': 670*0cbfa66cSDaniel Fojt do_download = 1; 671*0cbfa66cSDaniel Fojt break; 67218de8d7fSPeter Avalos case 'l': 67318de8d7fSPeter Avalos case 'L': 674e9778795SPeter Avalos if (lflag != 0) 675e9778795SPeter Avalos fatal("-%c flag already specified", lflag); 676e9778795SPeter Avalos lflag = ch; 677e9778795SPeter Avalos break; 67818de8d7fSPeter Avalos case 'x': 67918de8d7fSPeter Avalos case 'X': 680e9778795SPeter Avalos if (xflag != 0) 681e9778795SPeter Avalos fatal("-%c flag already specified", xflag); 682e9778795SPeter Avalos xflag = ch; 683e9778795SPeter Avalos break; 68418de8d7fSPeter Avalos case 'c': 68518de8d7fSPeter Avalos confirm = 1; 68618de8d7fSPeter Avalos break; 687664f4763Szrj case 'm': 688664f4763Szrj minleft = (int)strtonum(optarg, 1, UINT_MAX, NULL); 689664f4763Szrj if (minleft == 0) { 690664f4763Szrj usage(); 691664f4763Szrj ret = 1; 692664f4763Szrj goto done; 693664f4763Szrj } 694664f4763Szrj break; 695664f4763Szrj case 'M': 696664f4763Szrj maxsign = (int)strtonum(optarg, 1, UINT_MAX, NULL); 697664f4763Szrj if (maxsign == 0) { 698664f4763Szrj usage(); 699664f4763Szrj ret = 1; 700664f4763Szrj goto done; 701664f4763Szrj } 702664f4763Szrj break; 70318de8d7fSPeter Avalos case 'd': 70418de8d7fSPeter Avalos deleting = 1; 70518de8d7fSPeter Avalos break; 70618de8d7fSPeter Avalos case 'D': 707e9778795SPeter Avalos Dflag = 1; 708e9778795SPeter Avalos break; 70918de8d7fSPeter Avalos case 's': 710856ea928SPeter Avalos pkcs11provider = optarg; 71118de8d7fSPeter Avalos break; 712*0cbfa66cSDaniel Fojt case 'S': 713*0cbfa66cSDaniel Fojt skprovider = optarg; 714*0cbfa66cSDaniel Fojt break; 71518de8d7fSPeter Avalos case 'e': 71618de8d7fSPeter Avalos deleting = 1; 717856ea928SPeter Avalos pkcs11provider = optarg; 71818de8d7fSPeter Avalos break; 71918de8d7fSPeter Avalos case 't': 720*0cbfa66cSDaniel Fojt if ((lifetime = convtime(optarg)) == -1 || 721*0cbfa66cSDaniel Fojt lifetime < 0 || (u_long)lifetime > UINT32_MAX) { 72218de8d7fSPeter Avalos fprintf(stderr, "Invalid lifetime\n"); 72318de8d7fSPeter Avalos ret = 1; 72418de8d7fSPeter Avalos goto done; 72518de8d7fSPeter Avalos } 72618de8d7fSPeter Avalos break; 727ce74bacaSMatthew Dillon case 'q': 728ce74bacaSMatthew Dillon qflag = 1; 729ce74bacaSMatthew Dillon break; 730664f4763Szrj case 'T': 731664f4763Szrj Tflag = 1; 732664f4763Szrj break; 73318de8d7fSPeter Avalos default: 73418de8d7fSPeter Avalos usage(); 73518de8d7fSPeter Avalos ret = 1; 73618de8d7fSPeter Avalos goto done; 73718de8d7fSPeter Avalos } 73818de8d7fSPeter Avalos } 739664f4763Szrj log_init(__progname, log_level, log_facility, 1); 740e9778795SPeter Avalos 741e9778795SPeter Avalos if ((xflag != 0) + (lflag != 0) + (Dflag != 0) > 1) 742e9778795SPeter Avalos fatal("Invalid combination of actions"); 743e9778795SPeter Avalos else if (xflag) { 744e9778795SPeter Avalos if (lock_agent(agent_fd, xflag == 'x' ? 1 : 0) == -1) 745e9778795SPeter Avalos ret = 1; 746e9778795SPeter Avalos goto done; 747e9778795SPeter Avalos } else if (lflag) { 748e9778795SPeter Avalos if (list_identities(agent_fd, lflag == 'l' ? 1 : 0) == -1) 749e9778795SPeter Avalos ret = 1; 750e9778795SPeter Avalos goto done; 751e9778795SPeter Avalos } else if (Dflag) { 752664f4763Szrj if (delete_all(agent_fd, qflag) == -1) 753e9778795SPeter Avalos ret = 1; 754e9778795SPeter Avalos goto done; 755e9778795SPeter Avalos } 756e9778795SPeter Avalos 757*0cbfa66cSDaniel Fojt #ifdef ENABLE_SK_INTERNAL 758*0cbfa66cSDaniel Fojt if (skprovider == NULL) 759*0cbfa66cSDaniel Fojt skprovider = "internal"; 760*0cbfa66cSDaniel Fojt #endif 761*0cbfa66cSDaniel Fojt 76218de8d7fSPeter Avalos argc -= optind; 76318de8d7fSPeter Avalos argv += optind; 764664f4763Szrj if (Tflag) { 765664f4763Szrj if (argc <= 0) 766664f4763Szrj fatal("no keys to test"); 767664f4763Szrj for (r = i = 0; i < argc; i++) 768664f4763Szrj r |= test_key(agent_fd, argv[i]); 769664f4763Szrj ret = r == 0 ? 0 : 1; 770664f4763Szrj goto done; 771664f4763Szrj } 772856ea928SPeter Avalos if (pkcs11provider != NULL) { 773664f4763Szrj if (update_card(agent_fd, !deleting, pkcs11provider, 774664f4763Szrj qflag) == -1) 77518de8d7fSPeter Avalos ret = 1; 77618de8d7fSPeter Avalos goto done; 77718de8d7fSPeter Avalos } 778*0cbfa66cSDaniel Fojt if (do_download) { 779*0cbfa66cSDaniel Fojt if (skprovider == NULL) 780*0cbfa66cSDaniel Fojt fatal("Cannot download keys without provider"); 781*0cbfa66cSDaniel Fojt if (load_resident_keys(agent_fd, skprovider, qflag) != 0) 782*0cbfa66cSDaniel Fojt ret = 1; 783*0cbfa66cSDaniel Fojt goto done; 784*0cbfa66cSDaniel Fojt } 78518de8d7fSPeter Avalos if (argc == 0) { 786e9778795SPeter Avalos char buf[PATH_MAX]; 78718de8d7fSPeter Avalos struct passwd *pw; 78818de8d7fSPeter Avalos struct stat st; 78918de8d7fSPeter Avalos int count = 0; 79018de8d7fSPeter Avalos 79118de8d7fSPeter Avalos if ((pw = getpwuid(getuid())) == NULL) { 79218de8d7fSPeter Avalos fprintf(stderr, "No user found with uid %u\n", 79318de8d7fSPeter Avalos (u_int)getuid()); 79418de8d7fSPeter Avalos ret = 1; 79518de8d7fSPeter Avalos goto done; 79618de8d7fSPeter Avalos } 79718de8d7fSPeter Avalos 79818de8d7fSPeter Avalos for (i = 0; default_files[i]; i++) { 79918de8d7fSPeter Avalos snprintf(buf, sizeof(buf), "%s/%s", pw->pw_dir, 80018de8d7fSPeter Avalos default_files[i]); 801*0cbfa66cSDaniel Fojt if (stat(buf, &st) == -1) 80218de8d7fSPeter Avalos continue; 803ce74bacaSMatthew Dillon if (do_file(agent_fd, deleting, key_only, buf, 804*0cbfa66cSDaniel Fojt qflag, skprovider) == -1) 80518de8d7fSPeter Avalos ret = 1; 80618de8d7fSPeter Avalos else 80718de8d7fSPeter Avalos count++; 80818de8d7fSPeter Avalos } 80918de8d7fSPeter Avalos if (count == 0) 81018de8d7fSPeter Avalos ret = 1; 81118de8d7fSPeter Avalos } else { 81218de8d7fSPeter Avalos for (i = 0; i < argc; i++) { 813e9778795SPeter Avalos if (do_file(agent_fd, deleting, key_only, 814*0cbfa66cSDaniel Fojt argv[i], qflag, skprovider) == -1) 81518de8d7fSPeter Avalos ret = 1; 81618de8d7fSPeter Avalos } 81718de8d7fSPeter Avalos } 81818de8d7fSPeter Avalos done: 819*0cbfa66cSDaniel Fojt clear_pass(); 820e9778795SPeter Avalos ssh_close_authentication_socket(agent_fd); 82118de8d7fSPeter Avalos return ret; 82218de8d7fSPeter Avalos } 823