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