blob: 0f01d5dfd3c33d6566a14cf21fb90e0b8c1d652a [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 Miller3f905871999-11-15 17:10:57 +110017RCSID("$Id: ssh-add.c,v 1.8 1999/11/15 06:10:57 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"
23
Damien Millerd05a2471999-11-15 14:25:30 +110024#ifdef USE_EXTERNAL_ASKPASS
25int askpass(const char *filename, RSA *key, const char *saved_comment, char **comment);
26#endif /* USE_EXTERNAL_ASKPASS */
27
Damien Miller3f905871999-11-15 17:10:57 +110028#ifdef HAVE___PROGNAME
29extern char *__progname;
30#else /* HAVE___PROGNAME */
31const char *__progname = "ssh-add";
32#endif /* HAVE___PROGNAME */
33
Damien Millerd4a8b7e1999-10-27 13:42:43 +100034void
Damien Miller01ab4a21999-10-28 15:23:30 +100035delete_file(AuthenticationConnection *ac, const char *filename)
Damien Millerd4a8b7e1999-10-27 13:42:43 +100036{
37 RSA *key;
38 char *comment;
Damien Millerd4a8b7e1999-10-27 13:42:43 +100039
40 key = RSA_new();
41 if (!load_public_key(filename, key, &comment))
42 {
43 printf("Bad key file %s: %s\n", filename, strerror(errno));
44 return;
45 }
46
Damien Millerd4a8b7e1999-10-27 13:42:43 +100047 if (ssh_remove_identity(ac, key))
48 fprintf(stderr, "Identity removed: %s (%s)\n", filename, comment);
49 else
50 fprintf(stderr, "Could not remove identity: %s\n", filename);
51 RSA_free(key);
52 xfree(comment);
Damien Millerd4a8b7e1999-10-27 13:42:43 +100053}
54
55void
Damien Miller01ab4a21999-10-28 15:23:30 +100056delete_all(AuthenticationConnection *ac)
Damien Millerd4a8b7e1999-10-27 13:42:43 +100057{
Damien Millerd4a8b7e1999-10-27 13:42:43 +100058 /* Send a request to remove all identities. */
59 if (ssh_remove_all_identities(ac))
60 fprintf(stderr, "All identities removed.\n");
61 else
62 fprintf(stderr, "Failed to remove all identitities.\n");
Damien Millerd4a8b7e1999-10-27 13:42:43 +100063}
64
65void
Damien Miller01ab4a21999-10-28 15:23:30 +100066add_file(AuthenticationConnection *ac, const char *filename)
Damien Millerd4a8b7e1999-10-27 13:42:43 +100067{
68 RSA *key;
69 RSA *public_key;
Damien Millerd05a2471999-11-15 14:25:30 +110070 char *saved_comment, *comment;
71 int success;
72
Damien Millerd4a8b7e1999-10-27 13:42:43 +100073 key = RSA_new();
74 public_key = RSA_new();
75 if (!load_public_key(filename, public_key, &saved_comment))
76 {
77 printf("Bad key file %s: %s\n", filename, strerror(errno));
78 return;
79 }
80 RSA_free(public_key);
Damien Millerd4a8b7e1999-10-27 13:42:43 +100081
Damien Millerd05a2471999-11-15 14:25:30 +110082 /* At first, try empty passphrase */
83 success = load_private_key(filename, "", key, &comment);
84 if (!success) {
85 printf("Need passphrase for %s (%s).\n", filename, saved_comment);
86 if (!isatty(STDIN_FILENO)) {
87#ifdef USE_EXTERNAL_ASKPASS
88 int prompts = 3;
89
90 while (prompts && !success)
91 {
92 success = askpass(filename, key, saved_comment, &comment);
93 prompts--;
94 }
95 if (!success)
96 {
97 xfree(saved_comment);
98 return;
99 }
100#else /* !USE_EXTERNAL_ASKPASS */
Damien Miller3d1b22c1999-11-12 15:46:08 +1100101 xfree(saved_comment);
102 return;
Damien Millerd05a2471999-11-15 14:25:30 +1100103#endif /* USE_EXTERNAL_ASKPASS */
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000104 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000105
Damien Millerd05a2471999-11-15 14:25:30 +1100106 while (!success) {
107 char *pass = read_passphrase("Enter passphrase: ", 1);
108 if (strcmp(pass, "") == 0){
109 xfree(pass);
110 xfree(saved_comment);
111 return;
112 }
113 success = load_private_key(filename, pass, key, &comment);
114 memset(pass, 0, strlen(pass));
115 xfree(pass);
116 if (success)
117 break;
118
119 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 Miller01ab4a21999-10-28 15:23:30 +1000133list_identities(AuthenticationConnection *ac)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000134{
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000135 BIGNUM *e, *n;
136 int bits, status;
137 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;
143 for (status = ssh_get_first_identity(ac, &bits, e, n, &comment);
144 status;
145 status = ssh_get_next_identity(ac, &bits, e, n, &comment))
146 {
147 char *buf;
148 had_identities = 1;
149 printf("%d ", bits);
150 buf = BN_bn2dec(e);
Damien Millerfd7c9111999-11-08 16:15:55 +1100151 if (buf != NULL) {
152 printf("%s ", buf);
153 free (buf);
154 } else {
155 error("list_identities: BN_bn2dec #1 failed.");
156 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000157 buf = BN_bn2dec(n);
Damien Millerfd7c9111999-11-08 16:15:55 +1100158 if (buf != NULL) {
159 printf("%s %s\n", buf, comment);
160 free (buf);
161 } else {
162 error("list_identities: BN_bn2dec #2 failed.");
163 }
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000164 xfree(comment);
165 }
166 BN_clear_free(e);
167 BN_clear_free(n);
168 if (!had_identities)
169 printf("The agent has no identities.\n");
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000170}
171
172int
Damien Miller01ab4a21999-10-28 15:23:30 +1000173main(int argc, char **argv)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000174{
Damien Miller01ab4a21999-10-28 15:23:30 +1000175 AuthenticationConnection *ac = NULL;
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000176 struct passwd *pw;
177 char buf[1024];
178 int no_files = 1;
179 int i;
180 int deleting = 0;
181
182 /* check if RSA support exists */
183 if (rsa_alive() == 0) {
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000184
185 fprintf(stderr,
186 "%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
187 __progname);
188 exit(1);
189 }
190
Damien Miller01ab4a21999-10-28 15:23:30 +1000191 /* At first, get a connection to the authentication agent. */
192 ac = ssh_get_authentication_connection();
193 if (ac == NULL) {
194 fprintf(stderr, "Could not open a connection to your authentication agent.\n");
195 exit(1);
196 }
197
198 for (i = 1; i < argc; i++)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000199 {
Damien Miller01ab4a21999-10-28 15:23:30 +1000200 if (strcmp(argv[i], "-l") == 0)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000201 {
Damien Miller01ab4a21999-10-28 15:23:30 +1000202 list_identities(ac);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000203 no_files = 0; /* Don't default-add/delete if -l. */
204 continue;
205 }
Damien Miller01ab4a21999-10-28 15:23:30 +1000206 if (strcmp(argv[i], "-d") == 0)
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000207 {
208 deleting = 1;
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 {
Damien Miller01ab4a21999-10-28 15:23:30 +1000213 delete_all(ac);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000214 no_files = 0;
215 continue;
216 }
217 no_files = 0;
218 if (deleting)
Damien Miller01ab4a21999-10-28 15:23:30 +1000219 delete_file(ac, argv[i]);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000220 else
Damien Miller01ab4a21999-10-28 15:23:30 +1000221 add_file(ac, argv[i]);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000222 }
223 if (no_files)
224 {
225 pw = getpwuid(getuid());
226 if (!pw)
227 {
228 fprintf(stderr, "No user found with uid %d\n", (int)getuid());
Damien Miller01ab4a21999-10-28 15:23:30 +1000229 ssh_close_authentication_connection(ac);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000230 exit(1);
231 }
232 snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, SSH_CLIENT_IDENTITY);
233 if (deleting)
Damien Miller01ab4a21999-10-28 15:23:30 +1000234 delete_file(ac, buf);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000235 else
Damien Miller01ab4a21999-10-28 15:23:30 +1000236 add_file(ac, buf);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000237 }
Damien Miller01ab4a21999-10-28 15:23:30 +1000238 ssh_close_authentication_connection(ac);
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000239 exit(0);
240}
Damien Millerd05a2471999-11-15 14:25:30 +1100241
242#ifdef USE_EXTERNAL_ASKPASS
243int askpass(const char *filename, RSA *key, const char *saved_comment, char **comment)
244{
245 int pipes[2];
246 char buf[1024];
247 int tmp;
248 pid_t child;
249 FILE *pipef;
250
251 /* Check that we are X11-capable */
252 if (getenv("DISPLAY") == NULL)
253 exit(1);
254
255 if (pipe(pipes) == -1) {
256 fprintf(stderr, "Creating pipes failed: %s\n", strerror(errno));
257 exit(1);
258 }
259
260 if (fflush(NULL) == EOF) {
261 fprintf(stderr, "Cannot flush buffers: %s\n", strerror(errno));
262 exit(1);
263 }
264
265 child = fork();
266 if (child == -1) {
267 fprintf(stderr, "Cannot fork: %s\n", strerror(errno));
268 exit(1);
269 }
270
271 if (child == 0) {
272 /* In child */
273
274 close(pipes[0]);
275 if (dup2(pipes[1], 1) ==-1) {
276 fprintf(stderr, "dup2 failed: %s\n", strerror(errno));
277 exit(1);
278 }
279
280 tmp = snprintf(buf, sizeof(buf), "Need passphrase for %s (%s)", filename, saved_comment);
281 /* skip the prompt if it won't fit */
282 if ((tmp < 0) || (tmp >= sizeof(buf)))
283 tmp = execlp(ASKPASS_PROGRAM, "ssh-askpass", 0);
284 else
285 tmp = execlp(ASKPASS_PROGRAM, "ssh-askpass", buf, 0);
286
287 /* Shouldn't get this far */
288 fprintf(stderr, "Executing ssh-askpass failed: %s\n", strerror(errno));
289 exit(1);
290 }
291
292 /* In parent */
293 close(pipes[1]);
294
295 if ((pipef = fdopen(pipes[0], "r")) == NULL) {
296 fprintf(stderr, "fdopen failed: %s\n", strerror(errno));
297 exit(1);
298 }
299
300 /* Read passphrase back from child, abort if none presented */
301 if(fgets(buf, sizeof(buf), pipef) == NULL)
302 exit(1);
303
304 fclose(pipef);
305
306 if (strchr(buf, '\n'))
307 *strchr(buf, '\n') = 0;
308
309 if (waitpid(child, NULL, 0) == -1) {
310 fprintf(stderr, "Waiting for child failed: %s\n",
311 strerror(errno));
312 exit(1);
313 }
314
315 /* Try password as it was presented */
316 tmp = load_private_key(filename, buf, key, comment);
317
318 memset(buf, 0, sizeof(buf));
319
320 return(tmp);
321}
322#endif /* USE_EXTERNAL_ASKPASS */