[BACK]Return to ssh-agent.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ssh

Annotation of src/usr.bin/ssh/ssh-agent.c, Revision 1.2

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