]> andersk Git - openssh.git/blob - ssh-agent.c
20001203
[openssh.git] / ssh-agent.c
1 /*      $OpenBSD: ssh-agent.c,v 1.41 2000/11/30 18:33:05 markus 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  * SSH2 implementation,
16  * Copyright (c) 2000 Markus Friedl. All rights reserved.
17  *
18  * Redistribution and use in source and binary forms, with or without
19  * modification, are permitted provided that the following conditions
20  * are met:
21  * 1. Redistributions of source code must retain the above copyright
22  *    notice, this list of conditions and the following disclaimer.
23  * 2. Redistributions in binary form must reproduce the above copyright
24  *    notice, this list of conditions and the following disclaimer in the
25  *    documentation and/or other materials provided with the distribution.
26  *
27  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
28  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
29  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
30  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
31  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
32  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
33  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
34  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
35  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
36  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
37  */
38
39 #include "includes.h"
40 RCSID("$OpenBSD: ssh-agent.c,v 1.41 2000/11/30 18:33:05 markus Exp $");
41
42 #include "ssh.h"
43 #include "rsa.h"
44 #include "buffer.h"
45 #include "bufaux.h"
46 #include "xmalloc.h"
47 #include "packet.h"
48 #include "getput.h"
49 #include "mpaux.h"
50
51 #include <openssl/evp.h>
52 #include <openssl/md5.h>
53 #include <openssl/dsa.h>
54 #include <openssl/rsa.h>
55 #include "key.h"
56 #include "authfd.h"
57 #include "kex.h"
58 #include "compat.h"
59
60 typedef struct {
61         int fd;
62         enum {
63                 AUTH_UNUSED, AUTH_SOCKET, AUTH_CONNECTION
64         } type;
65         Buffer input;
66         Buffer output;
67 } SocketEntry;
68
69 unsigned int sockets_alloc = 0;
70 SocketEntry *sockets = NULL;
71
72 typedef struct {
73         Key *key;
74         char *comment;
75 } Identity;
76
77 typedef struct {
78         int nentries;
79         Identity *identities;
80 } Idtab;
81
82 /* private key table, one per protocol version */
83 Idtab idtable[3];
84
85 int max_fd = 0;
86
87 /* pid of shell == parent of agent */
88 pid_t parent_pid = -1;
89
90 /* pathname and directory for AUTH_SOCKET */
91 char socket_name[1024];
92 char socket_dir[1024];
93
94 #ifdef HAVE___PROGNAME
95 extern char *__progname;
96 #else
97 char *__progname;
98 #endif
99
100 void
101 idtab_init(void)
102 {
103         int i;
104         for (i = 0; i <=2; i++){
105                 idtable[i].identities = NULL;
106                 idtable[i].nentries = 0;
107         }
108 }
109
110 /* return private key table for requested protocol version */
111 Idtab *
112 idtab_lookup(int version)
113 {
114         if (version < 1 || version > 2)
115                 fatal("internal error, bad protocol version %d", version);
116         return &idtable[version];
117 }
118
119 /* return matching private key for given public key */
120 Key *
121 lookup_private_key(Key *key, int *idx, int version)
122 {
123         int i;
124         Idtab *tab = idtab_lookup(version);
125         for (i = 0; i < tab->nentries; i++) {
126                 if (key_equal(key, tab->identities[i].key)) {
127                         if (idx != NULL)
128                                 *idx = i;
129                         return tab->identities[i].key;
130                 }
131         }
132         return NULL;
133 }
134
135 /* send list of supported public keys to 'client' */
136 void
137 process_request_identities(SocketEntry *e, int version)
138 {
139         Idtab *tab = idtab_lookup(version);
140         Buffer msg;
141         int i;
142
143         buffer_init(&msg);
144         buffer_put_char(&msg, (version == 1) ?
145             SSH_AGENT_RSA_IDENTITIES_ANSWER : SSH2_AGENT_IDENTITIES_ANSWER);
146         buffer_put_int(&msg, tab->nentries);
147         for (i = 0; i < tab->nentries; i++) {
148                 Identity *id = &tab->identities[i];
149                 if (id->key->type == KEY_RSA1) {
150                         buffer_put_int(&msg, BN_num_bits(id->key->rsa->n));
151                         buffer_put_bignum(&msg, id->key->rsa->e);
152                         buffer_put_bignum(&msg, id->key->rsa->n);
153                 } else {
154                         unsigned char *blob;
155                         unsigned int blen;
156                         key_to_blob(id->key, &blob, &blen);
157                         buffer_put_string(&msg, blob, blen);
158                         xfree(blob);
159                 }
160                 buffer_put_cstring(&msg, id->comment);
161         }
162         buffer_put_int(&e->output, buffer_len(&msg));
163         buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
164         buffer_free(&msg);
165 }
166
167 /* ssh1 only */
168 void
169 process_authentication_challenge1(SocketEntry *e)
170 {
171         Key *key, *private;
172         BIGNUM *challenge;
173         int i, len;
174         Buffer msg;
175         MD5_CTX md;
176         unsigned char buf[32], mdbuf[16], session_id[16];
177         unsigned int response_type;
178
179         buffer_init(&msg);
180         key = key_new(KEY_RSA1);
181         challenge = BN_new();
182
183         buffer_get_int(&e->input);                              /* ignored */
184         buffer_get_bignum(&e->input, key->rsa->e);
185         buffer_get_bignum(&e->input, key->rsa->n);
186         buffer_get_bignum(&e->input, challenge);
187
188         /* Only protocol 1.1 is supported */
189         if (buffer_len(&e->input) == 0)
190                 goto failure;
191         buffer_get(&e->input, (char *) session_id, 16);
192         response_type = buffer_get_int(&e->input);
193         if (response_type != 1)
194                 goto failure;
195
196         private = lookup_private_key(key, NULL, 1);
197         if (private != NULL) {
198                 /* Decrypt the challenge using the private key. */
199                 rsa_private_decrypt(challenge, challenge, private->rsa);
200
201                 /* The response is MD5 of decrypted challenge plus session id. */
202                 len = BN_num_bytes(challenge);
203                 if (len <= 0 || len > 32) {
204                         log("process_authentication_challenge: bad challenge length %d", len);
205                         goto failure;
206                 }
207                 memset(buf, 0, 32);
208                 BN_bn2bin(challenge, buf + 32 - len);
209                 MD5_Init(&md);
210                 MD5_Update(&md, buf, 32);
211                 MD5_Update(&md, session_id, 16);
212                 MD5_Final(mdbuf, &md);
213
214                 /* Send the response. */
215                 buffer_put_char(&msg, SSH_AGENT_RSA_RESPONSE);
216                 for (i = 0; i < 16; i++)
217                         buffer_put_char(&msg, mdbuf[i]);
218                 goto send;
219         }
220
221 failure:
222         /* Unknown identity or protocol error.  Send failure. */
223         buffer_put_char(&msg, SSH_AGENT_FAILURE);
224 send:
225         buffer_put_int(&e->output, buffer_len(&msg));
226         buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
227         key_free(key);
228         BN_clear_free(challenge);
229         buffer_free(&msg);
230 }
231
232 /* ssh2 only */
233 void
234 process_sign_request2(SocketEntry *e)
235 {
236         extern int datafellows;
237         Key *key, *private;
238         unsigned char *blob, *data, *signature = NULL;
239         unsigned int blen, dlen, slen = 0;
240         int flags;
241         Buffer msg;
242         int ok = -1;
243
244         datafellows = 0;
245         
246         blob = buffer_get_string(&e->input, &blen);
247         data = buffer_get_string(&e->input, &dlen);
248
249         flags = buffer_get_int(&e->input);
250         if (flags & SSH_AGENT_OLD_SIGNATURE)
251                 datafellows = SSH_BUG_SIGBLOB;
252
253         key = key_from_blob(blob, blen);
254         if (key != NULL) {
255                 private = lookup_private_key(key, NULL, 2);
256                 if (private != NULL)
257                         ok = key_sign(private, &signature, &slen, data, dlen);
258         }
259         key_free(key);
260         buffer_init(&msg);
261         if (ok == 0) {
262                 buffer_put_char(&msg, SSH2_AGENT_SIGN_RESPONSE);
263                 buffer_put_string(&msg, signature, slen);
264         } else {
265                 buffer_put_char(&msg, SSH_AGENT_FAILURE);
266         }
267         buffer_put_int(&e->output, buffer_len(&msg));
268         buffer_append(&e->output, buffer_ptr(&msg),
269             buffer_len(&msg));
270         buffer_free(&msg);
271         xfree(data);
272         xfree(blob);
273         if (signature != NULL)
274                 xfree(signature);
275 }
276
277 /* shared */
278 void
279 process_remove_identity(SocketEntry *e, int version)
280 {
281         Key *key = NULL, *private;
282         unsigned char *blob;
283         unsigned int blen;
284         unsigned int bits;
285         int success = 0;
286
287         switch(version){
288         case 1:
289                 key = key_new(KEY_RSA1);
290                 bits = buffer_get_int(&e->input);
291                 buffer_get_bignum(&e->input, key->rsa->e);
292                 buffer_get_bignum(&e->input, key->rsa->n);
293
294                 if (bits != key_size(key))
295                         log("Warning: identity keysize mismatch: actual %d, announced %d",
296                               key_size(key), bits);
297                 break;
298         case 2:
299                 blob = buffer_get_string(&e->input, &blen);
300                 key = key_from_blob(blob, blen);
301                 xfree(blob);
302                 break;
303         }
304         if (key != NULL) {
305                 int idx;
306                 private = lookup_private_key(key, &idx, version);
307                 if (private != NULL) {
308                         /*
309                          * We have this key.  Free the old key.  Since we
310                          * don\'t want to leave empty slots in the middle of
311                          * the array, we actually free the key there and move
312                          * all the entries between the empty slot and the end
313                          * of the array.
314                          */
315                         Idtab *tab = idtab_lookup(version);
316                         key_free(tab->identities[idx].key);
317                         xfree(tab->identities[idx].comment);
318                         if (tab->nentries < 1)
319                                 fatal("process_remove_identity: "
320                                     "internal error: tab->nentries %d",
321                                     tab->nentries);
322                         if (idx != tab->nentries - 1) {
323                                 int i;
324                                 for (i = idx; i < tab->nentries - 1; i++)
325                                         tab->identities[i] = tab->identities[i+1];
326                         }
327                         tab->identities[tab->nentries - 1].key = NULL;
328                         tab->identities[tab->nentries - 1].comment = NULL;
329                         tab->nentries--;
330                         success = 1;
331                 }
332                 key_free(key);
333         }
334         buffer_put_int(&e->output, 1);
335         buffer_put_char(&e->output,
336             success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
337 }
338
339 void
340 process_remove_all_identities(SocketEntry *e, int version)
341 {
342         unsigned int i;
343         Idtab *tab = idtab_lookup(version);
344
345         /* Loop over all identities and clear the keys. */
346         for (i = 0; i < tab->nentries; i++) {
347                 key_free(tab->identities[i].key);
348                 xfree(tab->identities[i].comment);
349         }
350
351         /* Mark that there are no identities. */
352         tab->nentries = 0;
353
354         /* Send success. */
355         buffer_put_int(&e->output, 1);
356         buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
357         return;
358 }
359
360 void
361 generate_additional_parameters(RSA *rsa)
362 {
363         BIGNUM *aux;
364         BN_CTX *ctx;
365         /* Generate additional parameters */
366         aux = BN_new();
367         ctx = BN_CTX_new();
368
369         BN_sub(aux, rsa->q, BN_value_one());
370         BN_mod(rsa->dmq1, rsa->d, aux, ctx);
371
372         BN_sub(aux, rsa->p, BN_value_one());
373         BN_mod(rsa->dmp1, rsa->d, aux, ctx);
374
375         BN_clear_free(aux);
376         BN_CTX_free(ctx);
377 }
378
379 void
380 process_add_identity(SocketEntry *e, int version)
381 {
382         Key *k = NULL;
383         char *type_name;
384         char *comment;
385         int type, success = 0;
386         Idtab *tab = idtab_lookup(version);
387
388         switch (version) {
389         case 1:
390                 k = key_new_private(KEY_RSA1);
391                 buffer_get_int(&e->input);                      /* ignored */
392                 buffer_get_bignum(&e->input, k->rsa->n);
393                 buffer_get_bignum(&e->input, k->rsa->e);
394                 buffer_get_bignum(&e->input, k->rsa->d);
395                 buffer_get_bignum(&e->input, k->rsa->iqmp);
396
397                 /* SSH and SSL have p and q swapped */
398                 buffer_get_bignum(&e->input, k->rsa->q);        /* p */
399                 buffer_get_bignum(&e->input, k->rsa->p);        /* q */
400
401                 /* Generate additional parameters */
402                 generate_additional_parameters(k->rsa);
403                 break;
404         case 2:
405                 type_name = buffer_get_string(&e->input, NULL);
406                 type = key_type_from_name(type_name);
407                 xfree(type_name);
408                 switch(type) {
409                 case KEY_DSA:
410                         k = key_new_private(type);
411                         buffer_get_bignum2(&e->input, k->dsa->p);
412                         buffer_get_bignum2(&e->input, k->dsa->q);
413                         buffer_get_bignum2(&e->input, k->dsa->g);
414                         buffer_get_bignum2(&e->input, k->dsa->pub_key);
415                         buffer_get_bignum2(&e->input, k->dsa->priv_key);
416                         break;
417                 case KEY_RSA:
418                         k = key_new_private(type);
419                         buffer_get_bignum2(&e->input, k->rsa->n);
420                         buffer_get_bignum2(&e->input, k->rsa->e);
421                         buffer_get_bignum2(&e->input, k->rsa->d);
422                         buffer_get_bignum2(&e->input, k->rsa->iqmp);
423                         buffer_get_bignum2(&e->input, k->rsa->p);
424                         buffer_get_bignum2(&e->input, k->rsa->q);
425
426                         /* Generate additional parameters */
427                         generate_additional_parameters(k->rsa);
428                         break;
429                 default:
430                         buffer_clear(&e->input);
431                         goto send;
432                 }
433                 break;
434         }
435         comment = buffer_get_string(&e->input, NULL);
436         if (k == NULL) {
437                 xfree(comment);
438                 goto send;
439         }
440         success = 1;
441         if (lookup_private_key(k, NULL, version) == NULL) {
442                 if (tab->nentries == 0)
443                         tab->identities = xmalloc(sizeof(Identity));
444                 else
445                         tab->identities = xrealloc(tab->identities,
446                             (tab->nentries + 1) * sizeof(Identity));
447                 tab->identities[tab->nentries].key = k;
448                 tab->identities[tab->nentries].comment = comment;
449                 /* Increment the number of identities. */
450                 tab->nentries++;
451         } else {
452                 key_free(k);
453                 xfree(comment);
454         }
455 send:
456         buffer_put_int(&e->output, 1);
457         buffer_put_char(&e->output,
458             success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
459 }
460
461 /* dispatch incoming messages */
462
463 void
464 process_message(SocketEntry *e)
465 {
466         unsigned int msg_len;
467         unsigned int type;
468         unsigned char *cp;
469         if (buffer_len(&e->input) < 5)
470                 return;         /* Incomplete message. */
471         cp = (unsigned char *) buffer_ptr(&e->input);
472         msg_len = GET_32BIT(cp);
473         if (msg_len > 256 * 1024) {
474                 shutdown(e->fd, SHUT_RDWR);
475                 close(e->fd);
476                 e->type = AUTH_UNUSED;
477                 return;
478         }
479         if (buffer_len(&e->input) < msg_len + 4)
480                 return;
481         buffer_consume(&e->input, 4);
482         type = buffer_get_char(&e->input);
483
484         switch (type) {
485         /* ssh1 */
486         case SSH_AGENTC_RSA_CHALLENGE:
487                 process_authentication_challenge1(e);
488                 break;
489         case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
490                 process_request_identities(e, 1);
491                 break;
492         case SSH_AGENTC_ADD_RSA_IDENTITY:
493                 process_add_identity(e, 1);
494                 break;
495         case SSH_AGENTC_REMOVE_RSA_IDENTITY:
496                 process_remove_identity(e, 1);
497                 break;
498         case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
499                 process_remove_all_identities(e, 1);
500                 break;
501         /* ssh2 */
502         case SSH2_AGENTC_SIGN_REQUEST:
503                 process_sign_request2(e);
504                 break;
505         case SSH2_AGENTC_REQUEST_IDENTITIES:
506                 process_request_identities(e, 2);
507                 break;
508         case SSH2_AGENTC_ADD_IDENTITY:
509                 process_add_identity(e, 2);
510                 break;
511         case SSH2_AGENTC_REMOVE_IDENTITY:
512                 process_remove_identity(e, 2);
513                 break;
514         case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
515                 process_remove_all_identities(e, 2);
516                 break;
517         default:
518                 /* Unknown message.  Respond with failure. */
519                 error("Unknown message %d", type);
520                 buffer_clear(&e->input);
521                 buffer_put_int(&e->output, 1);
522                 buffer_put_char(&e->output, SSH_AGENT_FAILURE);
523                 break;
524         }
525 }
526
527 void
528 new_socket(int type, int fd)
529 {
530         unsigned int i, old_alloc;
531         if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
532                 error("fcntl O_NONBLOCK: %s", strerror(errno));
533
534         if (fd > max_fd)
535                 max_fd = fd;
536
537         for (i = 0; i < sockets_alloc; i++)
538                 if (sockets[i].type == AUTH_UNUSED) {
539                         sockets[i].fd = fd;
540                         sockets[i].type = type;
541                         buffer_init(&sockets[i].input);
542                         buffer_init(&sockets[i].output);
543                         return;
544                 }
545         old_alloc = sockets_alloc;
546         sockets_alloc += 10;
547         if (sockets)
548                 sockets = xrealloc(sockets, sockets_alloc * sizeof(sockets[0]));
549         else
550                 sockets = xmalloc(sockets_alloc * sizeof(sockets[0]));
551         for (i = old_alloc; i < sockets_alloc; i++)
552                 sockets[i].type = AUTH_UNUSED;
553         sockets[old_alloc].type = type;
554         sockets[old_alloc].fd = fd;
555         buffer_init(&sockets[old_alloc].input);
556         buffer_init(&sockets[old_alloc].output);
557 }
558
559 void
560 prepare_select(fd_set *readset, fd_set *writeset)
561 {
562         unsigned int i;
563         for (i = 0; i < sockets_alloc; i++)
564                 switch (sockets[i].type) {
565                 case AUTH_SOCKET:
566                 case AUTH_CONNECTION:
567                         FD_SET(sockets[i].fd, readset);
568                         if (buffer_len(&sockets[i].output) > 0)
569                                 FD_SET(sockets[i].fd, writeset);
570                         break;
571                 case AUTH_UNUSED:
572                         break;
573                 default:
574                         fatal("Unknown socket type %d", sockets[i].type);
575                         break;
576                 }
577 }
578
579 void
580 after_select(fd_set *readset, fd_set *writeset)
581 {
582         unsigned int i;
583         int len, sock;
584         socklen_t slen;
585         char buf[1024];
586         struct sockaddr_un sunaddr;
587
588         for (i = 0; i < sockets_alloc; i++)
589                 switch (sockets[i].type) {
590                 case AUTH_UNUSED:
591                         break;
592                 case AUTH_SOCKET:
593                         if (FD_ISSET(sockets[i].fd, readset)) {
594                                 slen = sizeof(sunaddr);
595                                 sock = accept(sockets[i].fd, (struct sockaddr *) & sunaddr, &slen);
596                                 if (sock < 0) {
597                                         perror("accept from AUTH_SOCKET");
598                                         break;
599                                 }
600                                 new_socket(AUTH_CONNECTION, sock);
601                         }
602                         break;
603                 case AUTH_CONNECTION:
604                         if (buffer_len(&sockets[i].output) > 0 &&
605                             FD_ISSET(sockets[i].fd, writeset)) {
606                                 len = write(sockets[i].fd, buffer_ptr(&sockets[i].output),
607                                          buffer_len(&sockets[i].output));
608                                 if (len <= 0) {
609                                         shutdown(sockets[i].fd, SHUT_RDWR);
610                                         close(sockets[i].fd);
611                                         sockets[i].type = AUTH_UNUSED;
612                                         buffer_free(&sockets[i].input);
613                                         buffer_free(&sockets[i].output);
614                                         break;
615                                 }
616                                 buffer_consume(&sockets[i].output, len);
617                         }
618                         if (FD_ISSET(sockets[i].fd, readset)) {
619                                 len = read(sockets[i].fd, buf, sizeof(buf));
620                                 if (len <= 0) {
621                                         shutdown(sockets[i].fd, SHUT_RDWR);
622                                         close(sockets[i].fd);
623                                         sockets[i].type = AUTH_UNUSED;
624                                         buffer_free(&sockets[i].input);
625                                         buffer_free(&sockets[i].output);
626                                         break;
627                                 }
628                                 buffer_append(&sockets[i].input, buf, len);
629                                 process_message(&sockets[i]);
630                         }
631                         break;
632                 default:
633                         fatal("Unknown type %d", sockets[i].type);
634                 }
635 }
636
637 void
638 check_parent_exists(int sig)
639 {
640         if (parent_pid != -1 && kill(parent_pid, 0) < 0) {
641                 /* printf("Parent has died - Authentication agent exiting.\n"); */
642                 exit(1);
643         }
644         signal(SIGALRM, check_parent_exists);
645         alarm(10);
646 }
647
648 void
649 cleanup_socket(void)
650 {
651         unlink(socket_name);
652         rmdir(socket_dir);
653 }
654
655 void
656 cleanup_exit(int i)
657 {
658         cleanup_socket();
659         exit(i);
660 }
661
662 void
663 usage()
664 {
665         fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION);
666         fprintf(stderr, "Usage: %s [-c | -s] [-k] [command {args...]]\n",
667                 __progname);
668         exit(1);
669 }
670
671 int
672 main(int ac, char **av)
673 {
674         fd_set readset, writeset;
675         int sock, c_flag = 0, k_flag = 0, s_flag = 0, ch;
676         struct sockaddr_un sunaddr;
677         struct rlimit rlim;
678         pid_t pid;
679         char *shell, *format, *pidstr, pidstrbuf[1 + 3 * sizeof pid];
680         extern int optind;
681         
682         __progname = get_progname(av[0]);
683         init_rng();
684         
685 #ifdef __GNU_LIBRARY__
686         while ((ch = getopt(ac, av, "+cks")) != -1) {
687 #else /* __GNU_LIBRARY__ */
688         while ((ch = getopt(ac, av, "cks")) != -1) {
689 #endif /* __GNU_LIBRARY__ */
690                 switch (ch) {
691                 case 'c':
692                         if (s_flag)
693                                 usage();
694                         c_flag++;
695                         break;
696                 case 'k':
697                         k_flag++;
698                         break;
699                 case 's':
700                         if (c_flag)
701                                 usage();
702                         s_flag++;
703                         break;
704                 default:
705                         usage();
706                 }
707         }
708         ac -= optind;
709         av += optind;
710
711         if (ac > 0 && (c_flag || k_flag || s_flag))
712                 usage();
713
714         if (ac == 0 && !c_flag && !k_flag && !s_flag) {
715                 shell = getenv("SHELL");
716                 if (shell != NULL && strncmp(shell + strlen(shell) - 3, "csh", 3) == 0)
717                         c_flag = 1;
718         }
719         if (k_flag) {
720                 pidstr = getenv(SSH_AGENTPID_ENV_NAME);
721                 if (pidstr == NULL) {
722                         fprintf(stderr, "%s not set, cannot kill agent\n",
723                                 SSH_AGENTPID_ENV_NAME);
724                         exit(1);
725                 }
726                 pid = atoi(pidstr);
727                 if (pid < 1) {  /* XXX PID_MAX check too */
728                 /* Yes, PID_MAX check please */
729                         fprintf(stderr, "%s=\"%s\", which is not a good PID\n",
730                                 SSH_AGENTPID_ENV_NAME, pidstr);
731                         exit(1);
732                 }
733                 if (kill(pid, SIGTERM) == -1) {
734                         perror("kill");
735                         exit(1);
736                 }
737                 format = c_flag ? "unsetenv %s;\n" : "unset %s;\n";
738                 printf(format, SSH_AUTHSOCKET_ENV_NAME);
739                 printf(format, SSH_AGENTPID_ENV_NAME);
740                 printf("echo Agent pid %d killed;\n", pid);
741                 exit(0);
742         }
743         parent_pid = getpid();
744
745         /* Create private directory for agent socket */
746         strlcpy(socket_dir, "/tmp/ssh-XXXXXXXX", sizeof socket_dir);
747         if (mkdtemp(socket_dir) == NULL) {
748                 perror("mkdtemp: private socket dir");
749                 exit(1);
750         }
751         snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir,
752                  parent_pid);
753
754         /*
755          * Create socket early so it will exist before command gets run from
756          * the parent.
757          */
758         sock = socket(AF_UNIX, SOCK_STREAM, 0);
759         if (sock < 0) {
760                 perror("socket");
761                 cleanup_exit(1);
762         }
763         memset(&sunaddr, 0, sizeof(sunaddr));
764         sunaddr.sun_family = AF_UNIX;
765         strlcpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path));
766         if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) {
767                 perror("bind");
768                 cleanup_exit(1);
769         }
770         if (listen(sock, 5) < 0) {
771                 perror("listen");
772                 cleanup_exit(1);
773         }
774         /*
775          * Fork, and have the parent execute the command, if any, or present
776          * the socket data.  The child continues as the authentication agent.
777          */
778         pid = fork();
779         if (pid == -1) {
780                 perror("fork");
781                 exit(1);
782         }
783         if (pid != 0) {         /* Parent - execute the given command. */
784                 close(sock);
785                 snprintf(pidstrbuf, sizeof pidstrbuf, "%d", pid);
786                 if (ac == 0) {
787                         format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
788                         printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
789                                SSH_AUTHSOCKET_ENV_NAME);
790                         printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf,
791                                SSH_AGENTPID_ENV_NAME);
792                         printf("echo Agent pid %d;\n", pid);
793                         exit(0);
794                 }
795                 if (setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1) == -1 ||
796                     setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1) == -1) {
797                         perror("setenv");
798                         exit(1);
799                 }
800                 execvp(av[0], av);
801                 perror(av[0]);
802                 exit(1);
803         }
804         close(0);
805         close(1);
806         close(2);
807
808         /* deny core dumps, since memory contains unencrypted private keys */
809         rlim.rlim_cur = rlim.rlim_max = 0;
810         if (setrlimit(RLIMIT_CORE, &rlim) < 0) {
811                 perror("setrlimit rlimit_core failed");
812                 cleanup_exit(1);
813         }
814         if (setsid() == -1) {
815                 perror("setsid");
816                 cleanup_exit(1);
817         }
818         if (atexit(cleanup_socket) < 0) {
819                 perror("atexit");
820                 cleanup_exit(1);
821         }
822         new_socket(AUTH_SOCKET, sock);
823         if (ac > 0) {
824                 signal(SIGALRM, check_parent_exists);
825                 alarm(10);
826         }
827         idtab_init();
828         signal(SIGINT, SIG_IGN);
829         signal(SIGPIPE, SIG_IGN);
830         signal(SIGHUP, cleanup_exit);
831         signal(SIGTERM, cleanup_exit);
832         while (1) {
833                 FD_ZERO(&readset);
834                 FD_ZERO(&writeset);
835                 prepare_select(&readset, &writeset);
836                 if (select(max_fd + 1, &readset, &writeset, NULL, NULL) < 0) {
837                         if (errno == EINTR)
838                                 continue;
839                         exit(1);
840                 }
841                 after_select(&readset, &writeset);
842         }
843         /* NOTREACHED */
844 }
This page took 0.112848 seconds and 5 git commands to generate.