[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.12

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"
1.12    ! markus     17: RCSID("$Id: ssh-agent.c,v 1.11 1999/10/07 22:46:32 markus Exp $");
1.1       deraadt    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 "getput.h"
                     27: #include "mpaux.h"
                     28:
1.7       deraadt    29: #include <md5.h>
                     30:
1.1       deraadt    31: typedef struct
                     32: {
                     33:   int fd;
1.12    ! markus     34:   enum { AUTH_UNUSED, AUTH_SOCKET, AUTH_CONNECTION } type;
1.1       deraadt    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.11      markus     53: /* pid of shell == parent of agent */
1.10      markus     54: int parent_pid = -1;
                     55:
                     56: /* pathname and directory for AUTH_SOCKET */
                     57: char socket_name[1024];
                     58: char socket_dir[1024];
                     59:
1.2       provos     60: void
                     61: process_request_identity(SocketEntry *e)
1.1       deraadt    62: {
                     63:   Buffer msg;
                     64:   int i;
                     65:
                     66:   buffer_init(&msg);
                     67:   buffer_put_char(&msg, SSH_AGENT_RSA_IDENTITIES_ANSWER);
                     68:   buffer_put_int(&msg, num_identities);
                     69:   for (i = 0; i < num_identities; i++)
                     70:     {
1.2       provos     71:       buffer_put_int(&msg, BN_num_bits(identities[i].key->n));
                     72:       buffer_put_bignum(&msg, identities[i].key->e);
                     73:       buffer_put_bignum(&msg, identities[i].key->n);
1.1       deraadt    74:       buffer_put_string(&msg, identities[i].comment,
                     75:                        strlen(identities[i].comment));
                     76:     }
                     77:   buffer_put_int(&e->output, buffer_len(&msg));
                     78:   buffer_append(&e->output, buffer_ptr(&msg), buffer_len(&msg));
                     79:   buffer_free(&msg);
                     80: }
                     81:
1.2       provos     82: void
                     83: process_authentication_challenge(SocketEntry *e)
1.1       deraadt    84: {
1.2       provos     85:   int i, pub_bits, len;
                     86:   BIGNUM *pub_e, *pub_n, *challenge;
1.1       deraadt    87:   Buffer msg;
1.7       deraadt    88:   MD5_CTX md;
1.1       deraadt    89:   unsigned char buf[32], mdbuf[16], session_id[16];
                     90:   unsigned int response_type;
                     91:
                     92:   buffer_init(&msg);
1.2       provos     93:   pub_e = BN_new();
                     94:   pub_n = BN_new();
                     95:   challenge = BN_new();
1.1       deraadt    96:   pub_bits = buffer_get_int(&e->input);
1.2       provos     97:   buffer_get_bignum(&e->input, pub_e);
                     98:   buffer_get_bignum(&e->input, pub_n);
                     99:   buffer_get_bignum(&e->input, challenge);
1.1       deraadt   100:   if (buffer_len(&e->input) == 0)
                    101:     {
                    102:       /* Compatibility code for old servers. */
                    103:       memset(session_id, 0, 16);
                    104:       response_type = 0;
                    105:     }
                    106:   else
                    107:     {
                    108:       /* New code. */
                    109:       buffer_get(&e->input, (char *)session_id, 16);
                    110:       response_type = buffer_get_int(&e->input);
                    111:     }
                    112:   for (i = 0; i < num_identities; i++)
1.2       provos    113:     if (pub_bits == BN_num_bits(identities[i].key->n) &&
                    114:        BN_cmp(pub_e, identities[i].key->e) == 0 &&
                    115:        BN_cmp(pub_n, identities[i].key->n) == 0)
1.1       deraadt   116:       {
                    117:        /* Decrypt the challenge using the private key. */
1.2       provos    118:        rsa_private_decrypt(challenge, challenge, identities[i].key);
1.1       deraadt   119:
                    120:        /* Compute the desired response. */
                    121:        switch (response_type)
                    122:          {
                    123:          case 0: /* As of protocol 1.0 */
                    124:            /* This response type is no longer supported. */
                    125:            log("Compatibility with ssh protocol 1.0 no longer supported.");
                    126:            buffer_put_char(&msg, SSH_AGENT_FAILURE);
                    127:            goto send;
                    128:
                    129:          case 1: /* As of protocol 1.1 */
                    130:            /* The response is MD5 of decrypted challenge plus session id. */
1.2       provos    131:            len = BN_num_bytes(challenge);
                    132:            assert(len <= 32 && len);
                    133:            memset(buf, 0, 32);
                    134:            BN_bn2bin(challenge, buf + 32 - len);
1.1       deraadt   135:            MD5Init(&md);
                    136:            MD5Update(&md, buf, 32);
                    137:            MD5Update(&md, session_id, 16);
                    138:            MD5Final(mdbuf, &md);
                    139:            break;
                    140:
                    141:          default:
                    142:            fatal("process_authentication_challenge: bad response_type %d",
                    143:                  response_type);
                    144:            break;
                    145:          }
                    146:
                    147:        /* Send the response. */
                    148:        buffer_put_char(&msg, SSH_AGENT_RSA_RESPONSE);
                    149:        for (i = 0; i < 16; i++)
                    150:          buffer_put_char(&msg, mdbuf[i]);
                    151:
                    152:        goto send;
                    153:       }
                    154:   /* Unknown identity.  Send failure. */
                    155:   buffer_put_char(&msg, SSH_AGENT_FAILURE);
                    156:  send:
                    157:   buffer_put_int(&e->output, buffer_len(&msg));
                    158:   buffer_append(&e->output, buffer_ptr(&msg),
                    159:                buffer_len(&msg));
                    160:   buffer_free(&msg);
1.2       provos    161:   BN_clear_free(pub_e);
                    162:   BN_clear_free(pub_n);
                    163:   BN_clear_free(challenge);
1.1       deraadt   164: }
                    165:
1.2       provos    166: void
                    167: process_remove_identity(SocketEntry *e)
1.1       deraadt   168: {
                    169:   unsigned int bits;
                    170:   unsigned int i;
1.2       provos    171:   BIGNUM *dummy, *n;
1.1       deraadt   172:
1.2       provos    173:   dummy = BN_new();
                    174:   n = BN_new();
1.1       deraadt   175:
                    176:   /* Get the key from the packet. */
                    177:   bits = buffer_get_int(&e->input);
1.2       provos    178:   buffer_get_bignum(&e->input, dummy);
                    179:   buffer_get_bignum(&e->input, n);
1.1       deraadt   180:
                    181:   /* Check if we have the key. */
                    182:   for (i = 0; i < num_identities; i++)
1.2       provos    183:     if (BN_cmp(identities[i].key->n, n) == 0)
1.1       deraadt   184:       {
                    185:        /* We have this key.  Free the old key.  Since we don\'t want to leave
                    186:           empty slots in the middle of the array, we actually free the
                    187:           key there and copy data from the last entry. */
1.2       provos    188:        RSA_free(identities[i].key);
1.1       deraadt   189:        xfree(identities[i].comment);
                    190:        if (i < num_identities - 1)
                    191:          identities[i] = identities[num_identities - 1];
                    192:        num_identities--;
1.2       provos    193:        BN_clear_free(dummy);
                    194:        BN_clear_free(n);
1.1       deraadt   195:
                    196:        /* Send success. */
                    197:        buffer_put_int(&e->output, 1);
                    198:        buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
                    199:        return;
                    200:       }
                    201:   /* We did not have the key. */
1.2       provos    202:   BN_clear(dummy);
                    203:   BN_clear(n);
1.1       deraadt   204:
                    205:   /* Send failure. */
                    206:   buffer_put_int(&e->output, 1);
                    207:   buffer_put_char(&e->output, SSH_AGENT_FAILURE);
                    208: }
                    209:
                    210: /* Removes all identities from the agent. */
                    211:
1.2       provos    212: void
                    213: process_remove_all_identities(SocketEntry *e)
1.1       deraadt   214: {
                    215:   unsigned int i;
                    216:
                    217:   /* Loop over all identities and clear the keys. */
                    218:   for (i = 0; i < num_identities; i++)
                    219:     {
1.2       provos    220:       RSA_free(identities[i].key);
1.1       deraadt   221:       xfree(identities[i].comment);
                    222:     }
                    223:
                    224:   /* Mark that there are no identities. */
                    225:   num_identities = 0;
                    226:
                    227:   /* Send success. */
                    228:   buffer_put_int(&e->output, 1);
                    229:   buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
                    230:   return;
                    231: }
                    232:
                    233: /* Adds an identity to the agent. */
                    234:
1.2       provos    235: void
                    236: process_add_identity(SocketEntry *e)
1.1       deraadt   237: {
1.2       provos    238:   RSA *k;
1.1       deraadt   239:   int i;
1.2       provos    240:   BIGNUM *aux;
                    241:   BN_CTX *ctx;
                    242:
1.1       deraadt   243:   if (num_identities == 0)
                    244:     identities = xmalloc(sizeof(Identity));
                    245:   else
                    246:     identities = xrealloc(identities, (num_identities + 1) * sizeof(Identity));
1.2       provos    247:
                    248:   identities[num_identities].key = RSA_new();
                    249:   k = identities[num_identities].key;
                    250:   buffer_get_int(&e->input); /* bits */
                    251:   k->n = BN_new();
                    252:   buffer_get_bignum(&e->input, k->n);
                    253:   k->e = BN_new();
                    254:   buffer_get_bignum(&e->input, k->e);
                    255:   k->d = BN_new();
                    256:   buffer_get_bignum(&e->input, k->d);
                    257:   k->iqmp = BN_new();
                    258:   buffer_get_bignum(&e->input, k->iqmp);
                    259:   /* SSH and SSL have p and q swapped */
                    260:   k->q = BN_new();
                    261:   buffer_get_bignum(&e->input, k->q); /* p */
                    262:   k->p = BN_new();
                    263:   buffer_get_bignum(&e->input, k->p); /* q */
                    264:
                    265:   /* Generate additional parameters */
                    266:   aux = BN_new();
                    267:   ctx = BN_CTX_new();
                    268:
                    269:   BN_sub(aux, k->q, BN_value_one());
                    270:   k->dmq1 = BN_new();
                    271:   BN_mod(k->dmq1, k->d, aux, ctx);
                    272:
                    273:   BN_sub(aux, k->p, BN_value_one());
                    274:   k->dmp1 = BN_new();
                    275:   BN_mod(k->dmp1, k->d, aux, ctx);
                    276:
                    277:   BN_clear_free(aux);
                    278:   BN_CTX_free(ctx);
                    279:
1.1       deraadt   280:   identities[num_identities].comment = buffer_get_string(&e->input, NULL);
                    281:
                    282:   /* Check if we already have the key. */
                    283:   for (i = 0; i < num_identities; i++)
1.2       provos    284:     if (BN_cmp(identities[i].key->n, k->n) == 0)
1.1       deraadt   285:       {
                    286:        /* We already have this key.  Clear and free the new data and
                    287:           return success. */
1.2       provos    288:        RSA_free(k);
1.1       deraadt   289:        xfree(identities[num_identities].comment);
                    290:
                    291:        /* Send success. */
                    292:        buffer_put_int(&e->output, 1);
                    293:        buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
                    294:        return;
                    295:       }
                    296:
                    297:   /* Increment the number of identities. */
                    298:   num_identities++;
                    299:
                    300:   /* Send a success message. */
                    301:   buffer_put_int(&e->output, 1);
                    302:   buffer_put_char(&e->output, SSH_AGENT_SUCCESS);
                    303: }
                    304:
1.2       provos    305: void
                    306: process_message(SocketEntry *e)
1.1       deraadt   307: {
                    308:   unsigned int msg_len;
                    309:   unsigned int type;
                    310:   unsigned char *cp;
                    311:   if (buffer_len(&e->input) < 5)
                    312:     return; /* Incomplete message. */
                    313:   cp = (unsigned char *)buffer_ptr(&e->input);
                    314:   msg_len = GET_32BIT(cp);
                    315:   if (msg_len > 256 * 1024)
                    316:     {
1.8       deraadt   317:       shutdown(e->fd, SHUT_RDWR);
1.1       deraadt   318:       close(e->fd);
                    319:       e->type = AUTH_UNUSED;
                    320:       return;
                    321:     }
                    322:   if (buffer_len(&e->input) < msg_len + 4)
                    323:     return;
                    324:   buffer_consume(&e->input, 4);
                    325:   type = buffer_get_char(&e->input);
1.12    ! markus    326:
1.1       deraadt   327:   switch (type)
                    328:     {
                    329:     case SSH_AGENTC_REQUEST_RSA_IDENTITIES:
                    330:       process_request_identity(e);
                    331:       break;
                    332:     case SSH_AGENTC_RSA_CHALLENGE:
                    333:       process_authentication_challenge(e);
                    334:       break;
                    335:     case SSH_AGENTC_ADD_RSA_IDENTITY:
                    336:       process_add_identity(e);
                    337:       break;
                    338:     case SSH_AGENTC_REMOVE_RSA_IDENTITY:
                    339:       process_remove_identity(e);
                    340:       break;
                    341:     case SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES:
                    342:       process_remove_all_identities(e);
                    343:       break;
                    344:     default:
                    345:       /* Unknown message.  Respond with failure. */
                    346:       error("Unknown message %d", type);
                    347:       buffer_clear(&e->input);
                    348:       buffer_put_int(&e->output, 1);
                    349:       buffer_put_char(&e->output, SSH_AGENT_FAILURE);
                    350:       break;
                    351:     }
                    352: }
                    353:
1.2       provos    354: void
                    355: new_socket(int type, int fd)
1.1       deraadt   356: {
                    357:   unsigned int i, old_alloc;
                    358:   if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
                    359:     error("fcntl O_NONBLOCK: %s", strerror(errno));
                    360:
                    361:   if (fd > max_fd)
                    362:     max_fd = fd;
                    363:
                    364:   for (i = 0; i < sockets_alloc; i++)
                    365:     if (sockets[i].type == AUTH_UNUSED)
                    366:       {
                    367:        sockets[i].fd = fd;
                    368:        sockets[i].type = type;
                    369:        buffer_init(&sockets[i].input);
                    370:        buffer_init(&sockets[i].output);
                    371:        return;
                    372:       }
                    373:   old_alloc = sockets_alloc;
                    374:   sockets_alloc += 10;
                    375:   if (sockets)
                    376:     sockets = xrealloc(sockets, sockets_alloc * sizeof(sockets[0]));
                    377:   else
                    378:     sockets = xmalloc(sockets_alloc * sizeof(sockets[0]));
                    379:   for (i = old_alloc; i < sockets_alloc; i++)
                    380:     sockets[i].type = AUTH_UNUSED;
                    381:   sockets[old_alloc].type = type;
                    382:   sockets[old_alloc].fd = fd;
                    383:   buffer_init(&sockets[old_alloc].input);
                    384:   buffer_init(&sockets[old_alloc].output);
                    385: }
                    386:
1.2       provos    387: void
                    388: prepare_select(fd_set *readset, fd_set *writeset)
1.1       deraadt   389: {
                    390:   unsigned int i;
                    391:   for (i = 0; i < sockets_alloc; i++)
                    392:     switch (sockets[i].type)
                    393:       {
1.12    ! markus    394:       case AUTH_SOCKET:
1.1       deraadt   395:       case AUTH_CONNECTION:
                    396:        FD_SET(sockets[i].fd, readset);
                    397:        if (buffer_len(&sockets[i].output) > 0)
                    398:          FD_SET(sockets[i].fd, writeset);
                    399:        break;
                    400:       case AUTH_UNUSED:
                    401:        break;
                    402:       default:
                    403:        fatal("Unknown socket type %d", sockets[i].type);
                    404:        break;
                    405:       }
                    406: }
                    407:
                    408: void after_select(fd_set *readset, fd_set *writeset)
                    409: {
                    410:   unsigned int i;
1.12    ! markus    411:   int len, sock;
1.1       deraadt   412:   char buf[1024];
                    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_SOCKET:
                    421:        if (FD_ISSET(sockets[i].fd, readset))
                    422:          {
                    423:            len = sizeof(sunaddr);
                    424:            sock = accept(sockets[i].fd, (struct sockaddr *)&sunaddr, &len);
                    425:            if (sock < 0)
                    426:              {
                    427:                perror("accept from AUTH_SOCKET");
                    428:                break;
                    429:              }
1.12    ! markus    430:            new_socket(AUTH_CONNECTION, sock);
1.1       deraadt   431:          }
                    432:        break;
                    433:       case AUTH_CONNECTION:
                    434:        if (buffer_len(&sockets[i].output) > 0 &&
                    435:            FD_ISSET(sockets[i].fd, writeset))
                    436:          {
                    437:            len = write(sockets[i].fd, buffer_ptr(&sockets[i].output),
                    438:                        buffer_len(&sockets[i].output));
                    439:            if (len <= 0)
                    440:              {
1.8       deraadt   441:                shutdown(sockets[i].fd, SHUT_RDWR);
1.1       deraadt   442:                close(sockets[i].fd);
                    443:                sockets[i].type = AUTH_UNUSED;
                    444:                break;
                    445:              }
                    446:            buffer_consume(&sockets[i].output, len);
                    447:          }
                    448:        if (FD_ISSET(sockets[i].fd, readset))
                    449:          {
                    450:            len = read(sockets[i].fd, buf, sizeof(buf));
                    451:            if (len <= 0)
                    452:              {
1.8       deraadt   453:                shutdown(sockets[i].fd, SHUT_RDWR);
1.1       deraadt   454:                close(sockets[i].fd);
                    455:                sockets[i].type = AUTH_UNUSED;
                    456:                break;
                    457:              }
                    458:            buffer_append(&sockets[i].input, buf, len);
                    459:            process_message(&sockets[i]);
                    460:          }
                    461:        break;
                    462:       default:
                    463:        fatal("Unknown type %d", sockets[i].type);
                    464:       }
                    465: }
                    466:
1.6       deraadt   467: void
1.2       provos    468: check_parent_exists(int sig)
1.1       deraadt   469: {
                    470:   if (kill(parent_pid, 0) < 0)
                    471:     {
                    472:       /* printf("Parent has died - Authentication agent exiting.\n"); */
                    473:       exit(1);
                    474:     }
                    475:   signal(SIGALRM, check_parent_exists);
                    476:   alarm(10);
                    477: }
                    478:
1.10      markus    479: void cleanup_socket(void) {
                    480:   remove(socket_name);
                    481:   rmdir(socket_dir);
                    482: }
                    483:
1.2       provos    484: int
                    485: main(int ac, char **av)
1.1       deraadt   486: {
                    487:   fd_set readset, writeset;
                    488:   int sock;
                    489:   struct sockaddr_un sunaddr;
                    490:
1.3       deraadt   491:   /* check if RSA support exists */
                    492:   if (rsa_alive() == 0) {
                    493:     extern char *__progname;
                    494:     fprintf(stderr,
                    495:       "%s: no RSA support in libssl and libcrypto.  See ssl(8).\n",
                    496:       __progname);
                    497:     exit(1);
                    498:   }
1.1       deraadt   499:
                    500:   if (ac < 2)
                    501:     {
                    502:       fprintf(stderr, "ssh-agent version %s\n", SSH_VERSION);
                    503:       fprintf(stderr, "Usage: %s command\n", av[0]);
                    504:       exit(1);
                    505:     }
                    506:
1.9       markus    507:   parent_pid = getpid();
1.10      markus    508:
                    509:   /* Create private directory for agent socket */
                    510:   strlcpy(socket_dir, "/tmp/ssh-XXXXXXXX", sizeof socket_dir);
                    511:   if (mkdtemp(socket_dir) == NULL) {
                    512:       perror("mkdtemp: private socket dir");
                    513:       exit(1);
                    514:   }
                    515:   snprintf(socket_name, sizeof socket_name, "%s/agent.%d", socket_dir, parent_pid);
1.9       markus    516:
                    517:   /* Fork, and have the parent execute the command.  The child continues as
                    518:      the authentication agent. */
                    519:   if (fork() != 0)
                    520:     { /* Parent - execute the given command. */
1.12    ! markus    521:       setenv(SSH_AUTHSOCKET_ENV_NAME, socket_name, 1);
1.9       markus    522:       execvp(av[1], av + 1);
                    523:       perror(av[1]);
                    524:       exit(1);
                    525:     }
1.10      markus    526:
                    527:   if (atexit(cleanup_socket) < 0) {
                    528:        perror("atexit");
                    529:        cleanup_socket();
                    530:        exit(1);
                    531:   }
                    532:
1.9       markus    533:   sock = socket(AF_UNIX, SOCK_STREAM, 0);
                    534:   if (sock < 0)
1.1       deraadt   535:     {
1.9       markus    536:       perror("socket");
                    537:       exit(1);
                    538:     }
                    539:   memset(&sunaddr, 0, sizeof(sunaddr));
                    540:   sunaddr.sun_family = AF_UNIX;
                    541:   strlcpy(sunaddr.sun_path, socket_name, sizeof(sunaddr.sun_path));
                    542:   if (bind(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0)
                    543:     {
                    544:       perror("bind");
                    545:       exit(1);
                    546:     }
                    547:   if (listen(sock, 5) < 0)
                    548:     {
                    549:       perror("listen");
                    550:       exit(1);
1.1       deraadt   551:     }
1.9       markus    552:   new_socket(AUTH_SOCKET, sock);
                    553:   signal(SIGALRM, check_parent_exists);
                    554:   alarm(10);
1.1       deraadt   555:
                    556:   signal(SIGINT, SIG_IGN);
                    557:   while (1)
                    558:     {
                    559:       FD_ZERO(&readset);
                    560:       FD_ZERO(&writeset);
                    561:       prepare_select(&readset, &writeset);
                    562:       if (select(max_fd + 1, &readset, &writeset, NULL, NULL) < 0)
                    563:        {
                    564:          if (errno == EINTR)
                    565:            continue;
                    566:          perror("select");
                    567:          exit(1);
                    568:        }
                    569:       after_select(&readset, &writeset);
                    570:     }
                    571:   /*NOTREACHED*/
                    572: }