1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
3*0Sstevel@tonic-gate  * Use is subject to license terms.
4*0Sstevel@tonic-gate  */
5*0Sstevel@tonic-gate /*
6*0Sstevel@tonic-gate  * Author: Tatu Ylonen <ylo@cs.hut.fi>
7*0Sstevel@tonic-gate  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8*0Sstevel@tonic-gate  *                    All rights reserved
9*0Sstevel@tonic-gate  * Adds an identity to the authentication server, or removes an identity.
10*0Sstevel@tonic-gate  *
11*0Sstevel@tonic-gate  * As far as I am concerned, the code I have written for this software
12*0Sstevel@tonic-gate  * can be used freely for any purpose.  Any derived versions of this
13*0Sstevel@tonic-gate  * software must be clearly marked as such, and if the derived work is
14*0Sstevel@tonic-gate  * incompatible with the protocol description in the RFC file, it must be
15*0Sstevel@tonic-gate  * called by a name other than "ssh" or "Secure Shell".
16*0Sstevel@tonic-gate  *
17*0Sstevel@tonic-gate  * SSH2 implementation,
18*0Sstevel@tonic-gate  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * Redistribution and use in source and binary forms, with or without
21*0Sstevel@tonic-gate  * modification, are permitted provided that the following conditions
22*0Sstevel@tonic-gate  * are met:
23*0Sstevel@tonic-gate  * 1. Redistributions of source code must retain the above copyright
24*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer.
25*0Sstevel@tonic-gate  * 2. Redistributions in binary form must reproduce the above copyright
26*0Sstevel@tonic-gate  *    notice, this list of conditions and the following disclaimer in the
27*0Sstevel@tonic-gate  *    documentation and/or other materials provided with the distribution.
28*0Sstevel@tonic-gate  *
29*0Sstevel@tonic-gate  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
30*0Sstevel@tonic-gate  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
31*0Sstevel@tonic-gate  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
32*0Sstevel@tonic-gate  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
33*0Sstevel@tonic-gate  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
34*0Sstevel@tonic-gate  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
35*0Sstevel@tonic-gate  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
36*0Sstevel@tonic-gate  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
37*0Sstevel@tonic-gate  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
38*0Sstevel@tonic-gate  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
39*0Sstevel@tonic-gate  */
40*0Sstevel@tonic-gate 
41*0Sstevel@tonic-gate #include "includes.h"
42*0Sstevel@tonic-gate RCSID("$OpenBSD: ssh-add.c,v 1.63 2002/09/19 15:51:23 markus Exp $");
43*0Sstevel@tonic-gate 
44*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
45*0Sstevel@tonic-gate 
46*0Sstevel@tonic-gate #include <openssl/evp.h>
47*0Sstevel@tonic-gate 
48*0Sstevel@tonic-gate #include "ssh.h"
49*0Sstevel@tonic-gate #include "rsa.h"
50*0Sstevel@tonic-gate #include "log.h"
51*0Sstevel@tonic-gate #include "xmalloc.h"
52*0Sstevel@tonic-gate #include "key.h"
53*0Sstevel@tonic-gate #include "authfd.h"
54*0Sstevel@tonic-gate #include "authfile.h"
55*0Sstevel@tonic-gate #include "pathnames.h"
56*0Sstevel@tonic-gate #include "readpass.h"
57*0Sstevel@tonic-gate #include "misc.h"
58*0Sstevel@tonic-gate 
59*0Sstevel@tonic-gate #ifdef HAVE___PROGNAME
60*0Sstevel@tonic-gate extern char *__progname;
61*0Sstevel@tonic-gate #else
62*0Sstevel@tonic-gate char *__progname;
63*0Sstevel@tonic-gate #endif
64*0Sstevel@tonic-gate 
65*0Sstevel@tonic-gate /* argv0 */
66*0Sstevel@tonic-gate extern char *__progname;
67*0Sstevel@tonic-gate 
68*0Sstevel@tonic-gate /* Default files to add */
69*0Sstevel@tonic-gate static char *default_files[] = {
70*0Sstevel@tonic-gate 	_PATH_SSH_CLIENT_ID_RSA,
71*0Sstevel@tonic-gate 	_PATH_SSH_CLIENT_ID_DSA,
72*0Sstevel@tonic-gate 	_PATH_SSH_CLIENT_IDENTITY,
73*0Sstevel@tonic-gate 	NULL
74*0Sstevel@tonic-gate };
75*0Sstevel@tonic-gate 
76*0Sstevel@tonic-gate /* Default lifetime (0 == forever) */
77*0Sstevel@tonic-gate static int lifetime = 0;
78*0Sstevel@tonic-gate 
79*0Sstevel@tonic-gate /* we keep a cache of one passphrases */
80*0Sstevel@tonic-gate static char *pass = NULL;
81*0Sstevel@tonic-gate static void
82*0Sstevel@tonic-gate clear_pass(void)
83*0Sstevel@tonic-gate {
84*0Sstevel@tonic-gate 	if (pass) {
85*0Sstevel@tonic-gate 		memset(pass, 0, strlen(pass));
86*0Sstevel@tonic-gate 		xfree(pass);
87*0Sstevel@tonic-gate 		pass = NULL;
88*0Sstevel@tonic-gate 	}
89*0Sstevel@tonic-gate }
90*0Sstevel@tonic-gate 
91*0Sstevel@tonic-gate static int
92*0Sstevel@tonic-gate delete_file(AuthenticationConnection *ac, const char *filename)
93*0Sstevel@tonic-gate {
94*0Sstevel@tonic-gate 	Key *public;
95*0Sstevel@tonic-gate 	char *comment = NULL;
96*0Sstevel@tonic-gate 	int ret = -1;
97*0Sstevel@tonic-gate 
98*0Sstevel@tonic-gate 	public = key_load_public(filename, &comment);
99*0Sstevel@tonic-gate 	if (public == NULL) {
100*0Sstevel@tonic-gate 		printf(gettext("Bad key file %s\n"), filename);
101*0Sstevel@tonic-gate 		return -1;
102*0Sstevel@tonic-gate 	}
103*0Sstevel@tonic-gate 	if (ssh_remove_identity(ac, public)) {
104*0Sstevel@tonic-gate 		fprintf(stderr, gettext("Identity removed: %s (%s)\n"),
105*0Sstevel@tonic-gate 			filename, comment);
106*0Sstevel@tonic-gate 		ret = 0;
107*0Sstevel@tonic-gate 	} else
108*0Sstevel@tonic-gate 		fprintf(stderr, gettext("Could not remove identity: %s\n"),
109*0Sstevel@tonic-gate 			filename);
110*0Sstevel@tonic-gate 
111*0Sstevel@tonic-gate 	key_free(public);
112*0Sstevel@tonic-gate 	xfree(comment);
113*0Sstevel@tonic-gate 
114*0Sstevel@tonic-gate 	return ret;
115*0Sstevel@tonic-gate }
116*0Sstevel@tonic-gate 
117*0Sstevel@tonic-gate /* Send a request to remove all identities. */
118*0Sstevel@tonic-gate static int
119*0Sstevel@tonic-gate delete_all(AuthenticationConnection *ac)
120*0Sstevel@tonic-gate {
121*0Sstevel@tonic-gate 	int ret = -1;
122*0Sstevel@tonic-gate 
123*0Sstevel@tonic-gate 	if (ssh_remove_all_identities(ac, 1))
124*0Sstevel@tonic-gate 		ret = 0;
125*0Sstevel@tonic-gate 	/* ignore error-code for ssh2 */
126*0Sstevel@tonic-gate 	ssh_remove_all_identities(ac, 2);
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate 	if (ret == 0)
129*0Sstevel@tonic-gate 		fprintf(stderr, gettext("All identities removed.\n"));
130*0Sstevel@tonic-gate 	else
131*0Sstevel@tonic-gate 		fprintf(stderr, gettext("Failed to remove all identities.\n"));
132*0Sstevel@tonic-gate 
133*0Sstevel@tonic-gate 	return ret;
134*0Sstevel@tonic-gate }
135*0Sstevel@tonic-gate 
136*0Sstevel@tonic-gate static int
137*0Sstevel@tonic-gate add_file(AuthenticationConnection *ac, const char *filename)
138*0Sstevel@tonic-gate {
139*0Sstevel@tonic-gate 	struct stat st;
140*0Sstevel@tonic-gate 	Key *private;
141*0Sstevel@tonic-gate 	char *comment = NULL;
142*0Sstevel@tonic-gate 	char msg[1024];
143*0Sstevel@tonic-gate 	int ret = -1;
144*0Sstevel@tonic-gate 
145*0Sstevel@tonic-gate 	if (stat(filename, &st) < 0) {
146*0Sstevel@tonic-gate 		perror(filename);
147*0Sstevel@tonic-gate 		return -1;
148*0Sstevel@tonic-gate 	}
149*0Sstevel@tonic-gate 	/* At first, try empty passphrase */
150*0Sstevel@tonic-gate 	private = key_load_private(filename, "", &comment);
151*0Sstevel@tonic-gate 	if (comment == NULL)
152*0Sstevel@tonic-gate 		comment = xstrdup(filename);
153*0Sstevel@tonic-gate 	/* try last */
154*0Sstevel@tonic-gate 	if (private == NULL && pass != NULL)
155*0Sstevel@tonic-gate 		private = key_load_private(filename, pass, NULL);
156*0Sstevel@tonic-gate 	if (private == NULL) {
157*0Sstevel@tonic-gate 		/* clear passphrase since it did not work */
158*0Sstevel@tonic-gate 		clear_pass();
159*0Sstevel@tonic-gate 		snprintf(msg, sizeof msg,
160*0Sstevel@tonic-gate 			 gettext("Enter passphrase for %.200s: "), comment);
161*0Sstevel@tonic-gate 		for (;;) {
162*0Sstevel@tonic-gate 			pass = read_passphrase(msg, RP_ALLOW_STDIN);
163*0Sstevel@tonic-gate 			if (strcmp(pass, "") == 0) {
164*0Sstevel@tonic-gate 				clear_pass();
165*0Sstevel@tonic-gate 				xfree(comment);
166*0Sstevel@tonic-gate 				return -1;
167*0Sstevel@tonic-gate 			}
168*0Sstevel@tonic-gate 			private = key_load_private(filename, pass, &comment);
169*0Sstevel@tonic-gate 			if (private != NULL)
170*0Sstevel@tonic-gate 				break;
171*0Sstevel@tonic-gate 			clear_pass();
172*0Sstevel@tonic-gate 			strlcpy(msg, gettext("Bad passphrase, try again: "),
173*0Sstevel@tonic-gate 				sizeof msg);
174*0Sstevel@tonic-gate 		}
175*0Sstevel@tonic-gate 	}
176*0Sstevel@tonic-gate 
177*0Sstevel@tonic-gate 	if (ssh_add_identity_constrained(ac, private, comment, lifetime)) {
178*0Sstevel@tonic-gate 		fprintf(stderr, gettext("Identity added: %s (%s)\n"),
179*0Sstevel@tonic-gate 			filename, comment);
180*0Sstevel@tonic-gate 		ret = 0;
181*0Sstevel@tonic-gate 		if (lifetime != 0)
182*0Sstevel@tonic-gate                         fprintf(stderr,
183*0Sstevel@tonic-gate 			    gettext("Lifetime set to %d seconds\n"), lifetime);
184*0Sstevel@tonic-gate 	} else if (ssh_add_identity(ac, private, comment)) {
185*0Sstevel@tonic-gate 		fprintf(stderr, gettext("Identity added: %s (%s)\n"),
186*0Sstevel@tonic-gate 			filename, comment);
187*0Sstevel@tonic-gate 		ret = 0;
188*0Sstevel@tonic-gate 	} else {
189*0Sstevel@tonic-gate 		fprintf(stderr, gettext("Could not add identity: %s\n"),
190*0Sstevel@tonic-gate 			filename);
191*0Sstevel@tonic-gate 	}
192*0Sstevel@tonic-gate 
193*0Sstevel@tonic-gate 	xfree(comment);
194*0Sstevel@tonic-gate 	key_free(private);
195*0Sstevel@tonic-gate 
196*0Sstevel@tonic-gate 	return ret;
197*0Sstevel@tonic-gate }
198*0Sstevel@tonic-gate 
199*0Sstevel@tonic-gate #ifdef SMARTCARD
200*0Sstevel@tonic-gate static int
201*0Sstevel@tonic-gate update_card(AuthenticationConnection *ac, int add, const char *id)
202*0Sstevel@tonic-gate {
203*0Sstevel@tonic-gate 	char *pin;
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate 	pin = read_passphrase("Enter passphrase for smartcard: ", RP_ALLOW_STDIN);
206*0Sstevel@tonic-gate 	if (pin == NULL)
207*0Sstevel@tonic-gate 		return -1;
208*0Sstevel@tonic-gate 
209*0Sstevel@tonic-gate 	if (ssh_update_card(ac, add, id, pin)) {
210*0Sstevel@tonic-gate 		fprintf(stderr, "Card %s: %s\n",
211*0Sstevel@tonic-gate 		    add ? "added" : "removed", id);
212*0Sstevel@tonic-gate 		return 0;
213*0Sstevel@tonic-gate 	} else {
214*0Sstevel@tonic-gate 		fprintf(stderr, "Could not %s card: %s\n",
215*0Sstevel@tonic-gate 		    add ? "add" : "remove", id);
216*0Sstevel@tonic-gate 		return -1;
217*0Sstevel@tonic-gate 	}
218*0Sstevel@tonic-gate }
219*0Sstevel@tonic-gate #endif /* SMARTCARD */
220*0Sstevel@tonic-gate 
221*0Sstevel@tonic-gate static int
222*0Sstevel@tonic-gate list_identities(AuthenticationConnection *ac, int do_fp)
223*0Sstevel@tonic-gate {
224*0Sstevel@tonic-gate 	Key *key;
225*0Sstevel@tonic-gate 	char *comment, *fp;
226*0Sstevel@tonic-gate 	int had_identities = 0;
227*0Sstevel@tonic-gate 	int version;
228*0Sstevel@tonic-gate 
229*0Sstevel@tonic-gate 	for (version = 1; version <= 2; version++) {
230*0Sstevel@tonic-gate 		for (key = ssh_get_first_identity(ac, &comment, version);
231*0Sstevel@tonic-gate 		    key != NULL;
232*0Sstevel@tonic-gate 		    key = ssh_get_next_identity(ac, &comment, version)) {
233*0Sstevel@tonic-gate 			had_identities = 1;
234*0Sstevel@tonic-gate 			if (do_fp) {
235*0Sstevel@tonic-gate 				fp = key_fingerprint(key, SSH_FP_MD5,
236*0Sstevel@tonic-gate 				    SSH_FP_HEX);
237*0Sstevel@tonic-gate 				printf("%d %s %s (%s)\n",
238*0Sstevel@tonic-gate 				    key_size(key), fp, comment, key_type(key));
239*0Sstevel@tonic-gate 				xfree(fp);
240*0Sstevel@tonic-gate 			} else {
241*0Sstevel@tonic-gate 				if (!key_write(key, stdout))
242*0Sstevel@tonic-gate 					fprintf(stderr,
243*0Sstevel@tonic-gate 						gettext("key_write failed"));
244*0Sstevel@tonic-gate 				fprintf(stdout, " %s\n", comment);
245*0Sstevel@tonic-gate 			}
246*0Sstevel@tonic-gate 			key_free(key);
247*0Sstevel@tonic-gate 			xfree(comment);
248*0Sstevel@tonic-gate 		}
249*0Sstevel@tonic-gate 	}
250*0Sstevel@tonic-gate 	if (!had_identities) {
251*0Sstevel@tonic-gate 		printf(gettext("The agent has no identities.\n"));
252*0Sstevel@tonic-gate 		return -1;
253*0Sstevel@tonic-gate 	}
254*0Sstevel@tonic-gate 	return 0;
255*0Sstevel@tonic-gate }
256*0Sstevel@tonic-gate 
257*0Sstevel@tonic-gate static int
258*0Sstevel@tonic-gate lock_agent(AuthenticationConnection *ac, int lock)
259*0Sstevel@tonic-gate {
260*0Sstevel@tonic-gate 	char prompt[100], *p1, *p2;
261*0Sstevel@tonic-gate 	int passok = 1, ret = -1;
262*0Sstevel@tonic-gate 
263*0Sstevel@tonic-gate 	strlcpy(prompt, "Enter lock password: ", sizeof(prompt));
264*0Sstevel@tonic-gate 	p1 = read_passphrase(prompt, RP_ALLOW_STDIN);
265*0Sstevel@tonic-gate 	if (lock) {
266*0Sstevel@tonic-gate 		strlcpy(prompt, "Again: ", sizeof prompt);
267*0Sstevel@tonic-gate 		p2 = read_passphrase(prompt, RP_ALLOW_STDIN);
268*0Sstevel@tonic-gate 		if (strcmp(p1, p2) != 0) {
269*0Sstevel@tonic-gate 			fprintf(stderr, gettext("Passwords do not match.\n"));
270*0Sstevel@tonic-gate 			passok = 0;
271*0Sstevel@tonic-gate 		}
272*0Sstevel@tonic-gate 		memset(p2, 0, strlen(p2));
273*0Sstevel@tonic-gate 		xfree(p2);
274*0Sstevel@tonic-gate 	}
275*0Sstevel@tonic-gate 	if (passok && ssh_lock_agent(ac, lock, p1)) {
276*0Sstevel@tonic-gate 		if (lock)
277*0Sstevel@tonic-gate 			fprintf(stderr, gettext("Agent locked.\n"));
278*0Sstevel@tonic-gate 		else
279*0Sstevel@tonic-gate 			fprintf(stderr, gettext("Agent unlocked.\n"));
280*0Sstevel@tonic-gate 		ret = 0;
281*0Sstevel@tonic-gate 	} else {
282*0Sstevel@tonic-gate 		if (lock)
283*0Sstevel@tonic-gate 			fprintf(stderr, gettext("Failed to lock agent.\n"));
284*0Sstevel@tonic-gate 		else
285*0Sstevel@tonic-gate 			fprintf(stderr, gettext("Failed to unlock agent.\n"));
286*0Sstevel@tonic-gate 	}
287*0Sstevel@tonic-gate 	memset(p1, 0, strlen(p1));
288*0Sstevel@tonic-gate 	xfree(p1);
289*0Sstevel@tonic-gate 	return (ret);
290*0Sstevel@tonic-gate }
291*0Sstevel@tonic-gate 
292*0Sstevel@tonic-gate static int
293*0Sstevel@tonic-gate do_file(AuthenticationConnection *ac, int deleting, char *file)
294*0Sstevel@tonic-gate {
295*0Sstevel@tonic-gate 	if (deleting) {
296*0Sstevel@tonic-gate 		if (delete_file(ac, file) == -1)
297*0Sstevel@tonic-gate 			return -1;
298*0Sstevel@tonic-gate 	} else {
299*0Sstevel@tonic-gate 		if (add_file(ac, file) == -1)
300*0Sstevel@tonic-gate 			return -1;
301*0Sstevel@tonic-gate 	}
302*0Sstevel@tonic-gate 	return 0;
303*0Sstevel@tonic-gate }
304*0Sstevel@tonic-gate 
305*0Sstevel@tonic-gate static void
306*0Sstevel@tonic-gate usage(void)
307*0Sstevel@tonic-gate {
308*0Sstevel@tonic-gate 	fprintf(stderr,
309*0Sstevel@tonic-gate 		gettext( "Usage: %s [options]\n"
310*0Sstevel@tonic-gate 		"Options:\n"
311*0Sstevel@tonic-gate 		"  -l          List fingerprints of all identities.\n"
312*0Sstevel@tonic-gate 		"  -L          List public key parameters of all identities.\n"
313*0Sstevel@tonic-gate 		"  -d          Delete identity.\n"
314*0Sstevel@tonic-gate 		"  -D          Delete all identities.\n"
315*0Sstevel@tonic-gate 		"  -x          Lock agent.\n"
316*0Sstevel@tonic-gate 		"  -X          Unlock agent.\n"
317*0Sstevel@tonic-gate 		"  -t life     Set lifetime (seconds) when adding identities.\n"
318*0Sstevel@tonic-gate #ifdef SMARTCARD
319*0Sstevel@tonic-gate 		"  -s reader   Add key in smartcard reader.\n"
320*0Sstevel@tonic-gate 		"  -e reader   Remove key in smartcard reader.\n"
321*0Sstevel@tonic-gate #endif /* SMARTCARD */
322*0Sstevel@tonic-gate 		), __progname);
323*0Sstevel@tonic-gate }
324*0Sstevel@tonic-gate 
325*0Sstevel@tonic-gate int
326*0Sstevel@tonic-gate main(int argc, char **argv)
327*0Sstevel@tonic-gate {
328*0Sstevel@tonic-gate 	extern char *optarg;
329*0Sstevel@tonic-gate 	extern int optind;
330*0Sstevel@tonic-gate 	AuthenticationConnection *ac = NULL;
331*0Sstevel@tonic-gate #ifdef SMARTCARD
332*0Sstevel@tonic-gate 	char *sc_reader_id = NULL;
333*0Sstevel@tonic-gate #endif /* SMARTCARD */
334*0Sstevel@tonic-gate 	int i, ch, deleting = 0, ret = 0;
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate 	__progname = get_progname(argv[0]);
337*0Sstevel@tonic-gate 
338*0Sstevel@tonic-gate 	(void) g11n_setlocale(LC_ALL, "");
339*0Sstevel@tonic-gate 
340*0Sstevel@tonic-gate 	init_rng();
341*0Sstevel@tonic-gate 	seed_rng();
342*0Sstevel@tonic-gate 
343*0Sstevel@tonic-gate 	SSLeay_add_all_algorithms();
344*0Sstevel@tonic-gate 
345*0Sstevel@tonic-gate 	/* At first, get a connection to the authentication agent. */
346*0Sstevel@tonic-gate 	ac = ssh_get_authentication_connection();
347*0Sstevel@tonic-gate 	if (ac == NULL) {
348*0Sstevel@tonic-gate 		fprintf(stderr, gettext("Could not open a connection "
349*0Sstevel@tonic-gate 			    "to your authentication agent.\n"));
350*0Sstevel@tonic-gate 		exit(2);
351*0Sstevel@tonic-gate 	}
352*0Sstevel@tonic-gate 	while ((ch = getopt(argc, argv, "lLdDxXe:s:t:")) != -1) {
353*0Sstevel@tonic-gate 		switch (ch) {
354*0Sstevel@tonic-gate 		case 'l':
355*0Sstevel@tonic-gate 		case 'L':
356*0Sstevel@tonic-gate 			if (list_identities(ac, ch == 'l' ? 1 : 0) == -1)
357*0Sstevel@tonic-gate 				ret = 1;
358*0Sstevel@tonic-gate 			goto done;
359*0Sstevel@tonic-gate 			break;
360*0Sstevel@tonic-gate 		case 'x':
361*0Sstevel@tonic-gate 		case 'X':
362*0Sstevel@tonic-gate 			if (lock_agent(ac, ch == 'x' ? 1 : 0) == -1)
363*0Sstevel@tonic-gate 				ret = 1;
364*0Sstevel@tonic-gate 			goto done;
365*0Sstevel@tonic-gate 			break;
366*0Sstevel@tonic-gate 		case 'd':
367*0Sstevel@tonic-gate 			deleting = 1;
368*0Sstevel@tonic-gate 			break;
369*0Sstevel@tonic-gate 		case 'D':
370*0Sstevel@tonic-gate 			if (delete_all(ac) == -1)
371*0Sstevel@tonic-gate 				ret = 1;
372*0Sstevel@tonic-gate 			goto done;
373*0Sstevel@tonic-gate 			break;
374*0Sstevel@tonic-gate #ifdef SMARTCARD
375*0Sstevel@tonic-gate 		case 's':
376*0Sstevel@tonic-gate 			sc_reader_id = optarg;
377*0Sstevel@tonic-gate 			break;
378*0Sstevel@tonic-gate 		case 'e':
379*0Sstevel@tonic-gate 			deleting = 1;
380*0Sstevel@tonic-gate 			sc_reader_id = optarg;
381*0Sstevel@tonic-gate 			break;
382*0Sstevel@tonic-gate #endif /* SMARTCARD */
383*0Sstevel@tonic-gate 		case 't':
384*0Sstevel@tonic-gate 			if ((lifetime = convtime(optarg)) == -1) {
385*0Sstevel@tonic-gate 				fprintf(stderr, gettext("Invalid lifetime\n"));
386*0Sstevel@tonic-gate 				ret = 1;
387*0Sstevel@tonic-gate 				goto done;
388*0Sstevel@tonic-gate 			}
389*0Sstevel@tonic-gate 			break;
390*0Sstevel@tonic-gate 		default:
391*0Sstevel@tonic-gate 			usage();
392*0Sstevel@tonic-gate 			ret = 1;
393*0Sstevel@tonic-gate 			goto done;
394*0Sstevel@tonic-gate 		}
395*0Sstevel@tonic-gate 	}
396*0Sstevel@tonic-gate 	argc -= optind;
397*0Sstevel@tonic-gate 	argv += optind;
398*0Sstevel@tonic-gate #ifdef SMARTCARD
399*0Sstevel@tonic-gate 	if (sc_reader_id != NULL) {
400*0Sstevel@tonic-gate 		if (update_card(ac, !deleting, sc_reader_id) == -1)
401*0Sstevel@tonic-gate 			ret = 1;
402*0Sstevel@tonic-gate 		goto done;
403*0Sstevel@tonic-gate 	}
404*0Sstevel@tonic-gate #endif /* SMARTCARD */
405*0Sstevel@tonic-gate 	if (argc == 0) {
406*0Sstevel@tonic-gate 		char buf[MAXPATHLEN];
407*0Sstevel@tonic-gate 		struct passwd *pw;
408*0Sstevel@tonic-gate 		struct stat st;
409*0Sstevel@tonic-gate 		int count = 0;
410*0Sstevel@tonic-gate 
411*0Sstevel@tonic-gate 		if ((pw = getpwuid(getuid())) == NULL) {
412*0Sstevel@tonic-gate 			fprintf(stderr, gettext("No user found with uid %u\n"),
413*0Sstevel@tonic-gate 			    (u_int)getuid());
414*0Sstevel@tonic-gate 			ret = 1;
415*0Sstevel@tonic-gate 			goto done;
416*0Sstevel@tonic-gate 		}
417*0Sstevel@tonic-gate 
418*0Sstevel@tonic-gate 		for(i = 0; default_files[i]; i++) {
419*0Sstevel@tonic-gate 			snprintf(buf, sizeof(buf), "%s/%s", pw->pw_dir,
420*0Sstevel@tonic-gate 			    default_files[i]);
421*0Sstevel@tonic-gate 			if (stat(buf, &st) < 0)
422*0Sstevel@tonic-gate 				continue;
423*0Sstevel@tonic-gate 			if (do_file(ac, deleting, buf) == -1)
424*0Sstevel@tonic-gate 				ret = 1;
425*0Sstevel@tonic-gate 			else
426*0Sstevel@tonic-gate 				count++;
427*0Sstevel@tonic-gate 		}
428*0Sstevel@tonic-gate 		if (count == 0)
429*0Sstevel@tonic-gate 			ret = 1;
430*0Sstevel@tonic-gate 	} else {
431*0Sstevel@tonic-gate 		for(i = 0; i < argc; i++) {
432*0Sstevel@tonic-gate 			if (do_file(ac, deleting, argv[i]) == -1)
433*0Sstevel@tonic-gate 				ret = 1;
434*0Sstevel@tonic-gate 		}
435*0Sstevel@tonic-gate 	}
436*0Sstevel@tonic-gate 	clear_pass();
437*0Sstevel@tonic-gate 
438*0Sstevel@tonic-gate done:
439*0Sstevel@tonic-gate 	ssh_close_authentication_connection(ac);
440*0Sstevel@tonic-gate 	return ret;
441*0Sstevel@tonic-gate }
442