source: trunk/third/openssh/ssh-agent.c @ 18759

Revision 18759, 27.3 KB checked in by zacheiss, 22 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r18758, which included commits to RCS files with non-trunk default branches.
Line 
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/sys-queue.h"
38RCSID("$OpenBSD: ssh-agent.c,v 1.105 2002/10/01 20:34:12 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
58typedef enum {
59        AUTH_UNUSED,
60        AUTH_SOCKET,
61        AUTH_CONNECTION
62} sock_type;
63
64typedef struct {
65        int fd;
66        sock_type type;
67        Buffer input;
68        Buffer output;
69        Buffer request;
70} SocketEntry;
71
72u_int sockets_alloc = 0;
73SocketEntry *sockets = NULL;
74
75typedef struct identity {
76        TAILQ_ENTRY(identity) next;
77        Key *key;
78        char *comment;
79        u_int death;
80} Identity;
81
82typedef struct {
83        int nentries;
84        TAILQ_HEAD(idqueue, identity) idlist;
85} Idtab;
86
87/* private key table, one per protocol version */
88Idtab idtable[3];
89
90int max_fd = 0;
91
92/* pid of shell == parent of agent */
93pid_t parent_pid = -1;
94
95/* pathname and directory for AUTH_SOCKET */
96char socket_name[1024];
97char socket_dir[1024];
98
99/* locking */
100int locked = 0;
101char *lock_passwd = NULL;
102
103#ifdef HAVE___PROGNAME
104extern char *__progname;
105#else
106char *__progname;
107#endif
108
109static void
110close_socket(SocketEntry *e)
111{
112        close(e->fd);
113        e->fd = -1;
114        e->type = AUTH_UNUSED;
115        buffer_free(&e->input);
116        buffer_free(&e->output);
117        buffer_free(&e->request);
118}
119
120static void
121idtab_init(void)
122{
123        int i;
124
125        for (i = 0; i <=2; i++) {
126                TAILQ_INIT(&idtable[i].idlist);
127                idtable[i].nentries = 0;
128        }
129}
130
131/* return private key table for requested protocol version */
132static Idtab *
133idtab_lookup(int version)
134{
135        if (version < 1 || version > 2)
136                fatal("internal error, bad protocol version %d", version);
137        return &idtable[version];
138}
139
140static void
141free_identity(Identity *id)
142{
143        key_free(id->key);
144        xfree(id->comment);
145        xfree(id);
146}
147
148/* return matching private key for given public key */
149static Identity *
150lookup_identity(Key *key, int version)
151{
152        Identity *id;
153
154        Idtab *tab = idtab_lookup(version);
155        TAILQ_FOREACH(id, &tab->idlist, next) {
156                if (key_equal(key, id->key))
157                        return (id);
158        }
159        return (NULL);
160}
161
162/* send list of supported public keys to 'client' */
163static void
164process_request_identities(SocketEntry *e, int version)
165{
166        Idtab *tab = idtab_lookup(version);
167        Identity *id;
168        Buffer msg;
169
170        buffer_init(&msg);
171        buffer_put_char(&msg, (version == 1) ?
172            SSH_AGENT_RSA_IDENTITIES_ANSWER : SSH2_AGENT_IDENTITIES_ANSWER);
173        buffer_put_int(&msg, tab->nentries);
174        TAILQ_FOREACH(id, &tab->idlist, next) {
175                if (id->key->type == KEY_RSA1) {
176                        buffer_put_int(&msg, BN_num_bits(id->key->rsa->n));
177                        buffer_put_bignum(&msg, id->key->rsa->e);
178                        buffer_put_bignum(&msg, id->key->rsa->n);
179                } else {
180                        u_char *blob;
181                        u_int blen;
182                        key_to_blob(id->key, &blob, &blen);
183                        buffer_put_string(&msg, blob, blen);
184                        xfree(blob);
185                }
186                buffer_put_cstring(&msg, id->comment);
187        }
188        buffer_put_int(&e->output, buffer_len(&msg));
189        buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
190        buffer_free(&msg);
191}
192
193/* ssh1 only */
194static void
195process_authentication_challenge1(SocketEntry *e)
196{
197        u_char buf[32], mdbuf[16], session_id[16];
198        u_int response_type;
199        BIGNUM *challenge;
200        Identity *id;
201        int i, len;
202        Buffer msg;
203        MD5_CTX md;
204        Key *key;
205
206        buffer_init(&msg);
207        key = key_new(KEY_RSA1);
208        if ((challenge = BN_new()) == NULL)
209                fatal("process_authentication_challenge1: BN_new failed");
210
211        (void) buffer_get_int(&e->request);                     /* ignored */
212        buffer_get_bignum(&e->request, key->rsa->e);
213        buffer_get_bignum(&e->request, key->rsa->n);
214        buffer_get_bignum(&e->request, challenge);
215
216        /* Only protocol 1.1 is supported */
217        if (buffer_len(&e->request) == 0)
218                goto failure;
219        buffer_get(&e->request, session_id, 16);
220        response_type = buffer_get_int(&e->request);
221        if (response_type != 1)
222                goto failure;
223
224        id = lookup_identity(key, 1);
225        if (id != NULL) {
226                Key *private = id->key;
227                /* Decrypt the challenge using the private key. */
228                if (rsa_private_decrypt(challenge, challenge, private->rsa) <= 0)
229                        goto failure;
230
231                /* The response is MD5 of decrypted challenge plus session id. */
232                len = BN_num_bytes(challenge);
233                if (len <= 0 || len > 32) {
234                        log("process_authentication_challenge: bad challenge length %d", len);
235                        goto failure;
236                }
237                memset(buf, 0, 32);
238                BN_bn2bin(challenge, buf + 32 - len);
239                MD5_Init(&md);
240                MD5_Update(&md, buf, 32);
241                MD5_Update(&md, session_id, 16);
242                MD5_Final(mdbuf, &md);
243
244                /* Send the response. */
245                buffer_put_char(&msg, SSH_AGENT_RSA_RESPONSE);
246                for (i = 0; i < 16; i++)
247                        buffer_put_char(&msg, mdbuf[i]);
248                goto send;
249        }
250
251failure:
252        /* Unknown identity or protocol error.  Send failure. */
253        buffer_put_char(&msg, SSH_AGENT_FAILURE);
254send:
255        buffer_put_int(&e->output, buffer_len(&msg));
256        buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
257        key_free(key);
258        BN_clear_free(challenge);
259        buffer_free(&msg);
260}
261
262/* ssh2 only */
263static void
264process_sign_request2(SocketEntry *e)
265{
266        u_char *blob, *data, *signature = NULL;
267        u_int blen, dlen, slen = 0;
268        extern int datafellows;
269        int ok = -1, flags;
270        Buffer msg;
271        Key *key;
272
273        datafellows = 0;
274
275        blob = buffer_get_string(&e->request, &blen);
276        data = buffer_get_string(&e->request, &dlen);
277
278        flags = buffer_get_int(&e->request);
279        if (flags & SSH_AGENT_OLD_SIGNATURE)
280                datafellows = SSH_BUG_SIGBLOB;
281
282        key = key_from_blob(blob, blen);
283        if (key != NULL) {
284                Identity *id = lookup_identity(key, 2);
285                if (id != NULL)
286                        ok = key_sign(id->key, &signature, &slen, data, dlen);
287        }
288        key_free(key);
289        buffer_init(&msg);
290        if (ok == 0) {
291                buffer_put_char(&msg, SSH2_AGENT_SIGN_RESPONSE);
292                buffer_put_string(&msg, signature, slen);
293        } else {
294                buffer_put_char(&msg, SSH_AGENT_FAILURE);
295        }
296        buffer_put_int(&e->output, buffer_len(&msg));
297        buffer_append(&e->output, buffer_ptr(&msg),
298            buffer_len(&msg));
299        buffer_free(&msg);
300        xfree(data);
301        xfree(blob);
302        if (signature != NULL)
303                xfree(signature);
304}
305
306/* shared */
307static void
308process_remove_identity(SocketEntry *e, int version)
309{
310        u_int blen, bits;
311        int success = 0;
312        Key *key = NULL;
313        u_char *blob;
314
315        switch (version) {
316        case 1:
317                key = key_new(KEY_RSA1);
318                bits = buffer_get_int(&e->request);
319                buffer_get_bignum(&e->request, key->rsa->e);
320                buffer_get_bignum(&e->request, key->rsa->n);
321
322                if (bits != key_size(key))
323                        log("Warning: identity keysize mismatch: actual %u, announced %u",
324                            key_size(key), bits);
325                break;
326        case 2:
327                blob = buffer_get_string(&e->request, &blen);
328                key = key_from_blob(blob, blen);
329                xfree(blob);
330                break;
331        }
332        if (key != NULL) {
333                Identity *id = lookup_identity(key, version);
334                if (id != NULL) {
335                        /*
336                         * We have this key.  Free the old key.  Since we
337                         * don\'t want to leave empty slots in the middle of
338                         * the array, we actually free the key there and move
339                         * all the entries between the empty slot and the end
340                         * of the array.
341                         */
342                        Idtab *tab = idtab_lookup(version);
343                        if (tab->nentries < 1)
344                                fatal("process_remove_identity: "
345                                    "internal error: tab->nentries %d",
346                                    tab->nentries);
347                        TAILQ_REMOVE(&tab->idlist, id, next);
348                        free_identity(id);
349                        tab->nentries--;
350                        success = 1;
351                }
352                key_free(key);
353        }
354        buffer_put_int(&e->output, 1);
355        buffer_put_char(&e->output,
356            success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
357}
358
359static void
360process_remove_all_identities(SocketEntry *e, int version)
361{
362        Idtab *tab = idtab_lookup(version);
363        Identity *id;
364
365        /* Loop over all identities and clear the keys. */
366        for (id = TAILQ_FIRST(&tab->idlist); id;
367            id = TAILQ_FIRST(&tab->idlist)) {
368                TAILQ_REMOVE(&tab->idlist, id, next);
369                free_identity(id);
370        }
371
372        /* Mark that there are no identities. */
373        tab->nentries = 0;
374
375        /* Send success. */
376        buffer_put_int(&e->output, 1);
377        buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
378}
379
380static void
381reaper(void)
382{
383        u_int now = time(NULL);
384        Identity *id, *nxt;
385        int version;
386        Idtab *tab;
387
388        for (version = 1; version < 3; version++) {
389                tab = idtab_lookup(version);
390                for (id = TAILQ_FIRST(&tab->idlist); id; id = nxt) {
391                        nxt = TAILQ_NEXT(id, next);
392                        if (id->death != 0 && now >= id->death) {
393                                TAILQ_REMOVE(&tab->idlist, id, next);
394                                free_identity(id);
395                                tab->nentries--;
396                        }
397                }
398        }
399}
400
401static void
402process_add_identity(SocketEntry *e, int version)
403{
404        Idtab *tab = idtab_lookup(version);
405        int type, success = 0, death = 0;
406        char *type_name, *comment;
407        Key *k = NULL;
408
409        switch (version) {
410        case 1:
411                k = key_new_private(KEY_RSA1);
412                (void) buffer_get_int(&e->request);             /* ignored */
413                buffer_get_bignum(&e->request, k->rsa->n);
414                buffer_get_bignum(&e->request, k->rsa->e);
415                buffer_get_bignum(&e->request, k->rsa->d);
416                buffer_get_bignum(&e->request, k->rsa->iqmp);
417
418                /* SSH and SSL have p and q swapped */
419                buffer_get_bignum(&e->request, k->rsa->q);      /* p */
420                buffer_get_bignum(&e->request, k->rsa->p);      /* q */
421
422                /* Generate additional parameters */
423                rsa_generate_additional_parameters(k->rsa);
424                break;
425        case 2:
426                type_name = buffer_get_string(&e->request, NULL);
427                type = key_type_from_name(type_name);
428                xfree(type_name);
429                switch (type) {
430                case KEY_DSA:
431                        k = key_new_private(type);
432                        buffer_get_bignum2(&e->request, k->dsa->p);
433                        buffer_get_bignum2(&e->request, k->dsa->q);
434                        buffer_get_bignum2(&e->request, k->dsa->g);
435                        buffer_get_bignum2(&e->request, k->dsa->pub_key);
436                        buffer_get_bignum2(&e->request, k->dsa->priv_key);
437                        break;
438                case KEY_RSA:
439                        k = key_new_private(type);
440                        buffer_get_bignum2(&e->request, k->rsa->n);
441                        buffer_get_bignum2(&e->request, k->rsa->e);
442                        buffer_get_bignum2(&e->request, k->rsa->d);
443                        buffer_get_bignum2(&e->request, k->rsa->iqmp);
444                        buffer_get_bignum2(&e->request, k->rsa->p);
445                        buffer_get_bignum2(&e->request, k->rsa->q);
446
447                        /* Generate additional parameters */
448                        rsa_generate_additional_parameters(k->rsa);
449                        break;
450                default:
451                        buffer_clear(&e->request);
452                        goto send;
453                }
454                break;
455        }
456        comment = buffer_get_string(&e->request, NULL);
457        if (k == NULL) {
458                xfree(comment);
459                goto send;
460        }
461        success = 1;
462        while (buffer_len(&e->request)) {
463                switch (buffer_get_char(&e->request)) {
464                case SSH_AGENT_CONSTRAIN_LIFETIME:
465                        death = time(NULL) + buffer_get_int(&e->request);
466                        break;
467                default:
468                        break;
469                }
470        }
471        if (lookup_identity(k, version) == NULL) {
472                Identity *id = xmalloc(sizeof(Identity));
473                id->key = k;
474                id->comment = comment;
475                id->death = death;
476                TAILQ_INSERT_TAIL(&tab->idlist, id, next);
477                /* Increment the number of identities. */
478                tab->nentries++;
479        } else {
480                key_free(k);
481                xfree(comment);
482        }
483send:
484        buffer_put_int(&e->output, 1);
485        buffer_put_char(&e->output,
486            success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
487}
488
489/* XXX todo: encrypt sensitive data with passphrase */
490static void
491process_lock_agent(SocketEntry *e, int lock)
492{
493        int success = 0;
494        char *passwd;
495
496        passwd = buffer_get_string(&e->request, NULL);
497        if (locked && !lock && strcmp(passwd, lock_passwd) == 0) {
498                locked = 0;
499                memset(lock_passwd, 0, strlen(lock_passwd));
500                xfree(lock_passwd);
501                lock_passwd = NULL;
502                success = 1;
503        } else if (!locked && lock) {
504                locked = 1;
505                lock_passwd = xstrdup(passwd);
506                success = 1;
507        }
508        memset(passwd, 0, strlen(passwd));
509        xfree(passwd);
510
511        buffer_put_int(&e->output, 1);
512        buffer_put_char(&e->output,
513            success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
514}
515
516static void
517no_identities(SocketEntry *e, u_int type)
518{
519        Buffer msg;
520
521        buffer_init(&msg);
522        buffer_put_char(&msg,
523            (type == SSH_AGENTC_REQUEST_RSA_IDENTITIES) ?
524            SSH_AGENT_RSA_IDENTITIES_ANSWER : SSH2_AGENT_IDENTITIES_ANSWER);
525        buffer_put_int(&msg, 0);
526        buffer_put_int(&e->output, buffer_len(&msg));
527        buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
528        buffer_free(&msg);
529}
530
531#ifdef SMARTCARD
532static void
533process_add_smartcard_key (SocketEntry *e)
534{
535        char *sc_reader_id = NULL, *pin;
536        int i, version, success = 0;
537        Key **keys, *k;
538        Identity *id;
539        Idtab *tab;
540
541        sc_reader_id = buffer_get_string(&e->request, NULL);
542        pin = buffer_get_string(&e->request, NULL);
543        keys = sc_get_keys(sc_reader_id, pin);
544        xfree(sc_reader_id);
545        xfree(pin);
546
547        if (keys == NULL || keys[0] == NULL) {
548                error("sc_get_keys failed");
549                goto send;
550        }
551        for (i = 0; keys[i] != NULL; i++) {
552                k = keys[i];
553                version = k->type == KEY_RSA1 ? 1 : 2;
554                tab = idtab_lookup(version);
555                if (lookup_identity(k, version) == NULL) {
556                        id = xmalloc(sizeof(Identity));
557                        id->key = k;
558                        id->comment = xstrdup("smartcard key");
559                        id->death = 0;
560                        TAILQ_INSERT_TAIL(&tab->idlist, id, next);
561                        tab->nentries++;
562                        success = 1;
563                } else {
564                        key_free(k);
565                }
566                keys[i] = NULL;
567        }
568        xfree(keys);
569send:
570        buffer_put_int(&e->output, 1);
571        buffer_put_char(&e->output,
572            success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
573}
574
575static void
576process_remove_smartcard_key(SocketEntry *e)
577{
578        char *sc_reader_id = NULL, *pin;
579        int i, version, success = 0;
580        Key **keys, *k = NULL;
581        Identity *id;
582        Idtab *tab;
583
584        sc_reader_id = buffer_get_string(&e->request, NULL);
585        pin = buffer_get_string(&e->request, NULL);
586        keys = sc_get_keys(sc_reader_id, pin);
587        xfree(sc_reader_id);
588        xfree(pin);
589
590        if (keys == NULL || keys[0] == NULL) {
591                error("sc_get_keys failed");
592                goto send;
593        }
594        for (i = 0; keys[i] != NULL; i++) {
595                k = keys[i];
596                version = k->type == KEY_RSA1 ? 1 : 2;
597                if ((id = lookup_identity(k, version)) != NULL) {
598                        tab = idtab_lookup(version);
599                        TAILQ_REMOVE(&tab->idlist, id, next);
600                        tab->nentries--;
601                        free_identity(id);
602                        success = 1;
603                }
604                key_free(k);
605                keys[i] = NULL;
606        }
607        xfree(keys);
608send:
609        buffer_put_int(&e->output, 1);
610        buffer_put_char(&e->output,
611            success ? SSH_AGENT_SUCCESS : SSH_AGENT_FAILURE);
612}
613#endif /* SMARTCARD */
614
615/* dispatch incoming messages */
616
617static void
618process_message(SocketEntry *e)
619{
620        u_int msg_len, type;
621        u_char *cp;
622
623        /* kill dead keys */
624        reaper();
625
626        if (buffer_len(&e->input) < 5)
627                return;         /* Incomplete message. */
628        cp = buffer_ptr(&e->input);
629        msg_len = GET_32BIT(cp);
630        if (msg_len > 256 * 1024) {
631                close_socket(e);
632                return;
633        }
634        if (buffer_len(&e->input) < msg_len + 4)
635                return;
636
637        /* move the current input to e->request */
638        buffer_consume(&e->input, 4);
639        buffer_clear(&e->request);
640        buffer_append(&e->request, buffer_ptr(&e->input), msg_len);
641        buffer_consume(&e->input, msg_len);
642        type = buffer_get_char(&e->request);
643
644        /* check wheter agent is locked */
645        if (locked && type != SSH_AGENTC_UNLOCK) {
646                buffer_clear(&e->request);
647                switch (type) {
648                case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
649                case SSH2_AGENTC_REQUEST_IDENTITIES:
650                        /* send empty lists */
651                        no_identities(e, type);
652                        break;
653                default:
654                        /* send a fail message for all other request types */
655                        buffer_put_int(&e->output, 1);
656                        buffer_put_char(&e->output, SSH_AGENT_FAILURE);
657                }
658                return;
659        }
660
661        debug("type %d", type);
662        switch (type) {
663        case SSH_AGENTC_LOCK:
664        case SSH_AGENTC_UNLOCK:
665                process_lock_agent(e, type == SSH_AGENTC_LOCK);
666                break;
667        /* ssh1 */
668        case SSH_AGENTC_RSA_CHALLENGE:
669                process_authentication_challenge1(e);
670                break;
671        case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
672                process_request_identities(e, 1);
673                break;
674        case SSH_AGENTC_ADD_RSA_IDENTITY:
675        case SSH_AGENTC_ADD_RSA_ID_CONSTRAINED:
676                process_add_identity(e, 1);
677                break;
678        case SSH_AGENTC_REMOVE_RSA_IDENTITY:
679                process_remove_identity(e, 1);
680                break;
681        case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
682                process_remove_all_identities(e, 1);
683                break;
684        /* ssh2 */
685        case SSH2_AGENTC_SIGN_REQUEST:
686                process_sign_request2(e);
687                break;
688        case SSH2_AGENTC_REQUEST_IDENTITIES:
689                process_request_identities(e, 2);
690                break;
691        case SSH2_AGENTC_ADD_IDENTITY:
692        case SSH2_AGENTC_ADD_ID_CONSTRAINED:
693                process_add_identity(e, 2);
694                break;
695        case SSH2_AGENTC_REMOVE_IDENTITY:
696                process_remove_identity(e, 2);
697                break;
698        case SSH2_AGENTC_REMOVE_ALL_IDENTITIES:
699                process_remove_all_identities(e, 2);
700                break;
701#ifdef SMARTCARD
702        case SSH_AGENTC_ADD_SMARTCARD_KEY:
703                process_add_smartcard_key(e);
704                break;
705        case SSH_AGENTC_REMOVE_SMARTCARD_KEY:
706                process_remove_smartcard_key(e);
707                break;
708#endif /* SMARTCARD */
709        default:
710                /* Unknown message.  Respond with failure. */
711                error("Unknown message %d", type);
712                buffer_clear(&e->request);
713                buffer_put_int(&e->output, 1);
714                buffer_put_char(&e->output, SSH_AGENT_FAILURE);
715                break;
716        }
717}
718
719static void
720new_socket(sock_type type, int fd)
721{
722        u_int i, old_alloc;
723
724        if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
725                error("fcntl O_NONBLOCK: %s", strerror(errno));
726
727        if (fd > max_fd)
728                max_fd = fd;
729
730        for (i = 0; i < sockets_alloc; i++)
731                if (sockets[i].type == AUTH_UNUSED) {
732                        sockets[i].fd = fd;
733                        sockets[i].type = type;
734                        buffer_init(&sockets[i].input);
735                        buffer_init(&sockets[i].output);
736                        buffer_init(&sockets[i].request);
737                        return;
738                }
739        old_alloc = sockets_alloc;
740        sockets_alloc += 10;
741        if (sockets)
742                sockets = xrealloc(sockets, sockets_alloc * sizeof(sockets[0]));
743        else
744                sockets = xmalloc(sockets_alloc * sizeof(sockets[0]));
745        for (i = old_alloc; i < sockets_alloc; i++)
746                sockets[i].type = AUTH_UNUSED;
747        sockets[old_alloc].type = type;
748        sockets[old_alloc].fd = fd;
749        buffer_init(&sockets[old_alloc].input);
750        buffer_init(&sockets[old_alloc].output);
751        buffer_init(&sockets[old_alloc].request);
752}
753
754static int
755prepare_select(fd_set **fdrp, fd_set **fdwp, int *fdl, int *nallocp)
756{
757        u_int i, sz;
758        int n = 0;
759
760        for (i = 0; i < sockets_alloc; i++) {
761                switch (sockets[i].type) {
762                case AUTH_SOCKET:
763                case AUTH_CONNECTION:
764                        n = MAX(n, sockets[i].fd);
765                        break;
766                case AUTH_UNUSED:
767                        break;
768                default:
769                        fatal("Unknown socket type %d", sockets[i].type);
770                        break;
771                }
772        }
773
774        sz = howmany(n+1, NFDBITS) * sizeof(fd_mask);
775        if (*fdrp == NULL || sz > *nallocp) {
776                if (*fdrp)
777                        xfree(*fdrp);
778                if (*fdwp)
779                        xfree(*fdwp);
780                *fdrp = xmalloc(sz);
781                *fdwp = xmalloc(sz);
782                *nallocp = sz;
783        }
784        if (n < *fdl)
785                debug("XXX shrink: %d < %d", n, *fdl);
786        *fdl = n;
787        memset(*fdrp, 0, sz);
788        memset(*fdwp, 0, sz);
789
790        for (i = 0; i < sockets_alloc; i++) {
791                switch (sockets[i].type) {
792                case AUTH_SOCKET:
793                case AUTH_CONNECTION:
794                        FD_SET(sockets[i].fd, *fdrp);
795                        if (buffer_len(&sockets[i].output) > 0)
796                                FD_SET(sockets[i].fd, *fdwp);
797                        break;
798                default:
799                        break;
800                }
801        }
802        return (1);
803}
804
805static void
806after_select(fd_set *readset, fd_set *writeset)
807{
808        struct sockaddr_un sunaddr;
809        socklen_t slen;
810        char buf[1024];
811        int len, sock;
812        u_int i;
813        uid_t euid;
814        gid_t egid;
815
816        for (i = 0; i < sockets_alloc; i++)
817                switch (sockets[i].type) {
818                case AUTH_UNUSED:
819                        break;
820                case AUTH_SOCKET:
821                        if (FD_ISSET(sockets[i].fd, readset)) {
822                                slen = sizeof(sunaddr);
823                                sock = accept(sockets[i].fd,
824                                    (struct sockaddr *) &sunaddr, &slen);
825                                if (sock < 0) {
826                                        error("accept from AUTH_SOCKET: %s",
827                                            strerror(errno));
828                                        break;
829                                }
830                                if (getpeereid(sock, &euid, &egid) < 0) {
831                                        error("getpeereid %d failed: %s",
832                                            sock, strerror(errno));
833                                        close(sock);
834                                        break;
835                                }
836                                if ((euid != 0) && (getuid() != euid)) {
837                                        error("uid mismatch: "
838                                            "peer euid %u != uid %u",
839                                            (u_int) euid, (u_int) getuid());
840                                        close(sock);
841                                        break;
842                                }
843                                new_socket(AUTH_CONNECTION, sock);
844                        }
845                        break;
846                case AUTH_CONNECTION:
847                        if (buffer_len(&sockets[i].output) > 0 &&
848                            FD_ISSET(sockets[i].fd, writeset)) {
849                                do {
850                                        len = write(sockets[i].fd,
851                                            buffer_ptr(&sockets[i].output),
852                                            buffer_len(&sockets[i].output));
853                                        if (len == -1 && (errno == EAGAIN ||
854                                            errno == EINTR))
855                                                continue;
856                                        break;
857                                } while (1);
858                                if (len <= 0) {
859                                        close_socket(&sockets[i]);
860                                        break;
861                                }
862                                buffer_consume(&sockets[i].output, len);
863                        }
864                        if (FD_ISSET(sockets[i].fd, readset)) {
865                                do {
866                                        len = read(sockets[i].fd, buf, sizeof(buf));
867                                        if (len == -1 && (errno == EAGAIN ||
868                                            errno == EINTR))
869                                                continue;
870                                        break;
871                                } while (1);
872                                if (len <= 0) {
873                                        close_socket(&sockets[i]);
874                                        break;
875                                }
876                                buffer_append(&sockets[i].input, buf, len);
877                                process_message(&sockets[i]);
878                        }
879                        break;
880                default:
881                        fatal("Unknown type %d", sockets[i].type);
882                }
883}
884
885static void
886cleanup_socket(void *p)
887{
888        if (socket_name[0])
889                unlink(socket_name);
890        if (socket_dir[0])
891                rmdir(socket_dir);
892}
893
894static void
895cleanup_exit(int i)
896{
897        cleanup_socket(NULL);
898        exit(i);
899}
900
901static void
902cleanup_handler(int sig)
903{
904        cleanup_socket(NULL);
905        _exit(2);
906}
907
908static void
909check_parent_exists(int sig)
910{
911        int save_errno = errno;
912
913        if (parent_pid != -1 && kill(parent_pid, 0) < 0) {
914                /* printf("Parent has died - Authentication agent exiting.\n"); */
915                cleanup_handler(sig); /* safe */
916        }
917        signal(SIGALRM, check_parent_exists);
918        alarm(10);
919        errno = save_errno;
920}
921
922static void
923usage(void)
924{
925        fprintf(stderr, "Usage: %s [options] [command [args ...]]\n",
926            __progname);
927        fprintf(stderr, "Options:\n");
928        fprintf(stderr, "  -c          Generate C-shell commands on stdout.\n");
929        fprintf(stderr, "  -s          Generate Bourne shell commands on stdout.\n");
930        fprintf(stderr, "  -k          Kill the current agent.\n");
931        fprintf(stderr, "  -d          Debug mode.\n");
932        fprintf(stderr, "  -a socket   Bind agent socket to given name.\n");
933        exit(1);
934}
935
936int
937main(int ac, char **av)
938{
939        int sock, c_flag = 0, d_flag = 0, k_flag = 0, s_flag = 0, ch, nalloc;
940        char *shell, *format, *pidstr, *agentsocket = NULL;
941        fd_set *readsetp = NULL, *writesetp = NULL;
942        struct sockaddr_un sunaddr;
943#ifdef HAVE_SETRLIMIT
944        struct rlimit rlim;
945#endif
946#ifdef HAVE_CYGWIN
947        int prev_mask;
948#endif
949        extern int optind;
950        extern char *optarg;
951        pid_t pid;
952        char pidstrbuf[1 + 3 * sizeof pid];
953
954        /* drop */
955        setegid(getgid());
956        setgid(getgid());
957
958        SSLeay_add_all_algorithms();
959
960        __progname = get_progname(av[0]);
961        init_rng();
962        seed_rng();
963
964        while ((ch = getopt(ac, av, "cdksa:")) != -1) {
965                switch (ch) {
966                case 'c':
967                        if (s_flag)
968                                usage();
969                        c_flag++;
970                        break;
971                case 'k':
972                        k_flag++;
973                        break;
974                case 's':
975                        if (c_flag)
976                                usage();
977                        s_flag++;
978                        break;
979                case 'd':
980                        if (d_flag)
981                                usage();
982                        d_flag++;
983                        break;
984                case 'a':
985                        agentsocket = optarg;
986                        break;
987                default:
988                        usage();
989                }
990        }
991        ac -= optind;
992        av += optind;
993
994        if (ac > 0 && (c_flag || k_flag || s_flag || d_flag))
995                usage();
996
997        if (ac == 0 && !c_flag && !s_flag) {
998                shell = getenv("SHELL");
999                if (shell != NULL && strncmp(shell + strlen(shell) - 3, "csh", 3) == 0)
1000                        c_flag = 1;
1001        }
1002        if (k_flag) {
1003                pidstr = getenv(SSH_AGENTPID_ENV_NAME);
1004                if (pidstr == NULL) {
1005                        fprintf(stderr, "%s not set, cannot kill agent\n",
1006                            SSH_AGENTPID_ENV_NAME);
1007                        exit(1);
1008                }
1009                pid = atoi(pidstr);
1010                if (pid < 1) {
1011                        fprintf(stderr, "%s=\"%s\", which is not a good PID\n",
1012                            SSH_AGENTPID_ENV_NAME, pidstr);
1013                        exit(1);
1014                }
1015                if (kill(pid, SIGTERM) == -1) {
1016                        perror("kill");
1017                        exit(1);
1018                }
1019                format = c_flag ? "unsetenv %s;\n" : "unset %s;\n";
1020                printf(format, SSH_AUTHSOCKET_ENV_NAME);
1021                printf(format, SSH_AGENTPID_ENV_NAME);
1022                printf("echo Agent pid %ld killed;\n", (long)pid);
1023                exit(0);
1024        }
1025        parent_pid = getpid();
1026
1027        if (agentsocket == NULL) {
1028                /* Create private directory for agent socket */
1029                strlcpy(socket_dir, "/tmp/ssh-XXXXXXXX", sizeof socket_dir);
1030                if (mkdtemp(socket_dir) == NULL) {
1031                        perror("mkdtemp: private socket dir");
1032                        exit(1);
1033                }
1034                snprintf(socket_name, sizeof socket_name, "%s/agent.%ld", socket_dir,
1035                    (long)parent_pid);
1036        } else {
1037                /* Try to use specified agent socket */
1038                socket_dir[0] = '\0';
1039                strlcpy(socket_name, agentsocket, sizeof socket_name);
1040        }
1041
1042        /*
1043         * Create socket early so it will exist before command gets run from
1044         * the parent.
1045         */
1046        sock = socket(AF_UNIX, SOCK_STREAM, 0);
1047        if (sock < 0) {
1048                perror("socket");
1049                cleanup_exit(1);
1050        }
1051        memset(&sunaddr, 0, sizeof(sunaddr));
1052        sunaddr.sun_family = AF_UNIX;
1053        strlcpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path));
1054#ifdef HAVE_CYGWIN
1055        prev_mask = umask(0177);
1056#endif
1057        if (bind(sock, (struct sockaddr *) & sunaddr, sizeof(sunaddr)) < 0) {
1058                perror("bind");
1059#ifdef HAVE_CYGWIN
1060                umask(prev_mask);
1061#endif
1062                cleanup_exit(1);
1063        }
1064#ifdef HAVE_CYGWIN
1065        umask(prev_mask);
1066#endif
1067        if (listen(sock, 128) < 0) {
1068                perror("listen");
1069                cleanup_exit(1);
1070        }
1071
1072        /*
1073         * Fork, and have the parent execute the command, if any, or present
1074         * the socket data.  The child continues as the authentication agent.
1075         */
1076        if (d_flag) {
1077                log_init(__progname, SYSLOG_LEVEL_DEBUG1, SYSLOG_FACILITY_AUTH, 1);
1078                format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
1079                printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
1080                    SSH_AUTHSOCKET_ENV_NAME);
1081                printf("echo Agent pid %ld;\n", (long)parent_pid);
1082                goto skip;
1083        }
1084        pid = fork();
1085        if (pid == -1) {
1086                perror("fork");
1087                cleanup_exit(1);
1088        }
1089        if (pid != 0) {         /* Parent - execute the given command. */
1090                close(sock);
1091                snprintf(pidstrbuf, sizeof pidstrbuf, "%ld", (long)pid);
1092                if (ac == 0) {
1093                        format = c_flag ? "setenv %s %s;\n" : "%s=%s; export %s;\n";
1094                        printf(format, SSH_AUTHSOCKET_ENV_NAME, socket_name,
1095                            SSH_AUTHSOCKET_ENV_NAME);
1096                        printf(format, SSH_AGENTPID_ENV_NAME, pidstrbuf,
1097                            SSH_AGENTPID_ENV_NAME);
1098                        printf("echo Agent pid %ld;\n", (long)pid);
1099                        exit(0);
1100                }
1101                if (setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1) == -1 ||
1102                    setenv(SSH_AGENTPID_ENV_NAME, pidstrbuf, 1) == -1) {
1103                        perror("setenv");
1104                        exit(1);
1105                }
1106                execvp(av[0], av);
1107                perror(av[0]);
1108                exit(1);
1109        }
1110        /* child */
1111        log_init(__progname, SYSLOG_LEVEL_INFO, SYSLOG_FACILITY_AUTH, 0);
1112
1113        if (setsid() == -1) {
1114                error("setsid: %s", strerror(errno));
1115                cleanup_exit(1);
1116        }
1117
1118        (void)chdir("/");
1119        close(0);
1120        close(1);
1121        close(2);
1122
1123#ifdef HAVE_SETRLIMIT
1124        /* deny core dumps, since memory contains unencrypted private keys */
1125        rlim.rlim_cur = rlim.rlim_max = 0;
1126        if (setrlimit(RLIMIT_CORE, &rlim) < 0) {
1127                error("setrlimit RLIMIT_CORE: %s", strerror(errno));
1128                cleanup_exit(1);
1129        }
1130#endif
1131
1132skip:
1133        fatal_add_cleanup(cleanup_socket, NULL);
1134        new_socket(AUTH_SOCKET, sock);
1135        if (ac > 0) {
1136                signal(SIGALRM, check_parent_exists);
1137                alarm(10);
1138        }
1139        idtab_init();
1140        if (!d_flag)
1141                signal(SIGINT, SIG_IGN);
1142        signal(SIGPIPE, SIG_IGN);
1143        signal(SIGHUP, cleanup_handler);
1144        signal(SIGTERM, cleanup_handler);
1145        nalloc = 0;
1146
1147        while (1) {
1148                prepare_select(&readsetp, &writesetp, &max_fd, &nalloc);
1149                if (select(max_fd + 1, readsetp, writesetp, NULL, NULL) < 0) {
1150                        if (errno == EINTR)
1151                                continue;
1152                        fatal("select: %s", strerror(errno));
1153                }
1154                after_select(readsetp, writesetp);
1155        }
1156        /* NOTREACHED */
1157}
Note: See TracBrowser for help on using the repository browser.