]>
Commit | Line | Data |
---|---|---|
8efc0c15 | 1 | /* |
2 | ||
3 | ssh-add.c | |
4 | ||
5 | Author: Tatu Ylonen <ylo@cs.hut.fi> | |
6 | ||
7 | Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland | |
8 | All rights reserved | |
9 | ||
10 | Created: Thu Apr 6 00:52:24 1995 ylo | |
11 | ||
12 | Adds an identity to the authentication server, or removes an identity. | |
13 | ||
14 | */ | |
15 | ||
16 | #include "includes.h" | |
17 | RCSID("$Id$"); | |
18 | ||
19 | #include "rsa.h" | |
20 | #include "ssh.h" | |
21 | #include "xmalloc.h" | |
22 | #include "authfd.h" | |
f095fcc7 | 23 | #include "fingerprint.h" |
8efc0c15 | 24 | |
dad9a31e | 25 | #ifdef USE_EXTERNAL_ASKPASS |
26 | int askpass(const char *filename, RSA *key, const char *saved_comment, char **comment); | |
27 | #endif /* USE_EXTERNAL_ASKPASS */ | |
28 | ||
f601d847 | 29 | #ifdef HAVE___PROGNAME |
30 | extern char *__progname; | |
31 | #else /* HAVE___PROGNAME */ | |
32 | const char *__progname = "ssh-add"; | |
33 | #endif /* HAVE___PROGNAME */ | |
34 | ||
8efc0c15 | 35 | void |
5068f573 | 36 | delete_file(AuthenticationConnection *ac, const char *filename) |
8efc0c15 | 37 | { |
38 | RSA *key; | |
39 | char *comment; | |
8efc0c15 | 40 | |
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 | ||
8efc0c15 | 48 | 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); | |
8efc0c15 | 54 | } |
55 | ||
56 | void | |
5068f573 | 57 | delete_all(AuthenticationConnection *ac) |
8efc0c15 | 58 | { |
8efc0c15 | 59 | /* 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"); | |
8efc0c15 | 64 | } |
65 | ||
66 | void | |
5068f573 | 67 | add_file(AuthenticationConnection *ac, const char *filename) |
8efc0c15 | 68 | { |
69 | RSA *key; | |
70 | RSA *public_key; | |
dad9a31e | 71 | char *saved_comment, *comment; |
72 | int success; | |
73 | ||
8efc0c15 | 74 | 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); | |
8efc0c15 | 82 | |
dad9a31e | 83 | /* 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 */ | |
045672f9 | 102 | xfree(saved_comment); |
103 | return; | |
dad9a31e | 104 | #endif /* USE_EXTERNAL_ASKPASS */ |
8efc0c15 | 105 | } |
8efc0c15 | 106 | |
dad9a31e | 107 | 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; | |
dad9a31e | 119 | printf("Bad passphrase.\n"); |
120 | } | |
121 | } | |
8efc0c15 | 122 | xfree(saved_comment); |
123 | ||
8efc0c15 | 124 | 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); | |
8efc0c15 | 130 | } |
131 | ||
132 | void | |
f095fcc7 | 133 | list_identities(AuthenticationConnection *ac, int fp) |
8efc0c15 | 134 | { |
8efc0c15 | 135 | BIGNUM *e, *n; |
4d195447 | 136 | int status; |
8efc0c15 | 137 | char *comment; |
138 | int had_identities; | |
139 | ||
8efc0c15 | 140 | e = BN_new(); |
141 | n = BN_new(); | |
142 | had_identities = 0; | |
4d195447 | 143 | for (status = ssh_get_first_identity(ac, e, n, &comment); |
8efc0c15 | 144 | status; |
4d195447 | 145 | status = ssh_get_next_identity(ac, e, n, &comment)) |
8efc0c15 | 146 | { |
f095fcc7 | 147 | unsigned int bits = BN_num_bits(n); |
8efc0c15 | 148 | had_identities = 1; |
f095fcc7 | 149 | 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 | } | |
5bae4ab8 | 166 | } |
8efc0c15 | 167 | 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"); | |
8efc0c15 | 173 | } |
174 | ||
175 | int | |
5068f573 | 176 | main(int argc, char **argv) |
8efc0c15 | 177 | { |
5068f573 | 178 | AuthenticationConnection *ac = NULL; |
8efc0c15 | 179 | 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) { | |
8efc0c15 | 187 | fprintf(stderr, |
188 | "%s: no RSA support in libssl and libcrypto. See ssl(8).\n", | |
189 | __progname); | |
190 | exit(1); | |
191 | } | |
192 | ||
5068f573 | 193 | /* At first, get a connection to the authentication agent. */ |
194 | ac = ssh_get_authentication_connection(); | |
195 | if (ac == NULL) { | |
196 | fprintf(stderr, "Could not open a connection to your authentication agent.\n"); | |
197 | exit(1); | |
198 | } | |
199 | ||
200 | for (i = 1; i < argc; i++) | |
8efc0c15 | 201 | { |
f095fcc7 | 202 | if ((strcmp(argv[i], "-l") == 0) || |
203 | (strcmp(argv[i], "-L") == 0)) | |
8efc0c15 | 204 | { |
f095fcc7 | 205 | list_identities(ac, argv[i][1] == 'l' ? 1 : 0); |
8efc0c15 | 206 | no_files = 0; /* Don't default-add/delete if -l. */ |
207 | continue; | |
208 | } | |
5068f573 | 209 | if (strcmp(argv[i], "-d") == 0) |
8efc0c15 | 210 | { |
211 | deleting = 1; | |
212 | continue; | |
213 | } | |
5068f573 | 214 | if (strcmp(argv[i], "-D") == 0) |
8efc0c15 | 215 | { |
5068f573 | 216 | delete_all(ac); |
8efc0c15 | 217 | no_files = 0; |
218 | continue; | |
219 | } | |
220 | no_files = 0; | |
221 | if (deleting) | |
5068f573 | 222 | delete_file(ac, argv[i]); |
8efc0c15 | 223 | else |
5068f573 | 224 | add_file(ac, argv[i]); |
8efc0c15 | 225 | } |
226 | if (no_files) | |
227 | { | |
228 | pw = getpwuid(getuid()); | |
229 | if (!pw) | |
230 | { | |
231 | fprintf(stderr, "No user found with uid %d\n", (int)getuid()); | |
5068f573 | 232 | ssh_close_authentication_connection(ac); |
8efc0c15 | 233 | exit(1); |
234 | } | |
235 | snprintf(buf, sizeof buf, "%s/%s", pw->pw_dir, SSH_CLIENT_IDENTITY); | |
236 | if (deleting) | |
5068f573 | 237 | delete_file(ac, buf); |
8efc0c15 | 238 | else |
5068f573 | 239 | add_file(ac, buf); |
8efc0c15 | 240 | } |
5068f573 | 241 | ssh_close_authentication_connection(ac); |
8efc0c15 | 242 | exit(0); |
243 | } | |
dad9a31e | 244 | |
245 | #ifdef USE_EXTERNAL_ASKPASS | |
246 | int askpass(const char *filename, RSA *key, const char *saved_comment, char **comment) | |
247 | { | |
248 | int pipes[2]; | |
249 | char buf[1024]; | |
250 | int tmp; | |
251 | pid_t child; | |
252 | FILE *pipef; | |
253 | ||
254 | /* Check that we are X11-capable */ | |
255 | if (getenv("DISPLAY") == NULL) | |
256 | exit(1); | |
257 | ||
258 | if (pipe(pipes) == -1) { | |
259 | fprintf(stderr, "Creating pipes failed: %s\n", strerror(errno)); | |
260 | exit(1); | |
261 | } | |
262 | ||
263 | if (fflush(NULL) == EOF) { | |
264 | fprintf(stderr, "Cannot flush buffers: %s\n", strerror(errno)); | |
265 | exit(1); | |
266 | } | |
267 | ||
268 | child = fork(); | |
269 | if (child == -1) { | |
270 | fprintf(stderr, "Cannot fork: %s\n", strerror(errno)); | |
271 | exit(1); | |
272 | } | |
273 | ||
274 | if (child == 0) { | |
275 | /* In child */ | |
276 | ||
277 | close(pipes[0]); | |
278 | if (dup2(pipes[1], 1) ==-1) { | |
279 | fprintf(stderr, "dup2 failed: %s\n", strerror(errno)); | |
280 | exit(1); | |
281 | } | |
282 | ||
d84a9a44 | 283 | tmp = snprintf(buf, sizeof(buf), "Need passphrase for %s", saved_comment); |
dad9a31e | 284 | /* skip the prompt if it won't fit */ |
285 | if ((tmp < 0) || (tmp >= sizeof(buf))) | |
286 | tmp = execlp(ASKPASS_PROGRAM, "ssh-askpass", 0); | |
287 | else | |
288 | tmp = execlp(ASKPASS_PROGRAM, "ssh-askpass", buf, 0); | |
289 | ||
290 | /* Shouldn't get this far */ | |
291 | fprintf(stderr, "Executing ssh-askpass failed: %s\n", strerror(errno)); | |
292 | exit(1); | |
293 | } | |
294 | ||
295 | /* In parent */ | |
296 | close(pipes[1]); | |
297 | ||
298 | if ((pipef = fdopen(pipes[0], "r")) == NULL) { | |
299 | fprintf(stderr, "fdopen failed: %s\n", strerror(errno)); | |
300 | exit(1); | |
301 | } | |
302 | ||
303 | /* Read passphrase back from child, abort if none presented */ | |
304 | if(fgets(buf, sizeof(buf), pipef) == NULL) | |
305 | exit(1); | |
306 | ||
307 | fclose(pipef); | |
308 | ||
309 | if (strchr(buf, '\n')) | |
310 | *strchr(buf, '\n') = 0; | |
311 | ||
312 | if (waitpid(child, NULL, 0) == -1) { | |
313 | fprintf(stderr, "Waiting for child failed: %s\n", | |
314 | strerror(errno)); | |
315 | exit(1); | |
316 | } | |
317 | ||
318 | /* Try password as it was presented */ | |
319 | tmp = load_private_key(filename, buf, key, comment); | |
320 | ||
321 | memset(buf, 0, sizeof(buf)); | |
322 | ||
323 | return(tmp); | |
324 | } | |
325 | #endif /* USE_EXTERNAL_ASKPASS */ |