]> andersk Git - openssh.git/blob - ssh-agent.c
- markus@cvs.openbsd.org 2002/06/05 16:08:07
[openssh.git] / ssh-agent.c
1 /*
2  * Author: Tatu Ylonen <ylo@cs.hut.fi>
3  * Copyright (c) 1995 Tatu Ylonen <ylo@cs.hut.fi>, Espoo, Finland
4  *                    All rights reserved
5  * The authentication agent program.
6  *
7  * As far as I am concerned, the code I have written for this software
8  * can be used freely for any purpose.  Any derived versions of this
9  * software must be clearly marked as such, and if the derived work is
10  * incompatible with the protocol description in the RFC file, it must be
11  * called by a name other than "ssh" or "Secure Shell".
12  *
13  * Copyright (c) 2000, 2001 Markus Friedl.  All rights reserved.
14  *
15  * Redistribution and use in source and binary forms, with or without
16  * modification, are permitted provided that the following conditions
17  * are met:
18  * 1. Redistributions of source code must retain the above copyright
19  *    notice, this list of conditions and the following disclaimer.
20  * 2. Redistributions in binary form must reproduce the above copyright
21  *    notice, this list of conditions and the following disclaimer in the
22  *    documentation and/or other materials provided with the distribution.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
26  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
27  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
29  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
30  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
31  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
32  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
33  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
34  */
35
36 #include "includes.h"
37 #include "openbsd-compat/fake-queue.h"
38 RCSID("$OpenBSD: ssh-agent.c,v 1.86 2002/06/05 16:08:07 markus Exp $");
39
40 #include <openssl/evp.h>
41 #include <openssl/md5.h>
42
43 #include "ssh.h"
44 #include "rsa.h"
45 #include "buffer.h"
46 #include "bufaux.h"
47 #include "xmalloc.h"
48 #include "getput.h"
49 #include "key.h"
50 #include "authfd.h"
51 #include "compat.h"
52 #include "log.h"
53
54 #ifdef SMARTCARD
55 #include "scard.h"
56 #endif
57
58 typedef enum {
59         AUTH_UNUSED,
60         AUTH_SOCKET,
61         AUTH_CONNECTION
62 } sock_type;
63
64 typedef struct {
65         int fd;
66         sock_type type;
67         Buffer input;
68         Buffer output;
69 } SocketEntry;
70
71 u_int sockets_alloc = 0;
72 SocketEntry *sockets = NULL;
73
74 typedef struct identity {
75         TAILQ_ENTRY(identity) next;
76         Key *key;
77         char *comment;
78 } Identity;
79
80 typedef struct {
81         int nentries;
82         TAILQ_HEAD(idqueue, identity) idlist;
83 } Idtab;
84
85 /* private key table, one per protocol version */
86 Idtab idtable[3];
87
88 int max_fd = 0;
89
90 /* pid of shell == parent of agent */
91 pid_t parent_pid = -1;
92
93 /* pathname and directory for AUTH_SOCKET */
94 char socket_name[1024];
95 char socket_dir[1024];
96
97 #ifdef HAVE___PROGNAME
98 extern char *__progname;
99 #else
100 char *__progname;
101 #endif
102
103 static void
104 idtab_init(void)
105 {
106         int i;
107         for (i = 0; i <=2; i++) {
108                 TAILQ_INIT(&idtable[i].idlist);
109                 idtable[i].nentries = 0;
110         }
111 }
112
113 /* return private key table for requested protocol version */
114 static Idtab *
115 idtab_lookup(int version)
116 {
117         if (version < 1 || version > 2)
118                 fatal("internal error, bad protocol version %d", version);
119         return &idtable[version];
120 }
121
122 /* return matching private key for given public key */
123 static Identity *
124 lookup_identity(Key *key, int version)
125 {
126         Identity *id;
127
128         Idtab *tab = idtab_lookup(version);
129         TAILQ_FOREACH(id, &tab->idlist, next) {
130                 if (key_equal(key, id->key))
131                         return (id);
132         }
133         return (NULL);
134 }
135
136 static void
137 free_identity(Identity *id)
138 {
139         key_free(id->key);
140         xfree(id->comment);
141         xfree(id);
142 }
143
144 /* send list of supported public keys to 'client' */
145 static void
146 process_request_identities(SocketEntry *e, int version)
147 {
148         Idtab *tab = idtab_lookup(version);
149         Buffer msg;
150         Identity *id;
151
152         buffer_init(&msg);
153         buffer_put_char(&msg, (version == 1) ?
154             SSH_AGENT_RSA_IDENTITIES_ANSWER : SSH2_AGENT_IDENTITIES_ANSWER);
155         buffer_put_int(&msg, tab->nentries);
156         TAILQ_FOREACH(id, &tab->idlist, next) {
157                 if (id->key->type == KEY_RSA1) {
158                         buffer_put_int(&msg, BN_num_bits(id->key->rsa->n));
159                         buffer_put_bignum(&msg, id->key->rsa->e);
160                         buffer_put_bignum(&msg, id->key->rsa->n);
161                 } else {
162                         u_char *blob;
163                         u_int blen;
164                         key_to_blob(id->key, &blob, &blen);
165                         buffer_put_string(&msg, blob, blen);
166                         xfree(blob);
167                 }
168                 buffer_put_cstring(&msg, id->comment);
169         }
170         buffer_put_int(&e->output, buffer_len(&msg));
171         buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
172         buffer_free(&msg);
173 }
174
175 /* ssh1 only */
176 static void
177 process_authentication_challenge1(SocketEntry *e)
178 {
179         Identity *id;
180         Key *key;
181         BIGNUM *challenge;
182         int i, len;
183         Buffer msg;
184         MD5_CTX md;
185         u_char buf[32], mdbuf[16], session_id[16];
186         u_int response_type;
187
188         buffer_init(&msg);
189         key = key_new(KEY_RSA1);
190         if ((challenge = BN_new()) == NULL)
191                 fatal("process_authentication_challenge1: BN_new failed");
192
193         buffer_get_int(&e->input);                              /* ignored */
194         buffer_get_bignum(&e->input, key->rsa->e);
195         buffer_get_bignum(&e->input, key->rsa->n);
196         buffer_get_bignum(&e->input, challenge);
197
198         /* Only protocol 1.1 is supported */
199         if (buffer_len(&e->input) == 0)
200                 goto failure;
201         buffer_get(&e->input, session_id, 16);
202         response_type = buffer_get_int(&e->input);
203         if (response_type != 1)
204                 goto failure;
205
206         id = lookup_identity(key, 1);
207         if (id != NULL) {
208                 Key *private = id->key;
209                 /* Decrypt the challenge using the private key. */
210                 if (rsa_private_decrypt(challenge, challenge, private->rsa) <= 0)
211                         goto failure;
212
213                 /* The response is MD5 of decrypted challenge plus session id. */
214                 len = BN_num_bytes(challenge);
215                 if (len <= 0 || len > 32) {
216                         log("process_authentication_challenge: bad challenge length %d", len);
217                         goto failure;
218                 }
219                 memset(buf, 0, 32);
220                 BN_bn2bin(challenge, buf + 32 - len);
221                 MD5_Init(&md);
222                 MD5_Update(&md, buf, 32);
223                 MD5_Update(&md, session_id, 16);
224                 MD5_Final(mdbuf, &md);
225
226                 /* Send the response. */
227                 buffer_put_char(&msg, SSH_AGENT_RSA_RESPONSE);
228                 for (i = 0; i < 16; i++)
229                         buffer_put_char(&msg, mdbuf[i]);
230                 goto send;
231         }
232
233 failure:
234         /* Unknown identity or protocol error.  Send failure. */
235         buffer_put_char(&msg, SSH_AGENT_FAILURE);
236 send:
237         buffer_put_int(&e->output, buffer_len(&msg));
238         buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
239         key_free(key);
240         BN_clear_free(challenge);
241         buffer_free(&msg);
242 }
243
244 /* ssh2 only */
245 static void
246 process_sign_request2(SocketEntry *e)
247 {
248         extern int datafellows;
249         Key *key;
250         u_char *blob, *data, *signature = NULL;
251         u_int blen, dlen, slen = 0;
252         int flags;
253         Buffer msg;
254         int ok = -1;
255
256         datafellows = 0;
257
258         blob = buffer_get_string(&e->input, &blen);
259         data = buffer_get_string(&e->input, &dlen);
260
261         flags = buffer_get_int(&e->input);
262         if (flags & SSH_AGENT_OLD_SIGNATURE)
263                 datafellows = SSH_BUG_SIGBLOB;
264
265         key = key_from_blob(blob, blen);
266         if (key != NULL) {
267                 Identity *id = lookup_identity(key, 2);
268                 if (id != NULL)
269                         ok = key_sign(id->key, &signature, &slen, data, dlen);
270         }
271         key_free(key);
272         buffer_init(&msg);
273         if (ok == 0) {
274                 buffer_put_char(&msg, SSH2_AGENT_SIGN_RESPONSE);
275                 buffer_put_string(&msg, signature, slen);
276         } else {
277                 buffer_put_char(&msg, SSH_AGENT_FAILURE);
278         }
279         buffer_put_int(&e->output, buffer_len(&msg));
280         buffer_append(&e->output, buffer_ptr(&msg),
281             buffer_len(&msg));
282         buffer_free(&msg);
283         xfree(data);
284         xfree(blob);
285         if (signature != NULL)
286                 xfree(signature);
287 }
288
289 /* shared */
290 static void
291 process_remove_identity(SocketEntry *e, int version)
292 {
293         Key *key = NULL;
294         u_char *blob;
295         u_int blen;
296         u_int bits;
297         int success = 0;
298
299         switch (version) {
300         case 1:
301                 key = key_new(KEY_RSA1);
302                 bits = buffer_get_int(&e->input);
303                 buffer_get_bignum(&e->input, key->rsa->e);
304                 buffer_get_bignum(&e->input, key->rsa->n);
305
306                 if (bits != key_size(key))
307                         log("Warning: identity keysize mismatch: actual %d, announced %d",
308                             key_size(key), bits);
309                 break;
310         case 2:
311                 blob = buffer_get_string(&e->input, &blen);
312                 key = key_from_blob(blob, blen);
313                 xfree(blob);
314                 break;
315         }
316         if (key != NULL) {
317                 Identity *id = lookup_identity(key, version);
318                 if (id != NULL) {
319                         /*
320                          * We have this key.  Free the old key.  Since we
321                          * don\'t want to leave empty slots in the middle of
322                          * the array, we actually free the key there and move
323                          * all the entries between the empty slot and the end
324                          * of the array.
325                          */
326                         Idtab *tab = idtab_lookup(version);
327                         if (tab->nentries < 1)
328                                 fatal("process_remove_identity: "
329                                     "internal error: tab->nentries %d",
330                                     tab->nentries);
331                         TAILQ_REMOVE(&tab->idlist, id, next);
332                         free_identity(id);
333                         tab->nentries--;
334                         success = 1;
335                 }
336                 key_free(key);
337         }
338         buffer_put_int(&e->output, 1);
339         buffer_put_char(&e->output,
340             success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
341 }
342
343 static void
344 process_remove_all_identities(SocketEntry *e, int version)
345 {
346         Idtab *tab = idtab_lookup(version);
347         Identity *id;
348
349         /* Loop over all identities and clear the keys. */
350         for (id = TAILQ_FIRST(&tab->idlist); id;
351             id = TAILQ_FIRST(&tab->idlist)) {
352                 TAILQ_REMOVE(&tab->idlist, id, next);
353                 free_identity(id);
354         }
355
356         /* Mark that there are no identities. */
357         tab->nentries = 0;
358
359         /* Send success. */
360         buffer_put_int(&e->output, 1);
361         buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
362         return;
363 }
364
365 static void
366 process_add_identity(SocketEntry *e, int version)
367 {
368         Key *k = NULL;
369         char *type_name;
370         char *comment;
371         int type, success = 0;
372         Idtab *tab = idtab_lookup(version);
373
374         switch (version) {
375         case 1:
376                 k = key_new_private(KEY_RSA1);
377                 buffer_get_int(&e->input);                      /* ignored */
378                 buffer_get_bignum(&e->input, k->rsa->n);
379                 buffer_get_bignum(&e->input, k->rsa->e);
380                 buffer_get_bignum(&e->input, k->rsa->d);
381                 buffer_get_bignum(&e->input, k->rsa->iqmp);
382
383                 /* SSH and SSL have p and q swapped */
384                 buffer_get_bignum(&e->input, k->rsa->q);        /* p */
385                 buffer_get_bignum(&e->input, k->rsa->p);        /* q */
386
387                 /* Generate additional parameters */
388                 rsa_generate_additional_parameters(k->rsa);
389                 break;
390         case 2:
391                 type_name = buffer_get_string(&e->input, NULL);
392                 type = key_type_from_name(type_name);
393                 xfree(type_name);
394                 switch (type) {
395                 case KEY_DSA:
396                         k = key_new_private(type);
397                         buffer_get_bignum2(&e->input, k->dsa->p);
398                         buffer_get_bignum2(&e->input, k->dsa->q);
399                         buffer_get_bignum2(&e->input, k->dsa->g);
400                         buffer_get_bignum2(&e->input, k->dsa->pub_key);
401                         buffer_get_bignum2(&e->input, k->dsa->priv_key);
402                         break;
403                 case KEY_RSA:
404                         k = key_new_private(type);
405                         buffer_get_bignum2(&e->input, k->rsa->n);
406                         buffer_get_bignum2(&e->input, k->rsa->e);
407                         buffer_get_bignum2(&e->input, k->rsa->d);
408                         buffer_get_bignum2(&e->input, k->rsa->iqmp);
409                         buffer_get_bignum2(&e->input, k->rsa->p);
410                         buffer_get_bignum2(&e->input, k->rsa->q);
411
412                         /* Generate additional parameters */
413                         rsa_generate_additional_parameters(k->rsa);
414                         break;
415                 default:
416                         buffer_clear(&e->input);
417                         goto send;
418                 }
419                 break;
420         }
421         comment = buffer_get_string(&e->input, NULL);
422         if (k == NULL) {
423                 xfree(comment);
424                 goto send;
425         }
426         success = 1;
427         if (lookup_identity(k, version) == NULL) {
428                 Identity *id = xmalloc(sizeof(Identity));
429                 id->key = k;
430                 id->comment = comment;
431                 TAILQ_INSERT_TAIL(&tab->idlist, id, next);
432                 /* Increment the number of identities. */
433                 tab->nentries++;
434         } else {
435                 key_free(k);
436                 xfree(comment);
437         }
438 send:
439         buffer_put_int(&e->output, 1);
440         buffer_put_char(&e->output,
441             success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
442 }
443
444
445 #ifdef SMARTCARD
446 static void
447 process_add_smartcard_key (SocketEntry *e)
448 {
449         Identity *id;
450         Idtab *tab;
451         Key **keys, *k;
452         char *sc_reader_id = NULL, *pin;
453         int i, version, success = 0;
454
455         sc_reader_id = buffer_get_string(&e->input, NULL);
456         pin = buffer_get_string(&e->input, NULL);
457         keys = sc_get_keys(sc_reader_id, pin);
458         xfree(sc_reader_id);
459         xfree(pin);
460
461         if (keys == NULL || keys[0] == NULL) {
462                 error("sc_get_keys failed");
463                 goto send;
464         }
465         for (i = 0; keys[i] != NULL; i++) {
466                 k = keys[i];
467                 version = k->type == KEY_RSA1 ? 1 : 2;
468                 tab = idtab_lookup(version);
469                 if (lookup_identity(k, version) == NULL) {
470                         id = xmalloc(sizeof(Identity));
471                         id->key = k;
472                         id->comment = xstrdup("smartcard key");
473                         TAILQ_INSERT_TAIL(&tab->idlist, id, next);
474                         tab->nentries++;
475                         success = 1;
476                 } else {
477                         key_free(k);
478                 }
479                 keys[i] = NULL;
480         }
481         xfree(keys);
482 send:
483         buffer_put_int(&e->output, 1);
484         buffer_put_char(&e->output,
485             success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
486 }
487
488 static void
489 process_remove_smartcard_key(SocketEntry *e)
490 {
491         Identity *id;
492         Idtab *tab;
493         Key **keys, *k = NULL;
494         char *sc_reader_id = NULL, *pin;
495         int i, version, success = 0;
496
497         sc_reader_id = buffer_get_string(&e->input, NULL);
498         pin = buffer_get_string(&e->input, NULL);
499         keys = sc_get_keys(sc_reader_id, pin);
500         xfree(sc_reader_id);
501         xfree(pin);
502
503         if (keys == NULL || keys[0] == NULL) {
504                 error("sc_get_keys failed");
505                 goto send;
506         }
507         for (i = 0; keys[i] != NULL; i++) {
508                 k = keys[i];
509                 version = k->type == KEY_RSA1 ? 1 : 2;
510                 if ((id = lookup_identity(k, version)) != NULL) {
511                         tab = idtab_lookup(version);
512                         TAILQ_REMOVE(&tab->idlist, id, next);
513                         tab->nentries--;
514                         free_identity(id);
515                         success = 1;
516                 }
517                 key_free(k);
518                 keys[i] = NULL;
519         }
520         xfree(keys);
521 send:
522         buffer_put_int(&e->output, 1);
523         buffer_put_char(&e->output,
524             success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
525 }
526 #endif /* SMARTCARD */
527
528 /* dispatch incoming messages */
529
530 static void
531 process_message(SocketEntry *e)
532 {
533         u_int msg_len;
534         u_int type;
535         u_char *cp;
536         if (buffer_len(&e->input) < 5)
537                 return;         /* Incomplete message. */
538         cp = buffer_ptr(&e->input);
539         msg_len = GET_32BIT(cp);
540         if (msg_len > 256 * 1024) {
541                 shutdown(e->fd, SHUT_RDWR);
542                 close(e->fd);
543                 e->type = AUTH_UNUSED;
544                 return;
545         }
546         if (buffer_len(&e->input) < msg_len + 4)
547                 return;
548         buffer_consume(&e->input, 4);
549         type = buffer_get_char(&e->input);
550
551         debug("type %d", type);
552         switch (type) {
553         /* ssh1 */
554         case SSH_AGENTC_RSA_CHALLENGE:
555                 process_authentication_challenge1(e);
556                 break;
557         case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
558                 process_request_identities(e, 1);
559                 break;
560         case SSH_AGENTC_ADD_RSA_IDENTITY:
561                 process_add_identity(e, 1);
562                 break;
563         case SSH_AGENTC_REMOVE_RSA_IDENTITY:
564                 process_remove_identity(e, 1);
565                 break;
566         case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
567                 process_remove_all_identities(e, 1);
568                 break;
569         /* ssh2 */
570         case SSH2_AGENTC_SIGN_REQUEST:
571                 process_sign_request2(e);
572                 break;
573         case SSH2_AGENTC_REQUEST_IDENTITIES:
574                 process_request_identities(e, 2);
575                 break;
576         case SSH2_AGENTC_ADD_IDENTITY:
577                 process_add_identity(e, 2);
578                 break;
579         case SSH2_AGENTC_REMOVE_IDENTITY:
580                 process_remove_identity(e, 2);
581                 break;
582         case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
583                 process_remove_all_identities(e, 2);
584                 break;
585 #ifdef SMARTCARD
586         case SSH_AGENTC_ADD_SMARTCARD_KEY:
587                 process_add_smartcard_key(e);
588                 break;
589         case SSH_AGENTC_REMOVE_SMARTCARD_KEY:
590                 process_remove_smartcard_key(e);
591                 break;
592 #endif /* SMARTCARD */
593         default:
594                 /* Unknown message.  Respond with failure. */
595                 error("Unknown message %d", type);
596                 buffer_clear(&e->input);
597                 buffer_put_int(&e->output, 1);
598                 buffer_put_char(&e->output, SSH_AGENT_FAILURE);
599                 break;
600         }
601 }
602
603 static void
604 new_socket(sock_type type, int fd)
605 {
606         u_int i, old_alloc;
607         if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
608                 error("fcntl O_NONBLOCK: %s", strerror(errno));
609
610         if (fd > max_fd)
611                 max_fd = fd;
612
613         for (i = 0; i < sockets_alloc; i++)
614                 if (sockets[i].type == AUTH_UNUSED) {
615                         sockets[i].fd = fd;
616                         sockets[i].type = type;
617                         buffer_init(&sockets[i].input);
618                         buffer_init(&sockets[i].output);
619                         return;
620                 }
621         old_alloc = sockets_alloc;
622         sockets_alloc += 10;
623         if (sockets)
624                 sockets = xrealloc(sockets, sockets_alloc * sizeof(sockets[0]));
625         else
626                 sockets = xmalloc(sockets_alloc * sizeof(sockets[0]));
627         for (i = old_alloc; i < sockets_alloc; i++)
628                 sockets[i].type = AUTH_UNUSED;
629         sockets[old_alloc].type = type;
630         sockets[old_alloc].fd = fd;
631         buffer_init(&sockets[old_alloc].input);
632         buffer_init(&sockets[old_alloc].output);
633 }
634
635 static int
636 prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl, int *nallocp)
637 {
638         u_int i, sz;
639         int n = 0;
640
641         for (i = 0; i < sockets_alloc; i++) {
642                 switch (sockets[i].type) {
643                 case AUTH_SOCKET:
644                 case AUTH_CONNECTION:
645                         n = MAX(n, sockets[i].fd);
646                         break;
647                 case AUTH_UNUSED:
648                         break;
649                 default:
650                         fatal("Unknown socket type %d", sockets[i].type);
651                         break;
652                 }
653         }
654
655         sz = howmany(n+1, NFDBITS) * sizeof(fd_mask);
656         if (*fdrp == NULL || sz > *nallocp) {
657                 if (*fdrp)
658                         xfree(*fdrp);
659                 if (*fdwp)
660                         xfree(*fdwp);
661                 *fdrp = xmalloc(sz);
662                 *fdwp = xmalloc(sz);
663                 *nallocp = sz;
664         }
665         if (n < *fdl)
666                 debug("XXX shrink: %d < %d", n, *fdl);
667         *fdl = n;
668         memset(*fdrp, 0, sz);
669         memset(*fdwp, 0, sz);
670
671         for (i = 0; i < sockets_alloc; i++) {
672                 switch (sockets[i].type) {
673                 case AUTH_SOCKET:
674                 case AUTH_CONNECTION:
675                         FD_SET(sockets[i].fd, *fdrp);
676                         if (buffer_len(&sockets[i].output) > 0)
677                                 FD_SET(sockets[i].fd, *fdwp);
678                         break;
679                 default:
680                         break;
681                 }
682         }
683         return (1);
684 }
685
686 static void
687 after_select(fd_set *readset, fd_set *writeset)
688 {
689         u_int i;
690         int len, sock;
691         socklen_t slen;
692         char buf[1024];
693         struct sockaddr_un sunaddr;
694
695         for (i = 0; i < sockets_alloc; i++)
696                 switch (sockets[i].type) {
697                 case AUTH_UNUSED:
698                         break;
699                 case AUTH_SOCKET:
700                         if (FD_ISSET(sockets[i].fd, readset)) {
701                                 slen = sizeof(sunaddr);
702                                 sock = accept(sockets[i].fd,
703                                     (struct sockaddr *) &sunaddr, &slen);
704                                 if (sock < 0) {
705                                         error("accept from AUTH_SOCKET: %s",
706                                             strerror(errno));
707                                         break;
708                                 }
709                                 new_socket(AUTH_CONNECTION, sock);
710                         }
711                         break;
712                 case AUTH_CONNECTION:
713                         if (buffer_len(&sockets[i].output) > 0 &&
714                             FD_ISSET(sockets[i].fd, writeset)) {
715                                 do {
716                                         len = write(sockets[i].fd,
717                                             buffer_ptr(&sockets[i].output),
718                                             buffer_len(&sockets[i].output));
719                                         if (len == -1 && (errno == EAGAIN ||
720                                             errno == EINTR))
721                                                 continue;
722                                         break;
723                                 } while (1);
724                                 if (len <= 0) {
725                                         shutdown(sockets[i].fd, SHUT_RDWR);
726                                         close(sockets[i].fd);
727                                         sockets[i].type = AUTH_UNUSED;
728                                         buffer_free(&sockets[i].input);
729                                         buffer_free(&sockets[i].output);
730                                         break;
731                                 }
732                                 buffer_consume(&sockets[i].output, len);
733                         }
734                         if (FD_ISSET(sockets[i].fd, readset)) {
735                                 do {
736                                         len = read(sockets[i].fd, buf, sizeof(buf));
737                                         if (len == -1 && (errno == EAGAIN ||
738                                             errno == EINTR))
739                                                 continue;
740                                         break;
741                                 } while (1);
742                                 if (len <= 0) {
743                                         shutdown(sockets[i].fd, SHUT_RDWR);
744                                         close(sockets[i].fd);
745                                         sockets[i].type = AUTH_UNUSED;
746                                         buffer_free(&sockets[i].input);
747                                         buffer_free(&sockets[i].output);
748                                         break;
749                                 }
750                                 buffer_append(&sockets[i].input, buf, len);
751                                 process_message(&sockets[i]);
752                         }
753                         break;
754                 default:
755                         fatal("Unknown type %d", sockets[i].type);
756                 }
757 }
758
759 static void
760 cleanup_socket(void *p)
761 {
762         if (socket_name[0])
763                 unlink(socket_name);
764         if (socket_dir[0])
765                 rmdir(socket_dir);
766 }
767
768 static void
769 cleanup_exit(int i)
770 {
771         cleanup_socket(NULL);
772         exit(i);
773 }
774
775 static void
776 cleanup_handler(int sig)
777 {
778         cleanup_socket(NULL);
779         _exit(2);
780 }
781
782 static void
783 check_parent_exists(int sig)
784 {
785         int save_errno = errno;
786
787         if (parent_pid != -1 && kill(parent_pid, 0) < 0) {
788                 /* printf("Parent has died - Authentication agent exiting.\n"); */
789                 cleanup_handler(sig); /* safe */
790         }
791         signal(SIGALRM, check_parent_exists);
792         alarm(10);
793         errno = save_errno;
794 }
795
796 static void
797 usage(void)
798 {
799         fprintf(stderr, "Usage: %s [options] [command [args ...]]\n",
800             __progname);
801         fprintf(stderr, "Options:\n");
802         fprintf(stderr, "  -c          Generate C-shell commands on stdout.\n");
803         fprintf(stderr, "  -s          Generate Bourne shell commands on stdout.\n");
804         fprintf(stderr, "  -k          Kill the current agent.\n");
805         fprintf(stderr, "  -d          Debug mode.\n");
806         fprintf(stderr, "  -a socket   Bind agent socket to given name.\n");
807         exit(1);
808 }
809
810 int
811 main(int ac, char **av)
812 {
813         int sock, c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0, ch, nalloc;
814         struct sockaddr_un sunaddr;
815 #ifdef HAVE_SETRLIMIT
816         struct rlimit rlim;
817 #endif
818 #ifdef HAVE_CYGWIN
819         int prev_mask;
820 #endif
821         pid_t pid;
822         char *shell, *format, *pidstr, pidstrbuf[1 + 3 * sizeof pid];
823         char *agentsocket = NULL;
824         extern int optind;
825         fd_set *readsetp = NULL, *writesetp = NULL;
826
827         SSLeay_add_all_algorithms();
828
829         __progname = get_progname(av[0]);
830         init_rng();
831         seed_rng();
832
833 #ifdef __GNU_LIBRARY__
834         while ((ch = getopt(ac, av, "+cdksa:")) != -1) {
835 #else /* __GNU_LIBRARY__ */
836         while ((ch = getopt(ac, av, "cdksa:")) != -1) {
837 #endif /* __GNU_LIBRARY__ */
838                 switch (ch) {
839                 case 'c':
840                         if (s_flag)
841                                 usage();
842                         c_flag++;
843                         break;
844                 case 'k':
845                         k_flag++;
846                         break;
847                 case 's':
848                         if (c_flag)
849                                 usage();
850                         s_flag++;
851                         break;
852                 case 'd':
853                         if (d_flag)
854                                 usage();
855                         d_flag++;
856                         break;
857                 case 'a':
858                         agentsocket = optarg;
859                         break;
860                 default:
861                         usage();
862                 }
863         }
864         ac -= optind;
865         av += optind;
866
867         if (ac > 0 && (c_flag || k_flag || s_flag || d_flag))
868                 usage();
869
870         if (ac == 0 && !c_flag && !s_flag) {
871                 shell = getenv("SHELL");
872                 if (shell != NULL && strncmp(shell + strlen(shell) - 3, "csh", 3) == 0)
873                         c_flag = 1;
874         }
875         if (k_flag) {
876                 pidstr = getenv(SSH_AGENTPID_ENV_NAME);
877                 if (pidstr == NULL) {
878                         fprintf(stderr, "%s not set, cannot kill agent\n",
879                             SSH_AGENTPID_ENV_NAME);
880                         exit(1);
881                 }
882                 pid = atoi(pidstr);
883                 if (pid < 1) {
884                         fprintf(stderr, "%s=\"%s\", which is not a good PID\n",
885                             SSH_AGENTPID_ENV_NAME, pidstr);
886                         exit(1);
887                 }
888                 if (kill(pid, SIGTERM) == -1) {
889                         perror("kill");
890                         exit(1);
891                 }
892                 format = c_flag ? "unsetenv %s;\n" : "unset %s;\n";
893                 printf(format, SSH_AUTHSOCKET_ENV_NAME);
894                 printf(format, SSH_AGENTPID_ENV_NAME);
895                 printf("echo Agent pid %d killed;\n", pid);
896                 exit(0);
897         }
898         parent_pid = getpid();
899
900         if (agentsocket == NULL) {
901                 /* Create private directory for agent socket */
902                 strlcpy(socket_dir, "/tmp/ssh-XXXXXXXX", sizeof socket_dir);
903                 if (mkdtemp(socket_dir) == NULL) {
904                         perror("mkdtemp: private socket dir");
905                         exit(1);
906                 }
907                 snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir,
908                     parent_pid);
909         } else {
910                 /* Try to use specified agent socket */
911                 socket_dir[0] = '\0';
912                 strlcpy(socket_name, agentsocket, sizeof socket_name);
913         }
914
915         /*
916          * Create socket early so it will exist before command gets run from
917          * the parent.
918          */
919         sock = socket(AF_UNIX, SOCK_STREAM, 0);
920         if (sock < 0) {
921                 perror("socket");
922                 cleanup_exit(1);
923         }
924         memset(&sunaddr, 0, sizeof(sunaddr));
925         sunaddr.sun_family = AF_UNIX;
926         strlcpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path));
927 #ifdef HAVE_CYGWIN
928         prev_mask = umask(0177);
929 #endif
930         if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) {
931                 perror("bind");
932 #ifdef HAVE_CYGWIN
933                 umask(prev_mask);
934 #endif
935                 cleanup_exit(1);
936         }
937 #ifdef HAVE_CYGWIN
938         umask(prev_mask);
939 #endif
940         if (listen(sock, 5) < 0) {
941                 perror("listen");
942                 cleanup_exit(1);
943         }
944
945         /*
946          * Fork, and have the parent execute the command, if any, or present
947          * the socket data.  The child continues as the authentication agent.
948          */
949         if (d_flag) {
950                 log_init(__progname, SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 1);
951                 format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
952                 printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
953                     SSH_AUTHSOCKET_ENV_NAME);
954                 printf("echo Agent pid %d;\n", parent_pid);
955                 goto skip;
956         }
957         pid = fork();
958         if (pid == -1) {
959                 perror("fork");
960                 cleanup_exit(1);
961         }
962         if (pid != 0) {         /* Parent - execute the given command. */
963                 close(sock);
964                 snprintf(pidstrbuf, sizeof pidstrbuf, "%d", pid);
965                 if (ac == 0) {
966                         format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
967                         printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
968                             SSH_AUTHSOCKET_ENV_NAME);
969                         printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf,
970                             SSH_AGENTPID_ENV_NAME);
971                         printf("echo Agent pid %d;\n", pid);
972                         exit(0);
973                 }
974                 if (setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1) == -1 ||
975                     setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1) == -1) {
976                         perror("setenv");
977                         exit(1);
978                 }
979                 execvp(av[0], av);
980                 perror(av[0]);
981                 exit(1);
982         }
983         /* child */
984         log_init(__progname, SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_AUTH, 0);
985
986         if (setsid() == -1) {
987                 error("setsid: %s", strerror(errno));
988                 cleanup_exit(1);
989         }
990
991         (void)chdir("/");
992         close(0);
993         close(1);
994         close(2);
995
996 #ifdef HAVE_SETRLIMIT
997         /* deny core dumps, since memory contains unencrypted private keys */
998         rlim.rlim_cur = rlim.rlim_max = 0;
999         if (setrlimit(RLIMIT_CORE, &rlim) < 0) {
1000                 error("setrlimit RLIMIT_CORE: %s", strerror(errno));
1001                 cleanup_exit(1);
1002         }
1003 #endif
1004
1005 skip:
1006         fatal_add_cleanup(cleanup_socket, NULL);
1007         new_socket(AUTH_SOCKET, sock);
1008         if (ac > 0) {
1009                 signal(SIGALRM, check_parent_exists);
1010                 alarm(10);
1011         }
1012         idtab_init();
1013         if (!d_flag)
1014                 signal(SIGINT, SIG_IGN);
1015         signal(SIGPIPE, SIG_IGN);
1016         signal(SIGHUP, cleanup_handler);
1017         signal(SIGTERM, cleanup_handler);
1018         nalloc = 0;
1019
1020         while (1) {
1021                 prepare_select(&readsetp, &writesetp, &max_fd, &nalloc);
1022                 if (select(max_fd + 1, readsetp, writesetp, NULL, NULL) < 0) {
1023                         if (errno == EINTR)
1024                                 continue;
1025                         fatal("select: %s", strerror(errno));
1026                 }
1027                 after_select(readsetp, writesetp);
1028         }
1029         /* NOTREACHED */
1030 }
This page took 0.735079 seconds and 5 git commands to generate.