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

Annotation of src/usr.bin/ssh/authfd.c, Revision 1.10

1.1       deraadt     1: /*
                      2:
                      3: authfd.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 01:30:28 1995 ylo
                     11:
                     12: Functions for connecting the local authentication agent.
                     13:
                     14: */
                     15:
                     16: #include "includes.h"
1.10    ! markus     17: RCSID("$Id: authfd.c,v 1.9 1999/11/15 20:53:24 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 "getput.h"
                     26:
1.2       provos     27: #include <ssl/rsa.h>
                     28:
1.1       deraadt    29: /* Returns the number of the authentication fd, or -1 if there is none. */
                     30:
1.2       provos     31: int
1.8       markus     32: ssh_get_authentication_socket()
1.1       deraadt    33: {
1.7       markus     34:   const char *authsocket;
1.1       deraadt    35:   int sock;
                     36:   struct sockaddr_un sunaddr;
                     37:
                     38:   authsocket = getenv(SSH_AUTHSOCKET_ENV_NAME);
                     39:   if (!authsocket)
                     40:     return -1;
                     41:
                     42:   sunaddr.sun_family = AF_UNIX;
1.3       deraadt    43:   strlcpy(sunaddr.sun_path, authsocket, sizeof(sunaddr.sun_path));
1.1       deraadt    44:
                     45:   sock = socket(AF_UNIX, SOCK_STREAM, 0);
                     46:   if (sock < 0)
                     47:     return -1;
1.10    ! markus     48:
        !            49:   /* close on exec */
        !            50:   if (fcntl(sock, F_SETFD, 1) == -1)
        !            51:     {
        !            52:       close(sock);
        !            53:       return -1;
        !            54:     }
1.1       deraadt    55:
1.4       deraadt    56:   if (connect(sock, (struct sockaddr *)&sunaddr, sizeof(sunaddr)) < 0)
1.1       deraadt    57:     {
                     58:       close(sock);
                     59:       return -1;
                     60:     }
                     61:
                     62:   return sock;
                     63: }
                     64:
                     65: /* Closes the agent socket if it should be closed (depends on how it was
                     66:    obtained).  The argument must have been returned by
1.8       markus     67:    ssh_get_authentication_socket(). */
1.1       deraadt    68:
                     69: void ssh_close_authentication_socket(int sock)
                     70: {
                     71:   if (getenv(SSH_AUTHSOCKET_ENV_NAME))
                     72:     close(sock);
                     73: }
                     74:
                     75: /* Opens and connects a private socket for communication with the
                     76:    authentication agent.  Returns the file descriptor (which must be
                     77:    shut down and closed by the caller when no longer needed).
                     78:    Returns NULL if an error occurred and the connection could not be
                     79:    opened. */
                     80:
                     81: AuthenticationConnection *ssh_get_authentication_connection()
                     82: {
                     83:   AuthenticationConnection *auth;
                     84:   int sock;
                     85:
1.8       markus     86:   sock = ssh_get_authentication_socket();
1.1       deraadt    87:
                     88:   /* Fail if we couldn't obtain a connection.  This happens if we exited
                     89:      due to a timeout. */
                     90:   if (sock < 0)
                     91:     return NULL;
                     92:
                     93:   /* Applocate the connection structure and initialize it. */
                     94:   auth = xmalloc(sizeof(*auth));
                     95:   auth->fd = sock;
                     96:   buffer_init(&auth->packet);
                     97:   buffer_init(&auth->identities);
                     98:   auth->howmany = 0;
                     99:
                    100:   return auth;
                    101: }
                    102:
                    103: /* Closes the connection to the authentication agent and frees any associated
                    104:    memory. */
                    105:
                    106: void ssh_close_authentication_connection(AuthenticationConnection *ac)
                    107: {
                    108:   buffer_free(&ac->packet);
                    109:   buffer_free(&ac->identities);
                    110:   close(ac->fd);
1.8       markus    111:   /* Free the connection data structure. */
                    112:   xfree(ac);
1.1       deraadt   113: }
                    114:
                    115: /* Returns the first authentication identity held by the agent.
                    116:    Returns true if an identity is available, 0 otherwise.
                    117:    The caller must initialize the integers before the call, and free the
                    118:    comment after a successful call (before calling ssh_get_next_identity). */
                    119:
1.2       provos    120: int
                    121: ssh_get_first_identity(AuthenticationConnection *auth,
1.9       markus    122:                       BIGNUM *e, BIGNUM *n, char **comment)
1.1       deraadt   123: {
                    124:   unsigned char msg[8192];
                    125:   int len, l;
                    126:
                    127:   /* Send a message to the agent requesting for a list of the identities
                    128:      it can represent. */
                    129:   msg[0] = 0;
                    130:   msg[1] = 0;
                    131:   msg[2] = 0;
                    132:   msg[3] = 1;
                    133:   msg[4] = SSH_AGENTC_REQUEST_RSA_IDENTITIES;
                    134:   if (write(auth->fd, msg, 5) != 5)
                    135:     {
                    136:       error("write auth->fd: %.100s", strerror(errno));
                    137:       return 0;
                    138:     }
                    139:
                    140:   /* Read the length of the response.  XXX implement timeouts here. */
                    141:   len = 4;
                    142:   while (len > 0)
                    143:     {
                    144:       l = read(auth->fd, msg + 4 - len, len);
                    145:       if (l <= 0)
                    146:        {
                    147:          error("read auth->fd: %.100s", strerror(errno));
                    148:          return 0;
                    149:        }
                    150:       len -= l;
                    151:     }
                    152:
                    153:   /* Extract the length, and check it for sanity.  (We cannot trust
                    154:      authentication agents). */
                    155:   len = GET_32BIT(msg);
                    156:   if (len < 1 || len > 256*1024)
                    157:     fatal("Authentication reply message too long: %d\n", len);
                    158:
                    159:   /* Read the packet itself. */
                    160:   buffer_clear(&auth->identities);
                    161:   while (len > 0)
                    162:     {
                    163:       l = len;
                    164:       if (l > sizeof(msg))
                    165:        l = sizeof(msg);
                    166:       l = read(auth->fd, msg, l);
                    167:       if (l <= 0)
                    168:        fatal("Incomplete authentication reply.");
                    169:       buffer_append(&auth->identities, (char *)msg, l);
                    170:       len -= l;
                    171:     }
                    172:
                    173:   /* Get message type, and verify that we got a proper answer. */
                    174:   buffer_get(&auth->identities, (char *)msg, 1);
                    175:   if (msg[0] != SSH_AGENT_RSA_IDENTITIES_ANSWER)
                    176:     fatal("Bad authentication reply message type: %d", msg[0]);
                    177:
                    178:   /* Get the number of entries in the response and check it for sanity. */
                    179:   auth->howmany = buffer_get_int(&auth->identities);
                    180:   if (auth->howmany > 1024)
                    181:     fatal("Too many identities in authentication reply: %d\n", auth->howmany);
                    182:
                    183:   /* Return the first entry (if any). */
1.9       markus    184:   return ssh_get_next_identity(auth, e, n, comment);
1.1       deraadt   185: }
                    186:
                    187: /* Returns the next authentication identity for the agent.  Other functions
                    188:    can be called between this and ssh_get_first_identity or two calls of this
                    189:    function.  This returns 0 if there are no more identities.  The caller
                    190:    must free comment after a successful return. */
                    191:
1.2       provos    192: int
                    193: ssh_get_next_identity(AuthenticationConnection *auth,
1.9       markus    194:                      BIGNUM *e, BIGNUM *n, char **comment)
1.1       deraadt   195: {
1.9       markus    196:   unsigned int bits;
                    197:
1.1       deraadt   198:   /* Return failure if no more entries. */
                    199:   if (auth->howmany <= 0)
                    200:     return 0;
                    201:
                    202:   /* Get the next entry from the packet.  These will abort with a fatal
                    203:      error if the packet is too short or contains corrupt data. */
1.9       markus    204:   bits = buffer_get_int(&auth->identities);
1.2       provos    205:   buffer_get_bignum(&auth->identities, e);
                    206:   buffer_get_bignum(&auth->identities, n);
1.1       deraadt   207:   *comment = buffer_get_string(&auth->identities, NULL);
                    208:
1.9       markus    209:   if (bits != BN_num_bits(n))
                    210:     error("Warning: keysize mismatch: actual %d, announced %s",
                    211:          BN_num_bits(n), bits);
                    212:
1.1       deraadt   213:   /* Decrement the number of remaining entries. */
                    214:   auth->howmany--;
                    215:
                    216:   return 1;
                    217: }
                    218:
                    219: /* Generates a random challenge, sends it to the agent, and waits for response
                    220:    from the agent.  Returns true (non-zero) if the agent gave the correct
                    221:    answer, zero otherwise.  Response type selects the style of response
                    222:    desired, with 0 corresponding to protocol version 1.0 (no longer supported)
                    223:    and 1 corresponding to protocol version 1.1. */
                    224:
1.2       provos    225: int
                    226: ssh_decrypt_challenge(AuthenticationConnection *auth,
1.9       markus    227:                      BIGNUM *e, BIGNUM *n, BIGNUM *challenge,
1.2       provos    228:                      unsigned char session_id[16],
                    229:                      unsigned int response_type,
                    230:                      unsigned char response[16])
1.1       deraadt   231: {
                    232:   Buffer buffer;
                    233:   unsigned char buf[8192];
                    234:   int len, l, i;
                    235:
                    236:   /* Response type 0 is no longer supported. */
                    237:   if (response_type == 0)
                    238:     fatal("Compatibility with ssh protocol version 1.0 no longer supported.");
                    239:
                    240:   /* Format a message to the agent. */
                    241:   buf[0] = SSH_AGENTC_RSA_CHALLENGE;
                    242:   buffer_init(&buffer);
                    243:   buffer_append(&buffer, (char *)buf, 1);
1.9       markus    244:   buffer_put_int(&buffer, BN_num_bits(n));
1.2       provos    245:   buffer_put_bignum(&buffer, e);
                    246:   buffer_put_bignum(&buffer, n);
                    247:   buffer_put_bignum(&buffer, challenge);
1.1       deraadt   248:   buffer_append(&buffer, (char *)session_id, 16);
                    249:   buffer_put_int(&buffer, response_type);
                    250:
                    251:   /* Get the length of the message, and format it in the buffer. */
                    252:   len = buffer_len(&buffer);
                    253:   PUT_32BIT(buf, len);
                    254:
                    255:   /* Send the length and then the packet to the agent. */
                    256:   if (write(auth->fd, buf, 4) != 4 ||
                    257:       write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
                    258:         buffer_len(&buffer))
                    259:     {
                    260:       error("Error writing to authentication socket.");
                    261:     error_cleanup:
                    262:       buffer_free(&buffer);
                    263:       return 0;
                    264:     }
                    265:
                    266:   /* Wait for response from the agent.  First read the length of the
                    267:      response packet. */
                    268:   len = 4;
                    269:   while (len > 0)
                    270:     {
                    271:       l = read(auth->fd, buf + 4 - len, len);
                    272:       if (l <= 0)
                    273:        {
                    274:          error("Error reading response length from authentication socket.");
                    275:          goto error_cleanup;
                    276:        }
                    277:       len -= l;
                    278:     }
                    279:
                    280:   /* Extract the length, and check it for sanity. */
                    281:   len = GET_32BIT(buf);
                    282:   if (len > 256*1024)
                    283:     fatal("Authentication response too long: %d", len);
                    284:
                    285:   /* Read the rest of the response in tothe buffer. */
                    286:   buffer_clear(&buffer);
                    287:   while (len > 0)
                    288:     {
                    289:       l = len;
                    290:       if (l > sizeof(buf))
                    291:        l = sizeof(buf);
                    292:       l = read(auth->fd, buf, l);
                    293:       if (l <= 0)
                    294:        {
                    295:          error("Error reading response from authentication socket.");
                    296:          goto error_cleanup;
                    297:        }
                    298:       buffer_append(&buffer, (char *)buf, l);
                    299:       len -= l;
                    300:     }
                    301:
                    302:   /* Get the type of the packet. */
                    303:   buffer_get(&buffer, (char *)buf, 1);
                    304:
                    305:   /* Check for agent failure message. */
                    306:   if (buf[0] == SSH_AGENT_FAILURE)
                    307:     {
                    308:       log("Agent admitted failure to authenticate using the key.");
                    309:       goto error_cleanup;
                    310:     }
                    311:
                    312:   /* Now it must be an authentication response packet. */
                    313:   if (buf[0] != SSH_AGENT_RSA_RESPONSE)
                    314:     fatal("Bad authentication response: %d", buf[0]);
                    315:
                    316:   /* Get the response from the packet.  This will abort with a fatal error
                    317:      if the packet is corrupt. */
                    318:   for (i = 0; i < 16; i++)
                    319:     response[i] = buffer_get_char(&buffer);
                    320:
                    321:   /* The buffer containing the packet is no longer needed. */
                    322:   buffer_free(&buffer);
                    323:
                    324:   /* Correct answer. */
                    325:   return 1;
                    326: }
                    327:
                    328: /* Adds an identity to the authentication server.  This call is not meant to
                    329:    be used by normal applications. */
                    330:
                    331: int ssh_add_identity(AuthenticationConnection *auth,
1.2       provos    332:                     RSA *key, const char *comment)
1.1       deraadt   333: {
                    334:   Buffer buffer;
                    335:   unsigned char buf[8192];
                    336:   int len, l, type;
                    337:
                    338:   /* Format a message to the agent. */
                    339:   buffer_init(&buffer);
                    340:   buffer_put_char(&buffer, SSH_AGENTC_ADD_RSA_IDENTITY);
1.2       provos    341:   buffer_put_int(&buffer, BN_num_bits(key->n));
                    342:   buffer_put_bignum(&buffer, key->n);
                    343:   buffer_put_bignum(&buffer, key->e);
                    344:   buffer_put_bignum(&buffer, key->d);
                    345:   /* To keep within the protocol: p < q for ssh. in SSL p > q */
                    346:   buffer_put_bignum(&buffer, key->iqmp); /* ssh key->u */
                    347:   buffer_put_bignum(&buffer, key->q); /* ssh key->p, SSL key->q */
                    348:   buffer_put_bignum(&buffer, key->p); /* ssh key->q, SSL key->p */
1.1       deraadt   349:   buffer_put_string(&buffer, comment, strlen(comment));
                    350:
                    351:   /* Get the length of the message, and format it in the buffer. */
                    352:   len = buffer_len(&buffer);
                    353:   PUT_32BIT(buf, len);
                    354:
                    355:   /* Send the length and then the packet to the agent. */
                    356:   if (write(auth->fd, buf, 4) != 4 ||
                    357:       write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
                    358:         buffer_len(&buffer))
                    359:     {
                    360:       error("Error writing to authentication socket.");
                    361:     error_cleanup:
                    362:       buffer_free(&buffer);
                    363:       return 0;
                    364:     }
                    365:
                    366:   /* Wait for response from the agent.  First read the length of the
                    367:      response packet. */
                    368:   len = 4;
                    369:   while (len > 0)
                    370:     {
                    371:       l = read(auth->fd, buf + 4 - len, len);
                    372:       if (l <= 0)
                    373:        {
                    374:          error("Error reading response length from authentication socket.");
                    375:          goto error_cleanup;
                    376:        }
                    377:       len -= l;
                    378:     }
                    379:
                    380:   /* Extract the length, and check it for sanity. */
                    381:   len = GET_32BIT(buf);
                    382:   if (len > 256*1024)
                    383:     fatal("Add identity response too long: %d", len);
                    384:
                    385:   /* Read the rest of the response in tothe buffer. */
                    386:   buffer_clear(&buffer);
                    387:   while (len > 0)
                    388:     {
                    389:       l = len;
                    390:       if (l > sizeof(buf))
                    391:        l = sizeof(buf);
                    392:       l = read(auth->fd, buf, l);
                    393:       if (l <= 0)
                    394:        {
                    395:          error("Error reading response from authentication socket.");
                    396:          goto error_cleanup;
                    397:        }
                    398:       buffer_append(&buffer, (char *)buf, l);
                    399:       len -= l;
                    400:     }
                    401:
                    402:   /* Get the type of the packet. */
                    403:   type = buffer_get_char(&buffer);
                    404:   switch (type)
                    405:     {
                    406:     case SSH_AGENT_FAILURE:
                    407:       buffer_free(&buffer);
                    408:       return 0;
                    409:     case SSH_AGENT_SUCCESS:
                    410:       buffer_free(&buffer);
                    411:       return 1;
                    412:     default:
                    413:       fatal("Bad response to add identity from authentication agent: %d",
                    414:            type);
                    415:     }
                    416:   /*NOTREACHED*/
                    417:   return 0;
                    418: }
                    419:
                    420: /* Removes an identity from the authentication server.  This call is not meant
                    421:    to be used by normal applications. */
                    422:
1.2       provos    423: int ssh_remove_identity(AuthenticationConnection *auth, RSA *key)
1.1       deraadt   424: {
                    425:   Buffer buffer;
                    426:   unsigned char buf[8192];
                    427:   int len, l, type;
                    428:
                    429:   /* Format a message to the agent. */
                    430:   buffer_init(&buffer);
                    431:   buffer_put_char(&buffer, SSH_AGENTC_REMOVE_RSA_IDENTITY);
1.2       provos    432:   buffer_put_int(&buffer, BN_num_bits(key->n));
                    433:   buffer_put_bignum(&buffer, key->e);
                    434:   buffer_put_bignum(&buffer, key->n);
1.1       deraadt   435:
                    436:   /* Get the length of the message, and format it in the buffer. */
                    437:   len = buffer_len(&buffer);
                    438:   PUT_32BIT(buf, len);
                    439:
                    440:   /* Send the length and then the packet to the agent. */
                    441:   if (write(auth->fd, buf, 4) != 4 ||
                    442:       write(auth->fd, buffer_ptr(&buffer), buffer_len(&buffer)) !=
                    443:         buffer_len(&buffer))
                    444:     {
                    445:       error("Error writing to authentication socket.");
                    446:     error_cleanup:
                    447:       buffer_free(&buffer);
                    448:       return 0;
                    449:     }
                    450:
                    451:   /* Wait for response from the agent.  First read the length of the
                    452:      response packet. */
                    453:   len = 4;
                    454:   while (len > 0)
                    455:     {
                    456:       l = read(auth->fd, buf + 4 - len, len);
                    457:       if (l <= 0)
                    458:        {
                    459:          error("Error reading response length from authentication socket.");
                    460:          goto error_cleanup;
                    461:        }
                    462:       len -= l;
                    463:     }
                    464:
                    465:   /* Extract the length, and check it for sanity. */
                    466:   len = GET_32BIT(buf);
                    467:   if (len > 256*1024)
                    468:     fatal("Remove identity response too long: %d", len);
                    469:
                    470:   /* Read the rest of the response in tothe buffer. */
                    471:   buffer_clear(&buffer);
                    472:   while (len > 0)
                    473:     {
                    474:       l = len;
                    475:       if (l > sizeof(buf))
                    476:        l = sizeof(buf);
                    477:       l = read(auth->fd, buf, l);
                    478:       if (l <= 0)
                    479:        {
                    480:          error("Error reading response from authentication socket.");
                    481:          goto error_cleanup;
                    482:        }
                    483:       buffer_append(&buffer, (char *)buf, l);
                    484:       len -= l;
                    485:     }
                    486:
                    487:   /* Get the type of the packet. */
                    488:   type = buffer_get_char(&buffer);
                    489:   switch (type)
                    490:     {
                    491:     case SSH_AGENT_FAILURE:
                    492:       buffer_free(&buffer);
                    493:       return 0;
                    494:     case SSH_AGENT_SUCCESS:
                    495:       buffer_free(&buffer);
                    496:       return 1;
                    497:     default:
                    498:       fatal("Bad response to remove identity from authentication agent: %d",
                    499:            type);
                    500:     }
                    501:   /*NOTREACHED*/
                    502:   return 0;
                    503: }
                    504:
                    505: /* Removes all identities from the agent.  This call is not meant
                    506:    to be used by normal applications. */
                    507:
                    508: int ssh_remove_all_identities(AuthenticationConnection *auth)
                    509: {
                    510:   Buffer buffer;
                    511:   unsigned char buf[8192];
                    512:   int len, l, type;
                    513:
                    514:   /* Get the length of the message, and format it in the buffer. */
                    515:   PUT_32BIT(buf, 1);
                    516:   buf[4] = SSH_AGENTC_REMOVE_ALL_RSA_IDENTITIES;
                    517:
                    518:   /* Send the length and then the packet to the agent. */
                    519:   if (write(auth->fd, buf, 5) != 5)
                    520:     {
                    521:       error("Error writing to authentication socket.");
                    522:       return 0;
                    523:     }
                    524:
                    525:   /* Wait for response from the agent.  First read the length of the
                    526:      response packet. */
                    527:   len = 4;
                    528:   while (len > 0)
                    529:     {
                    530:       l = read(auth->fd, buf + 4 - len, len);
                    531:       if (l <= 0)
                    532:        {
                    533:          error("Error reading response length from authentication socket.");
                    534:          return 0;
                    535:        }
                    536:       len -= l;
                    537:     }
                    538:
                    539:   /* Extract the length, and check it for sanity. */
                    540:   len = GET_32BIT(buf);
                    541:   if (len > 256*1024)
                    542:     fatal("Remove identity response too long: %d", len);
                    543:
                    544:   /* Read the rest of the response into the buffer. */
                    545:   buffer_init(&buffer);
                    546:   while (len > 0)
                    547:     {
                    548:       l = len;
                    549:       if (l > sizeof(buf))
                    550:        l = sizeof(buf);
                    551:       l = read(auth->fd, buf, l);
                    552:       if (l <= 0)
                    553:        {
                    554:          error("Error reading response from authentication socket.");
                    555:          buffer_free(&buffer);
                    556:          return 0;
                    557:        }
                    558:       buffer_append(&buffer, (char *)buf, l);
                    559:       len -= l;
                    560:     }
                    561:
                    562:   /* Get the type of the packet. */
                    563:   type = buffer_get_char(&buffer);
                    564:   switch (type)
                    565:     {
                    566:     case SSH_AGENT_FAILURE:
                    567:       buffer_free(&buffer);
                    568:       return 0;
                    569:     case SSH_AGENT_SUCCESS:
                    570:       buffer_free(&buffer);
                    571:       return 1;
                    572:     default:
                    573:       fatal("Bad response to remove identity from authentication agent: %d",
                    574:            type);
                    575:     }
                    576:   /*NOTREACHED*/
                    577:   return 0;
                    578: }