blob: 56618aded25c1bc616f564c01db7cdf491a86d11 [file] [log] [blame]
Damien Millerd4a8b7e1999-10-27 13:42:43 +10001/*
2
3ssh-agent.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: Wed Mar 29 03:46:59 1995 ylo
11
12The authentication agent program.
13
14*/
15
Damien Miller7f6ea021999-10-28 13:25:17 +100016#include "config.h"
Damien Millerd4a8b7e1999-10-27 13:42:43 +100017#include "includes.h"
Damien Miller01ab4a21999-10-28 15:23:30 +100018RCSID("$Id: ssh-agent.c,v 1.3 1999/10/28 05:23:30 damien Exp $");
Damien Millerd4a8b7e1999-10-27 13:42:43 +100019
20#include "ssh.h"
21#include "rsa.h"
22#include "authfd.h"
23#include "buffer.h"
24#include "bufaux.h"
25#include "xmalloc.h"
26#include "packet.h"
27#include "getput.h"
28#include "mpaux.h"
29
Damien Miller7f6ea021999-10-28 13:25:17 +100030#ifdef HAVE_OPENSSL
Damien Millerd4a8b7e1999-10-27 13:42:43 +100031#include <openssl/md5.h>
Damien Miller7f6ea021999-10-28 13:25:17 +100032#endif
33#ifdef HAVE_SSL
34#include <ssl/md5.h>
35#endif
Damien Millerd4a8b7e1999-10-27 13:42:43 +100036
37typedef struct
38{
39 int fd;
40 enum { AUTH_UNUSED, AUTH_SOCKET, AUTH_CONNECTION } type;
41 Buffer input;
42 Buffer output;
43} SocketEntry;
44
45unsigned int sockets_alloc = 0;
46SocketEntry *sockets = NULL;
47
48typedef struct
49{
50 RSA *key;
51 char *comment;
52} Identity;
53
54unsigned int num_identities = 0;
55Identity *identities = NULL;
56
57int max_fd = 0;
58
59/* pid of shell == parent of agent */
60int parent_pid = -1;
61
62/* pathname and directory for AUTH_SOCKET */
63char socket_name[1024];
64char socket_dir[1024];
65
66void
67process_request_identity(SocketEntry *e)
68{
69 Buffer msg;
70 int i;
71
72 buffer_init(&msg);
73 buffer_put_char(&msg, SSH_AGENT_RSA_IDENTITIES_ANSWER);
74 buffer_put_int(&msg, num_identities);
75 for (i = 0; i < num_identities; i++)
76 {
77 buffer_put_int(&msg, BN_num_bits(identities[i].key->n));
78 buffer_put_bignum(&msg, identities[i].key->e);
79 buffer_put_bignum(&msg, identities[i].key->n);
80 buffer_put_string(&msg, identities[i].comment,
81 strlen(identities[i].comment));
82 }
83 buffer_put_int(&e->output, buffer_len(&msg));
84 buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
85 buffer_free(&msg);
86}
87
88void
89process_authentication_challenge(SocketEntry *e)
90{
91 int i, pub_bits, len;
92 BIGNUM *pub_e, *pub_n, *challenge;
93 Buffer msg;
94 MD5_CTX md;
95 unsigned char buf[32], mdbuf[16], session_id[16];
96 unsigned int response_type;
97
98 buffer_init(&msg);
99 pub_e = BN_new();
100 pub_n = BN_new();
101 challenge = BN_new();
102 pub_bits = buffer_get_int(&e->input);
103 buffer_get_bignum(&e->input, pub_e);
104 buffer_get_bignum(&e->input, pub_n);
105 buffer_get_bignum(&e->input, challenge);
106 if (buffer_len(&e->input) == 0)
107 {
108 /* Compatibility code for old servers. */
109 memset(session_id, 0, 16);
110 response_type = 0;
111 }
112 else
113 {
114 /* New code. */
115 buffer_get(&e->input, (char *)session_id, 16);
116 response_type = buffer_get_int(&e->input);
117 }
118 for (i = 0; i < num_identities; i++)
119 if (pub_bits == BN_num_bits(identities[i].key->n) &&
120 BN_cmp(pub_e, identities[i].key->e) == 0 &&
121 BN_cmp(pub_n, identities[i].key->n) == 0)
122 {
123 /* Decrypt the challenge using the private key. */
124 rsa_private_decrypt(challenge, challenge, identities[i].key);
125
126 /* Compute the desired response. */
127 switch (response_type)
128 {
129 case 0: /* As of protocol 1.0 */
130 /* This response type is no longer supported. */
131 log("Compatibility with ssh protocol 1.0 no longer supported.");
132 buffer_put_char(&msg, SSH_AGENT_FAILURE);
133 goto send;
134
135 case 1: /* As of protocol 1.1 */
136 /* The response is MD5 of decrypted challenge plus session id. */
137 len = BN_num_bytes(challenge);
138 assert(len <= 32 && len);
139 memset(buf, 0, 32);
140 BN_bn2bin(challenge, buf + 32 - len);
141 MD5_Init(&md);
142 MD5_Update(&md, buf, 32);
143 MD5_Update(&md, session_id, 16);
144 MD5_Final(mdbuf, &md);
145 break;
146
147 default:
148 fatal("process_authentication_challenge: bad response_type %d",
149 response_type);
150 break;
151 }
152
153 /* Send the response. */
154 buffer_put_char(&msg, SSH_AGENT_RSA_RESPONSE);
155 for (i = 0; i < 16; i++)
156 buffer_put_char(&msg, mdbuf[i]);
157
158 goto send;
159 }
160 /* Unknown identity. Send failure. */
161 buffer_put_char(&msg, SSH_AGENT_FAILURE);
162 send:
163 buffer_put_int(&e->output, buffer_len(&msg));
164 buffer_append(&e->output, buffer_ptr(&msg),
165 buffer_len(&msg));
166 buffer_free(&msg);
167 BN_clear_free(pub_e);
168 BN_clear_free(pub_n);
169 BN_clear_free(challenge);
170}
171
172void
173process_remove_identity(SocketEntry *e)
174{
175 unsigned int bits;
176 unsigned int i;
177 BIGNUM *dummy, *n;
178
179 dummy = BN_new();
180 n = BN_new();
181
182 /* Get the key from the packet. */
183 bits = buffer_get_int(&e->input);
184 buffer_get_bignum(&e->input, dummy);
185 buffer_get_bignum(&e->input, n);
186
187 /* Check if we have the key. */
188 for (i = 0; i < num_identities; i++)
189 if (BN_cmp(identities[i].key->n, n) == 0)
190 {
191 /* We have this key. Free the old key. Since we don\'t want to leave
192 empty slots in the middle of the array, we actually free the
193 key there and copy data from the last entry. */
194 RSA_free(identities[i].key);
195 xfree(identities[i].comment);
196 if (i < num_identities - 1)
197 identities[i] = identities[num_identities - 1];
198 num_identities--;
199 BN_clear_free(dummy);
200 BN_clear_free(n);
201
202 /* Send success. */
203 buffer_put_int(&e->output, 1);
204 buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
205 return;
206 }
207 /* We did not have the key. */
208 BN_clear(dummy);
209 BN_clear(n);
210
211 /* Send failure. */
212 buffer_put_int(&e->output, 1);
213 buffer_put_char(&e->output, SSH_AGENT_FAILURE);
214}
215
216/* Removes all identities from the agent. */
217
218void
219process_remove_all_identities(SocketEntry *e)
220{
221 unsigned int i;
222
223 /* Loop over all identities and clear the keys. */
224 for (i = 0; i < num_identities; i++)
225 {
226 RSA_free(identities[i].key);
227 xfree(identities[i].comment);
228 }
229
230 /* Mark that there are no identities. */
231 num_identities = 0;
232
233 /* Send success. */
234 buffer_put_int(&e->output, 1);
235 buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
236 return;
237}
238
239/* Adds an identity to the agent. */
240
241void
242process_add_identity(SocketEntry *e)
243{
244 RSA *k;
245 int i;
246 BIGNUM *aux;
247 BN_CTX *ctx;
248
249 if (num_identities == 0)
250 identities = xmalloc(sizeof(Identity));
251 else
252 identities = xrealloc(identities, (num_identities + 1) * sizeof(Identity));
253
254 identities[num_identities].key = RSA_new();
255 k = identities[num_identities].key;
256 buffer_get_int(&e->input); /* bits */
257 k->n = BN_new();
258 buffer_get_bignum(&e->input, k->n);
259 k->e = BN_new();
260 buffer_get_bignum(&e->input, k->e);
261 k->d = BN_new();
262 buffer_get_bignum(&e->input, k->d);
263 k->iqmp = BN_new();
264 buffer_get_bignum(&e->input, k->iqmp);
265 /* SSH and SSL have p and q swapped */
266 k->q = BN_new();
267 buffer_get_bignum(&e->input, k->q); /* p */
268 k->p = BN_new();
269 buffer_get_bignum(&e->input, k->p); /* q */
270
271 /* Generate additional parameters */
272 aux = BN_new();
273 ctx = BN_CTX_new();
274
275 BN_sub(aux, k->q, BN_value_one());
276 k->dmq1 = BN_new();
277 BN_mod(k->dmq1, k->d, aux, ctx);
278
279 BN_sub(aux, k->p, BN_value_one());
280 k->dmp1 = BN_new();
281 BN_mod(k->dmp1, k->d, aux, ctx);
282
283 BN_clear_free(aux);
284 BN_CTX_free(ctx);
285
286 identities[num_identities].comment = buffer_get_string(&e->input, NULL);
287
288 /* Check if we already have the key. */
289 for (i = 0; i < num_identities; i++)
290 if (BN_cmp(identities[i].key->n, k->n) == 0)
291 {
292 /* We already have this key. Clear and free the new data and
293 return success. */
294 RSA_free(k);
295 xfree(identities[num_identities].comment);
296
297 /* Send success. */
298 buffer_put_int(&e->output, 1);
299 buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
300 return;
301 }
302
303 /* Increment the number of identities. */
304 num_identities++;
305
306 /* Send a success message. */
307 buffer_put_int(&e->output, 1);
308 buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
309}
310
311void
312process_message(SocketEntry *e)
313{
314 unsigned int msg_len;
315 unsigned int type;
316 unsigned char *cp;
317 if (buffer_len(&e->input) < 5)
318 return; /* Incomplete message. */
319 cp = (unsigned char *)buffer_ptr(&e->input);
320 msg_len = GET_32BIT(cp);
321 if (msg_len > 256 * 1024)
322 {
323 shutdown(e->fd, SHUT_RDWR);
324 close(e->fd);
325 e->type = AUTH_UNUSED;
326 return;
327 }
328 if (buffer_len(&e->input) < msg_len + 4)
329 return;
330 buffer_consume(&e->input, 4);
331 type = buffer_get_char(&e->input);
332
333 switch (type)
334 {
335 case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
336 process_request_identity(e);
337 break;
338 case SSH_AGENTC_RSA_CHALLENGE:
339 process_authentication_challenge(e);
340 break;
341 case SSH_AGENTC_ADD_RSA_IDENTITY:
342 process_add_identity(e);
343 break;
344 case SSH_AGENTC_REMOVE_RSA_IDENTITY:
345 process_remove_identity(e);
346 break;
347 case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
348 process_remove_all_identities(e);
349 break;
350 default:
351 /* Unknown message. Respond with failure. */
352 error("Unknown message %d", type);
353 buffer_clear(&e->input);
354 buffer_put_int(&e->output, 1);
355 buffer_put_char(&e->output, SSH_AGENT_FAILURE);
356 break;
357 }
358}
359
360void
361new_socket(int type, int fd)
362{
363 unsigned int i, old_alloc;
364 if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
365 error("fcntl O_NONBLOCK: %s", strerror(errno));
366
367 if (fd > max_fd)
368 max_fd = fd;
369
370 for (i = 0; i < sockets_alloc; i++)
371 if (sockets[i].type == AUTH_UNUSED)
372 {
373 sockets[i].fd = fd;
374 sockets[i].type = type;
375 buffer_init(&sockets[i].input);
376 buffer_init(&sockets[i].output);
377 return;
378 }
379 old_alloc = sockets_alloc;
380 sockets_alloc += 10;
381 if (sockets)
382 sockets = xrealloc(sockets, sockets_alloc * sizeof(sockets[0]));
383 else
384 sockets = xmalloc(sockets_alloc * sizeof(sockets[0]));
385 for (i = old_alloc; i < sockets_alloc; i++)
386 sockets[i].type = AUTH_UNUSED;
387 sockets[old_alloc].type = type;
388 sockets[old_alloc].fd = fd;
389 buffer_init(&sockets[old_alloc].input);
390 buffer_init(&sockets[old_alloc].output);
391}
392
393void
394prepare_select(fd_set *readset, fd_set *writeset)
395{
396 unsigned int i;
397 for (i = 0; i < sockets_alloc; i++)
398 switch (sockets[i].type)
399 {
400 case AUTH_SOCKET:
401 case AUTH_CONNECTION:
402 FD_SET(sockets[i].fd, readset);
403 if (buffer_len(&sockets[i].output) > 0)
404 FD_SET(sockets[i].fd, writeset);
405 break;
406 case AUTH_UNUSED:
407 break;
408 default:
409 fatal("Unknown socket type %d", sockets[i].type);
410 break;
411 }
412}
413
414void after_select(fd_set *readset, fd_set *writeset)
415{
416 unsigned int i;
417 int len, sock;
418 char buf[1024];
419 struct sockaddr_un sunaddr;
420
421 for (i = 0; i < sockets_alloc; i++)
422 switch (sockets[i].type)
423 {
424 case AUTH_UNUSED:
425 break;
426 case AUTH_SOCKET:
427 if (FD_ISSET(sockets[i].fd, readset))
428 {
429 len = sizeof(sunaddr);
430 sock = accept(sockets[i].fd, (struct sockaddr *)&sunaddr, &len);
431 if (sock < 0)
432 {
433 perror("accept from AUTH_SOCKET");
434 break;
435 }
436 new_socket(AUTH_CONNECTION, sock);
437 }
438 break;
439 case AUTH_CONNECTION:
440 if (buffer_len(&sockets[i].output) > 0 &&
441 FD_ISSET(sockets[i].fd, writeset))
442 {
443 len = write(sockets[i].fd, buffer_ptr(&sockets[i].output),
444 buffer_len(&sockets[i].output));
445 if (len <= 0)
446 {
447 shutdown(sockets[i].fd, SHUT_RDWR);
448 close(sockets[i].fd);
449 sockets[i].type = AUTH_UNUSED;
450 break;
451 }
452 buffer_consume(&sockets[i].output, len);
453 }
454 if (FD_ISSET(sockets[i].fd, readset))
455 {
456 len = read(sockets[i].fd, buf, sizeof(buf));
457 if (len <= 0)
458 {
459 shutdown(sockets[i].fd, SHUT_RDWR);
460 close(sockets[i].fd);
461 sockets[i].type = AUTH_UNUSED;
462 break;
463 }
464 buffer_append(&sockets[i].input, buf, len);
465 process_message(&sockets[i]);
466 }
467 break;
468 default:
469 fatal("Unknown type %d", sockets[i].type);
470 }
471}
472
473void
474check_parent_exists(int sig)
475{
476 if (kill(parent_pid, 0) < 0)
477 {
478 /* printf("Parent has died - Authentication agent exiting.\n"); */
479 exit(1);
480 }
481 signal(SIGALRM, check_parent_exists);
482 alarm(10);
483}
484
485void cleanup_socket(void) {
486 remove(socket_name);
487 rmdir(socket_dir);
488}
489
490int
491main(int ac, char **av)
492{
493 fd_set readset, writeset;
494 int sock;
495 struct sockaddr_un sunaddr;
496
497 /* check if RSA support exists */
498 if (rsa_alive() == 0) {
499 extern char *__progname;
500 fprintf(stderr,
501 "%s: no RSA support in libssl and libcrypto. See ssl(8).\n",
502 __progname);
503 exit(1);
504 }
505
506 if (ac < 2)
507 {
508 fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION);
509 fprintf(stderr, "Usage: %s command\n", av[0]);
510 exit(1);
511 }
512
513 parent_pid = getpid();
514
515 /* Create private directory for agent socket */
516 strlcpy(socket_dir, "/tmp/ssh-XXXXXXXX", sizeof socket_dir);
517 if (mkdtemp(socket_dir) == NULL) {
518 perror("mkdtemp: private socket dir");
519 exit(1);
520 }
521 snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir, parent_pid);
522
523 /* Fork, and have the parent execute the command. The child continues as
524 the authentication agent. */
525 if (fork() != 0)
526 { /* Parent - execute the given command. */
527 setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1);
528 execvp(av[1], av + 1);
529 perror(av[1]);
530 exit(1);
531 }
532
533 if (atexit(cleanup_socket) < 0) {
534 perror("atexit");
535 cleanup_socket();
536 exit(1);
537 }
538
Damien Miller01ab4a21999-10-28 15:23:30 +1000539 /* Create a new session and process group */
540 if (setsid() < 0) {
541 perror("setsid failed");
542 exit(1);
543 }
544
545 /* Ignore if a client dies while we are sending a reply */
546 signal(SIGPIPE, SIG_IGN);
547
Damien Millerd4a8b7e1999-10-27 13:42:43 +1000548 sock = socket(AF_UNIX, SOCK_STREAM, 0);
549 if (sock < 0)
550 {
551 perror("socket");
552 exit(1);
553 }
554 memset(&sunaddr, 0, sizeof(sunaddr));
555 sunaddr.sun_family = AF_UNIX;
556 strlcpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path));
557 if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0)
558 {
559 perror("bind");
560 exit(1);
561 }
562 if (listen(sock, 5) < 0)
563 {
564 perror("listen");
565 exit(1);
566 }
567 new_socket(AUTH_SOCKET, sock);
568 signal(SIGALRM, check_parent_exists);
569 alarm(10);
570
571 signal(SIGINT, SIG_IGN);
572 while (1)
573 {
574 FD_ZERO(&readset);
575 FD_ZERO(&writeset);
576 prepare_select(&readset, &writeset);
577 if (select(max_fd + 1, &readset, &writeset, NULL, NULL) < 0)
578 {
579 if (errno == EINTR)
580 continue;
581 perror("select");
582 exit(1);
583 }
584 after_select(&readset, &writeset);
585 }
586 /*NOTREACHED*/
587}