blob: cdd5ca1d029c634b071460c16404c507c84e4ef5 [file] [log] [blame]
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001/*
2
3ssh-add.c
4
5Author: Tatu Ylonen <ylo@cs.hut.fi>
6
7Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
8 All rights reserved
9
10Created: Thu Apr 6 00:52:24 1995 ylo
11
12Adds an identity to the authentication server, or removes an identity.
13
14*/
15
16#include "includes.h"
Damien Miller10f6f6b1999-11-17 17:29:08 +110017RCSID("$Id: ssh-add.c,v 1.10 1999/11/17 06:29:08 damien Exp $");
Damien Millerd4a8b7e1999-10-27 13:42:43 +100018
19#include "rsa.h"
20#include "ssh.h"
21#include "xmalloc.h"
22#include "authfd.h"
Damien Miller10f6f6b1999-11-17 17:29:08 +110023#include "fingerprint.h"
Damien Millerd4a8b7e1999-10-27 13:42:43 +100024
Damien Millerd05a2471999-11-15 14:25:30 +110025#ifdef USE_EXTERNAL_ASKPASS
26int askpass(const char *filename, RSA *key, const char *saved_comment, char **comment);
27#endif /* USE_EXTERNAL_ASKPASS */
28
Damien Miller3f905871999-11-15 17:10:57 +110029#ifdef HAVE___PROGNAME
30extern char *__progname;
31#else /* HAVE___PROGNAME */
32const char *__progname = "ssh-add";
33#endif /* HAVE___PROGNAME */
34
Damien Millerd4a8b7e1999-10-27 13:42:43 +100035void
Damien Miller01ab4a21999-10-28 15:23:30 +100036delete_file(AuthenticationConnection *ac, const char *filename)
Damien Millerd4a8b7e1999-10-27 13:42:43 +100037{
38 RSA *key;
39 char *comment;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100040
41 key = RSA_new();
42 if (!load_public_key(filename, key, &comment))
43 {
44 printf("Bad key file %s: %s\n", filename, strerror(errno));
45 return;
46 }
47
Damien Millerd4a8b7e1999-10-27 13:42:43 +100048 if (ssh_remove_identity(ac, key))
49 fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment);
50 else
51 fprintf(stderr, "Could not remove identity: %s\n", filename);
52 RSA_free(key);
53 xfree(comment);
Damien Millerd4a8b7e1999-10-27 13:42:43 +100054}
55
56void
Damien Miller01ab4a21999-10-28 15:23:30 +100057delete_all(AuthenticationConnection *ac)
Damien Millerd4a8b7e1999-10-27 13:42:43 +100058{
Damien Millerd4a8b7e1999-10-27 13:42:43 +100059 /* Send a request to remove all identities. */
60 if (ssh_remove_all_identities(ac))
61 fprintf(stderr, "All identities removed.\n");
62 else
63 fprintf(stderr, "Failed to remove all identitities.\n");
Damien Millerd4a8b7e1999-10-27 13:42:43 +100064}
65
66void
Damien Miller01ab4a21999-10-28 15:23:30 +100067add_file(AuthenticationConnection *ac, const char *filename)
Damien Millerd4a8b7e1999-10-27 13:42:43 +100068{
69 RSA *key;
70 RSA *public_key;
Damien Millerd05a2471999-11-15 14:25:30 +110071 char *saved_comment, *comment;
72 int success;
73
Damien Millerd4a8b7e1999-10-27 13:42:43 +100074 key = RSA_new();
75 public_key = RSA_new();
76 if (!load_public_key(filename, public_key, &saved_comment))
77 {
78 printf("Bad key file %s: %s\n", filename, strerror(errno));
79 return;
80 }
81 RSA_free(public_key);
Damien Millerd4a8b7e1999-10-27 13:42:43 +100082
Damien Millerd05a2471999-11-15 14:25:30 +110083 /* At first, try empty passphrase */
84 success = load_private_key(filename, "", key, &comment);
85 if (!success) {
86 printf("Need passphrase for %s (%s).\n", filename, saved_comment);
87 if (!isatty(STDIN_FILENO)) {
88#ifdef USE_EXTERNAL_ASKPASS
89 int prompts = 3;
90
91 while (prompts && !success)
92 {
93 success = askpass(filename, key, saved_comment, &comment);
94 prompts--;
95 }
96 if (!success)
97 {
98 xfree(saved_comment);
99 return;
100 }
101#else /* !USE_EXTERNAL_ASKPASS */
Damien Miller3d1b22c1999-11-12 15:46:08 +1100102 xfree(saved_comment);
103 return;
Damien Millerd05a2471999-11-15 14:25:30 +1100104#endif /* USE_EXTERNAL_ASKPASS */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000105 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000106
Damien Millerd05a2471999-11-15 14:25:30 +1100107 while (!success) {
108 char *pass = read_passphrase("Enter passphrase: ", 1);
109 if (strcmp(pass, "") == 0){
110 xfree(pass);
111 xfree(saved_comment);
112 return;
113 }
114 success = load_private_key(filename, pass, key, &comment);
115 memset(pass, 0, strlen(pass));
116 xfree(pass);
117 if (success)
118 break;
Damien Millerd05a2471999-11-15 14:25:30 +1100119 printf("Bad passphrase.\n");
120 }
121 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000122 xfree(saved_comment);
123
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000124 if (ssh_add_identity(ac, key, comment))
125 fprintf(stderr, "Identity added: %s (%s)\n", filename, comment);
126 else
127 fprintf(stderr, "Could not add identity: %s\n", filename);
128 RSA_free(key);
129 xfree(comment);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000130}
131
132void
Damien Miller10f6f6b1999-11-17 17:29:08 +1100133list_identities(AuthenticationConnection *ac, int fp)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000134{
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000135 BIGNUM *e, *n;
Damien Miller7e8e8201999-11-16 13:37:16 +1100136 int status;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000137 char *comment;
138 int had_identities;
139
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000140 e = BN_new();
141 n = BN_new();
142 had_identities = 0;
Damien Miller7e8e8201999-11-16 13:37:16 +1100143 for (status = ssh_get_first_identity(ac, e, n, &comment);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000144 status;
Damien Miller7e8e8201999-11-16 13:37:16 +1100145 status = ssh_get_next_identity(ac, e, n, &comment))
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000146 {
Damien Miller10f6f6b1999-11-17 17:29:08 +1100147 unsigned int bits = BN_num_bits(n);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000148 had_identities = 1;
Damien Miller10f6f6b1999-11-17 17:29:08 +1100149 if (fp) {
150 printf("%d %s %s\n", bits, fingerprint(e, n), comment);
151 } else {
152 char *ebuf, *nbuf;
153 ebuf = BN_bn2dec(e);
154 if (ebuf == NULL) {
155 error("list_identities: BN_bn2dec(e) failed.");
156 }else{
157 nbuf = BN_bn2dec(n);
158 if (nbuf == NULL) {
159 error("list_identities: BN_bn2dec(n) failed.");
160 }else{
161 printf("%d %s %s %s\n", bits, ebuf, nbuf, comment);
162 free(nbuf);
163 }
164 free(ebuf);
165 }
Damien Millerfd7c9111999-11-08 16:15:55 +1100166 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000167 xfree(comment);
168 }
169 BN_clear_free(e);
170 BN_clear_free(n);
171 if (!had_identities)
172 printf("The agent has no identities.\n");
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000173}
174
175int
Damien Miller01ab4a21999-10-28 15:23:30 +1000176main(int argc, char **argv)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000177{
Damien Miller01ab4a21999-10-28 15:23:30 +1000178 AuthenticationConnection *ac = NULL;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000179 struct passwd *pw;
180 char buf[1024];
181 int no_files = 1;
182 int i;
183 int deleting = 0;
184
185 /* check if RSA support exists */
186 if (rsa_alive() == 0) {
Damien Miller10f6f6b1999-11-17 17:29:08 +1100187 extern char *__progname;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000188
189 fprintf(stderr,
190 "%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
191 __progname);
192 exit(1);
193 }
194
Damien Miller01ab4a21999-10-28 15:23:30 +1000195 /* At first, get a connection to the authentication agent. */
196 ac = ssh_get_authentication_connection();
197 if (ac == NULL) {
198 fprintf(stderr, "Could not open a connection to your authentication agent.\n");
199 exit(1);
200 }
201
202 for (i = 1; i < argc; i++)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000203 {
Damien Miller10f6f6b1999-11-17 17:29:08 +1100204 if ((strcmp(argv[i], "-l") == 0) ||
205 (strcmp(argv[i], "-L") == 0))
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000206 {
Damien Miller10f6f6b1999-11-17 17:29:08 +1100207 list_identities(ac, argv[i][1] == 'l' ? 1 : 0);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000208 no_files = 0; /* Don't default-add/delete if -l. */
209 continue;
210 }
Damien Miller01ab4a21999-10-28 15:23:30 +1000211 if (strcmp(argv[i], "-d") == 0)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000212 {
213 deleting = 1;
214 continue;
215 }
Damien Miller01ab4a21999-10-28 15:23:30 +1000216 if (strcmp(argv[i], "-D") == 0)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000217 {
Damien Miller01ab4a21999-10-28 15:23:30 +1000218 delete_all(ac);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000219 no_files = 0;
220 continue;
221 }
222 no_files = 0;
223 if (deleting)
Damien Miller01ab4a21999-10-28 15:23:30 +1000224 delete_file(ac, argv[i]);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000225 else
Damien Miller01ab4a21999-10-28 15:23:30 +1000226 add_file(ac, argv[i]);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000227 }
228 if (no_files)
229 {
230 pw = getpwuid(getuid());
231 if (!pw)
232 {
233 fprintf(stderr, "No user found with uid %d\n", (int)getuid());
Damien Miller01ab4a21999-10-28 15:23:30 +1000234 ssh_close_authentication_connection(ac);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000235 exit(1);
236 }
237 snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, SSH_CLIENT_IDENTITY);
238 if (deleting)
Damien Miller01ab4a21999-10-28 15:23:30 +1000239 delete_file(ac, buf);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000240 else
Damien Miller01ab4a21999-10-28 15:23:30 +1000241 add_file(ac, buf);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000242 }
Damien Miller01ab4a21999-10-28 15:23:30 +1000243 ssh_close_authentication_connection(ac);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000244 exit(0);
245}
Damien Millerd05a2471999-11-15 14:25:30 +1100246
247#ifdef USE_EXTERNAL_ASKPASS
248int askpass(const char *filename, RSA *key, const char *saved_comment, char **comment)
249{
250 int pipes[2];
251 char buf[1024];
252 int tmp;
253 pid_t child;
254 FILE *pipef;
255
256 /* Check that we are X11-capable */
257 if (getenv("DISPLAY") == NULL)
258 exit(1);
259
260 if (pipe(pipes) == -1) {
261 fprintf(stderr, "Creating pipes failed: %s\n", strerror(errno));
262 exit(1);
263 }
264
265 if (fflush(NULL) == EOF) {
266 fprintf(stderr, "Cannot flush buffers: %s\n", strerror(errno));
267 exit(1);
268 }
269
270 child = fork();
271 if (child == -1) {
272 fprintf(stderr, "Cannot fork: %s\n", strerror(errno));
273 exit(1);
274 }
275
276 if (child == 0) {
277 /* In child */
278
279 close(pipes[0]);
280 if (dup2(pipes[1], 1) ==-1) {
281 fprintf(stderr, "dup2 failed: %s\n", strerror(errno));
282 exit(1);
283 }
284
285 tmp = snprintf(buf, sizeof(buf), "Need passphrase for %s (%s)", filename, saved_comment);
286 /* skip the prompt if it won't fit */
287 if ((tmp < 0) || (tmp >= sizeof(buf)))
288 tmp = execlp(ASKPASS_PROGRAM, "ssh-askpass", 0);
289 else
290 tmp = execlp(ASKPASS_PROGRAM, "ssh-askpass", buf, 0);
291
292 /* Shouldn't get this far */
293 fprintf(stderr, "Executing ssh-askpass failed: %s\n", strerror(errno));
294 exit(1);
295 }
296
297 /* In parent */
298 close(pipes[1]);
299
300 if ((pipef = fdopen(pipes[0], "r")) == NULL) {
301 fprintf(stderr, "fdopen failed: %s\n", strerror(errno));
302 exit(1);
303 }
304
305 /* Read passphrase back from child, abort if none presented */
306 if(fgets(buf, sizeof(buf), pipef) == NULL)
307 exit(1);
308
309 fclose(pipef);
310
311 if (strchr(buf, '\n'))
312 *strchr(buf, '\n') = 0;
313
314 if (waitpid(child, NULL, 0) == -1) {
315 fprintf(stderr, "Waiting for child failed: %s\n",
316 strerror(errno));
317 exit(1);
318 }
319
320 /* Try password as it was presented */
321 tmp = load_private_key(filename, buf, key, comment);
322
323 memset(buf, 0, sizeof(buf));
324
325 return(tmp);
326}
327#endif /* USE_EXTERNAL_ASKPASS */