xref: /freebsd/crypto/openssh/ssh-add.c (revision daf1cffce2e07931f27c6c6998652e90df6ba87e)
1 /*
2  * Author: Tatu Ylonen <ylo@cs.hut.fi>
3  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4  *                    All rights reserved
5  * Created: Thu Apr  6 00:52:24 1995 ylo
6  * Adds an identity to the authentication server, or removes an identity.
7  */
8 
9 #include "includes.h"
10 RCSID("$Id: ssh-add.c,v 1.15 1999/12/02 20:05:40 markus Exp $");
11 
12 #include "rsa.h"
13 #include "ssh.h"
14 #include "xmalloc.h"
15 #include "authfd.h"
16 #include "fingerprint.h"
17 
18 void
19 delete_file(AuthenticationConnection *ac, const char *filename)
20 {
21 	RSA *key;
22 	char *comment;
23 
24 	key = RSA_new();
25 	if (!load_public_key(filename, key, &comment)) {
26 		printf("Bad key file %s: %s\n", filename, strerror(errno));
27 		return;
28 	}
29 	if (ssh_remove_identity(ac, key))
30 		fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment);
31 	else
32 		fprintf(stderr, "Could not remove identity: %s\n", filename);
33 	RSA_free(key);
34 	xfree(comment);
35 }
36 
37 void
38 delete_all(AuthenticationConnection *ac)
39 {
40 	/* Send a request to remove all identities. */
41 	if (ssh_remove_all_identities(ac))
42 		fprintf(stderr, "All identities removed.\n");
43 	else
44 		fprintf(stderr, "Failed to remove all identitities.\n");
45 }
46 
47 char *
48 ssh_askpass(char *askpass, char *msg)
49 {
50 	pid_t pid;
51 	size_t len;
52 	char *nl, *pass;
53 	int p[2], status;
54 	char buf[1024];
55 
56 	if (askpass == NULL)
57 		fatal("internal error: askpass undefined");
58 	if (pipe(p) < 0)
59 		fatal("ssh_askpass: pipe: %s", strerror(errno));
60 	if ((pid = fork()) < 0)
61 		fatal("ssh_askpass: fork: %s", strerror(errno));
62 	if (pid == 0) {
63 		close(p[0]);
64 		if (dup2(p[1], STDOUT_FILENO) < 0)
65 			fatal("ssh_askpass: dup2: %s", strerror(errno));
66 		execlp(askpass, askpass, msg, (char *) 0);
67 		fatal("ssh_askpass: exec(%s): %s", askpass, strerror(errno));
68 	}
69 	close(p[1]);
70 	len = read(p[0], buf, sizeof buf);
71 	close(p[0]);
72 	while (waitpid(pid, &status, 0) < 0)
73 		if (errno != EINTR)
74 			break;
75 	if (len <= 1)
76 		return xstrdup("");
77 	nl = strchr(buf, '\n');
78 	if (nl)
79 		*nl = '\0';
80 	pass = xstrdup(buf);
81 	memset(buf, 0, sizeof(buf));
82 	return pass;
83 }
84 
85 void
86 add_file(AuthenticationConnection *ac, const char *filename)
87 {
88 	RSA *key;
89 	RSA *public_key;
90 	char *saved_comment, *comment, *askpass = NULL;
91 	char buf[1024], msg[1024];
92 	int success;
93 	int interactive = isatty(STDIN_FILENO);
94 
95 	key = RSA_new();
96 	public_key = RSA_new();
97 	if (!load_public_key(filename, public_key, &saved_comment)) {
98 		printf("Bad key file %s: %s\n", filename, strerror(errno));
99 		return;
100 	}
101 	RSA_free(public_key);
102 
103 	if (!interactive && getenv("DISPLAY")) {
104 		if (getenv(SSH_ASKPASS_ENV))
105 			askpass = getenv(SSH_ASKPASS_ENV);
106 		else
107 			askpass = SSH_ASKPASS_DEFAULT;
108 	}
109 
110 	/* At first, try empty passphrase */
111 	success = load_private_key(filename, "", key, &comment);
112 	if (!success) {
113 		printf("Need passphrase for %.200s\n", filename);
114 		if (!interactive && askpass == NULL) {
115 			xfree(saved_comment);
116 			return;
117 		}
118 		snprintf(msg, sizeof msg, "Enter passphrase for %.200s", saved_comment);
119 		for (;;) {
120 			char *pass;
121 			if (interactive) {
122 				snprintf(buf, sizeof buf, "%s: ", msg);
123 				pass = read_passphrase(buf, 1);
124 			} else {
125 				pass = ssh_askpass(askpass, msg);
126 			}
127 			if (strcmp(pass, "") == 0) {
128 				xfree(pass);
129 				xfree(saved_comment);
130 				return;
131 			}
132 			success = load_private_key(filename, pass, key, &comment);
133 			memset(pass, 0, strlen(pass));
134 			xfree(pass);
135 			if (success)
136 				break;
137 			strlcpy(msg, "Bad passphrase, try again", sizeof msg);
138 		}
139 	}
140 	xfree(saved_comment);
141 
142 	if (ssh_add_identity(ac, key, comment))
143 		fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
144 	else
145 		fprintf(stderr, "Could not add identity: %s\n", filename);
146 	RSA_free(key);
147 	xfree(comment);
148 }
149 
150 void
151 list_identities(AuthenticationConnection *ac, int fp)
152 {
153 	BIGNUM *e, *n;
154 	int status;
155 	char *comment;
156 	int had_identities;
157 
158 	e = BN_new();
159 	n = BN_new();
160 	had_identities = 0;
161 	for (status = ssh_get_first_identity(ac, e, n, &comment);
162 	     status;
163 	     status = ssh_get_next_identity(ac, e, n, &comment)) {
164 		unsigned int bits = BN_num_bits(n);
165 		had_identities = 1;
166 		if (fp) {
167 			printf("%d %s %s\n", bits, fingerprint(e, n), comment);
168 		} else {
169 			char *ebuf, *nbuf;
170 			ebuf = BN_bn2dec(e);
171 			if (ebuf == NULL) {
172 				error("list_identities: BN_bn2dec(e) failed.");
173 			} else {
174 				nbuf = BN_bn2dec(n);
175 				if (nbuf == NULL) {
176 					error("list_identities: BN_bn2dec(n) failed.");
177 				} else {
178 					printf("%d %s %s %s\n", bits, ebuf, nbuf, comment);
179 					free(nbuf);
180 				}
181 				free(ebuf);
182 			}
183 		}
184 		xfree(comment);
185 	}
186 	BN_clear_free(e);
187 	BN_clear_free(n);
188 	if (!had_identities)
189 		printf("The agent has no identities.\n");
190 }
191 
192 int
193 main(int argc, char **argv)
194 {
195 	AuthenticationConnection *ac = NULL;
196 	struct passwd *pw;
197 	char buf[1024];
198 	int no_files = 1;
199 	int i;
200 	int deleting = 0;
201 
202 	/* check if RSA support exists */
203 	if (rsa_alive() == 0) {
204 		extern char *__progname;
205 
206 		fprintf(stderr,
207 			"%s: no RSA support in libssl and libcrypto.  See ssl(8).\n",
208 			__progname);
209 		exit(1);
210 	}
211 	/* At first, get a connection to the authentication agent. */
212 	ac = ssh_get_authentication_connection();
213 	if (ac == NULL) {
214 		fprintf(stderr, "Could not open a connection to your authentication agent.\n");
215 		exit(1);
216 	}
217 	for (i = 1; i < argc; i++) {
218 		if ((strcmp(argv[i], "-l") == 0) ||
219 		    (strcmp(argv[i], "-L") == 0)) {
220 			list_identities(ac, argv[i][1] == 'l' ? 1 : 0);
221 			/* Don't default-add/delete if -l. */
222 			no_files = 0;
223 			continue;
224 		}
225 		if (strcmp(argv[i], "-d") == 0) {
226 			deleting = 1;
227 			continue;
228 		}
229 		if (strcmp(argv[i], "-D") == 0) {
230 			delete_all(ac);
231 			no_files = 0;
232 			continue;
233 		}
234 		no_files = 0;
235 		if (deleting)
236 			delete_file(ac, argv[i]);
237 		else
238 			add_file(ac, argv[i]);
239 	}
240 	if (no_files) {
241 		pw = getpwuid(getuid());
242 		if (!pw) {
243 			fprintf(stderr, "No user found with uid %d\n", (int) getuid());
244 			ssh_close_authentication_connection(ac);
245 			exit(1);
246 		}
247 		snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, SSH_CLIENT_IDENTITY);
248 		if (deleting)
249 			delete_file(ac, buf);
250 		else
251 			add_file(ac, buf);
252 	}
253 	ssh_close_authentication_connection(ac);
254 	exit(0);
255 }
256