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