]> andersk Git - openssh.git/blob - ssh-agent.c
Renamed open* -> * at request of Theo de Raadt <deraadt@cvs.openbsd.org>
[openssh.git] / ssh-agent.c
1 /*
2
3 ssh-agent.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: Wed Mar 29 03:46:59 1995 ylo
11
12 The authentication agent program.
13
14 */
15
16 #include "config.h"
17 #include "includes.h"
18 RCSID("$Id$");
19
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
30 #ifdef HAVE_OPENSSL
31 #include <openssl/md5.h>
32 #endif
33 #ifdef HAVE_SSL
34 #include <ssl/md5.h>
35 #endif
36
37 typedef struct
38 {
39   int fd;
40   enum { AUTH_UNUSED, AUTH_SOCKET, AUTH_CONNECTION } type;
41   Buffer input;
42   Buffer output;
43 } SocketEntry;
44
45 unsigned int sockets_alloc = 0;
46 SocketEntry *sockets = NULL;
47
48 typedef struct
49 {
50   RSA *key;
51   char *comment;
52 } Identity;
53
54 unsigned int num_identities = 0;
55 Identity *identities = NULL;
56
57 int max_fd = 0;
58
59 /* pid of shell == parent of agent */
60 int parent_pid = -1;
61
62 /* pathname and directory for AUTH_SOCKET */
63 char socket_name[1024];
64 char socket_dir[1024];
65
66 void
67 process_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
88 void
89 process_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
172 void
173 process_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
218 void
219 process_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
241 void
242 process_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
311 void
312 process_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
360 void
361 new_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
393 void
394 prepare_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
414 void 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
473 void
474 check_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
485 void cleanup_socket(void) {
486   remove(socket_name);
487   rmdir(socket_dir);
488 }
489
490 int
491 main(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
539   /* 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
548   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 }
This page took 0.109256 seconds and 5 git commands to generate.