Home | History | Annotate | Download | only in bio
      1 /* Copyright (C) 1995-1998 Eric Young (eay (at) cryptsoft.com)
      2  * All rights reserved.
      3  *
      4  * This package is an SSL implementation written
      5  * by Eric Young (eay (at) cryptsoft.com).
      6  * The implementation was written so as to conform with Netscapes SSL.
      7  *
      8  * This library is free for commercial and non-commercial use as long as
      9  * the following conditions are aheared to.  The following conditions
     10  * apply to all code found in this distribution, be it the RC4, RSA,
     11  * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
     12  * included with this distribution is covered by the same copyright terms
     13  * except that the holder is Tim Hudson (tjh (at) cryptsoft.com).
     14  *
     15  * Copyright remains Eric Young's, and as such any Copyright notices in
     16  * the code are not to be removed.
     17  * If this package is used in a product, Eric Young should be given attribution
     18  * as the author of the parts of the library used.
     19  * This can be in the form of a textual message at program startup or
     20  * in documentation (online or textual) provided with the package.
     21  *
     22  * Redistribution and use in source and binary forms, with or without
     23  * modification, are permitted provided that the following conditions
     24  * are met:
     25  * 1. Redistributions of source code must retain the copyright
     26  *    notice, this list of conditions and the following disclaimer.
     27  * 2. Redistributions in binary form must reproduce the above copyright
     28  *    notice, this list of conditions and the following disclaimer in the
     29  *    documentation and/or other materials provided with the distribution.
     30  * 3. All advertising materials mentioning features or use of this software
     31  *    must display the following acknowledgement:
     32  *    "This product includes cryptographic software written by
     33  *     Eric Young (eay (at) cryptsoft.com)"
     34  *    The word 'cryptographic' can be left out if the rouines from the library
     35  *    being used are not cryptographic related :-).
     36  * 4. If you include any Windows specific code (or a derivative thereof) from
     37  *    the apps directory (application code) you must include an acknowledgement:
     38  *    "This product includes software written by Tim Hudson (tjh (at) cryptsoft.com)"
     39  *
     40  * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
     41  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
     42  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
     43  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
     44  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
     45  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
     46  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
     47  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
     48  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     49  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     50  * SUCH DAMAGE.
     51  *
     52  * The licence and distribution terms for any publically available version or
     53  * derivative of this code cannot be changed.  i.e. this code cannot simply be
     54  * copied and put under another distribution licence
     55  * [including the GNU Public Licence.] */
     56 
     57 #include <openssl/bio.h>
     58 
     59 #include <assert.h>
     60 #include <errno.h>
     61 #include <stdio.h>
     62 
     63 #if !defined(OPENSSL_WINDOWS)
     64 #include <sys/socket.h>
     65 #include <netinet/in.h>
     66 #include <arpa/inet.h>
     67 #include <unistd.h>
     68 #endif
     69 
     70 #include <openssl/buf.h>
     71 #include <openssl/err.h>
     72 #include <openssl/mem.h>
     73 
     74 #include "internal.h"
     75 
     76 
     77 enum {
     78   BIO_CONN_S_BEFORE,
     79   BIO_CONN_S_BLOCKED_CONNECT,
     80   BIO_CONN_S_OK,
     81 };
     82 
     83 typedef struct bio_connect_st {
     84   int state;
     85 
     86   char *param_hostname;
     87   char *param_port;
     88   int nbio;
     89 
     90   uint8_t ip[4];
     91   unsigned short port;
     92 
     93   struct sockaddr_storage them;
     94   socklen_t them_length;
     95 
     96   /* the file descriptor is kept in bio->num in order to match the socket
     97    * BIO. */
     98 
     99   /* info_callback is called when the connection is initially made
    100    * callback(BIO,state,ret);  The callback should return 'ret', state is for
    101    * compatibility with the SSL info_callback. */
    102   int (*info_callback)(const BIO *bio, int state, int ret);
    103 } BIO_CONNECT;
    104 
    105 /* maybe_copy_ipv4_address sets |*ipv4| to the IPv4 address from |ss| (in
    106  * big-endian order), if |ss| contains an IPv4 socket address. */
    107 static void maybe_copy_ipv4_address(uint8_t *ipv4,
    108                                     const struct sockaddr_storage *ss) {
    109   const struct sockaddr_in *sin;
    110 
    111   if (ss->ss_family != AF_INET) {
    112     return;
    113   }
    114 
    115   sin = (const struct sockaddr_in*) ss;
    116   memcpy(ipv4, &sin->sin_addr, 4);
    117 }
    118 
    119 static int conn_state(BIO *bio, BIO_CONNECT *c) {
    120   int ret = -1, i;
    121   char *p, *q;
    122   int (*cb)(const BIO *, int, int) = NULL;
    123 
    124   if (c->info_callback != NULL) {
    125     cb = c->info_callback;
    126   }
    127 
    128   for (;;) {
    129     switch (c->state) {
    130       case BIO_CONN_S_BEFORE:
    131         p = c->param_hostname;
    132         if (p == NULL) {
    133           OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_NO_HOSTNAME_SPECIFIED);
    134           goto exit_loop;
    135         }
    136         for (; *p != 0; p++) {
    137           if (*p == ':' || *p == '/') {
    138             break;
    139           }
    140         }
    141 
    142         i = *p;
    143         if (i == ':' || i == '/') {
    144           *(p++) = 0;
    145           if (i == ':') {
    146             for (q = p; *q; q++) {
    147               if (*q == '/') {
    148                 *q = 0;
    149                 break;
    150               }
    151             }
    152             if (c->param_port != NULL) {
    153               OPENSSL_free(c->param_port);
    154             }
    155             c->param_port = BUF_strdup(p);
    156           }
    157         }
    158 
    159         if (c->param_port == NULL) {
    160           OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_NO_PORT_SPECIFIED);
    161           ERR_add_error_data(2, "host=", c->param_hostname);
    162           goto exit_loop;
    163         }
    164 
    165         if (!bio_ip_and_port_to_socket_and_addr(
    166                 &bio->num, &c->them, &c->them_length, c->param_hostname,
    167                 c->param_port)) {
    168           OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_UNABLE_TO_CREATE_SOCKET);
    169           ERR_add_error_data(4, "host=", c->param_hostname, ":", c->param_port);
    170           goto exit_loop;
    171         }
    172 
    173         memset(c->ip, 0, 4);
    174         maybe_copy_ipv4_address(c->ip, &c->them);
    175 
    176         if (c->nbio) {
    177           if (!bio_socket_nbio(bio->num, 1)) {
    178             OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_ERROR_SETTING_NBIO);
    179             ERR_add_error_data(4, "host=", c->param_hostname, ":",
    180                                c->param_port);
    181             goto exit_loop;
    182           }
    183         }
    184 
    185         i = 1;
    186         ret = setsockopt(bio->num, SOL_SOCKET, SO_KEEPALIVE, (char *)&i,
    187                          sizeof(i));
    188         if (ret < 0) {
    189           OPENSSL_PUT_SYSTEM_ERROR(setsockopt);
    190           OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_KEEPALIVE);
    191           ERR_add_error_data(4, "host=", c->param_hostname, ":", c->param_port);
    192           goto exit_loop;
    193         }
    194 
    195         BIO_clear_retry_flags(bio);
    196         ret = connect(bio->num, (struct sockaddr*) &c->them, c->them_length);
    197         if (ret < 0) {
    198           if (bio_fd_should_retry(ret)) {
    199             BIO_set_flags(bio, (BIO_FLAGS_IO_SPECIAL | BIO_FLAGS_SHOULD_RETRY));
    200             c->state = BIO_CONN_S_BLOCKED_CONNECT;
    201             bio->retry_reason = BIO_RR_CONNECT;
    202           } else {
    203             OPENSSL_PUT_SYSTEM_ERROR(connect);
    204             OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_CONNECT_ERROR);
    205             ERR_add_error_data(4, "host=", c->param_hostname, ":",
    206                                c->param_port);
    207           }
    208           goto exit_loop;
    209         } else {
    210           c->state = BIO_CONN_S_OK;
    211         }
    212         break;
    213 
    214       case BIO_CONN_S_BLOCKED_CONNECT:
    215         i = bio_sock_error(bio->num);
    216         if (i) {
    217           if (bio_fd_should_retry(ret)) {
    218             BIO_set_flags(bio, (BIO_FLAGS_IO_SPECIAL | BIO_FLAGS_SHOULD_RETRY));
    219             c->state = BIO_CONN_S_BLOCKED_CONNECT;
    220             bio->retry_reason = BIO_RR_CONNECT;
    221             ret = -1;
    222           } else {
    223             BIO_clear_retry_flags(bio);
    224             OPENSSL_PUT_SYSTEM_ERROR(connect);
    225             OPENSSL_PUT_ERROR(BIO, conn_state, BIO_R_NBIO_CONNECT_ERROR);
    226             ERR_add_error_data(4, "host=", c->param_hostname, ":", c->param_port);
    227             ret = 0;
    228           }
    229           goto exit_loop;
    230         } else {
    231           c->state = BIO_CONN_S_OK;
    232         }
    233         break;
    234 
    235       case BIO_CONN_S_OK:
    236         ret = 1;
    237         goto exit_loop;
    238       default:
    239         assert(0);
    240         goto exit_loop;
    241     }
    242 
    243     if (cb != NULL) {
    244       ret = cb((BIO *)bio, c->state, ret);
    245       if (ret == 0) {
    246         goto end;
    247       }
    248     }
    249   }
    250 
    251 exit_loop:
    252   if (cb != NULL) {
    253     ret = cb((BIO *)bio, c->state, ret);
    254   }
    255 
    256 end:
    257   return ret;
    258 }
    259 
    260 static BIO_CONNECT *BIO_CONNECT_new(void) {
    261   BIO_CONNECT *ret = OPENSSL_malloc(sizeof(BIO_CONNECT));
    262 
    263   if (ret == NULL) {
    264     return NULL;
    265   }
    266   memset(ret, 0, sizeof(BIO_CONNECT));
    267 
    268   ret->state = BIO_CONN_S_BEFORE;
    269   return ret;
    270 }
    271 
    272 static void BIO_CONNECT_free(BIO_CONNECT *c) {
    273   if (c == NULL) {
    274     return;
    275   }
    276 
    277   if (c->param_hostname != NULL) {
    278     OPENSSL_free(c->param_hostname);
    279   }
    280   if (c->param_port != NULL) {
    281     OPENSSL_free(c->param_port);
    282   }
    283   OPENSSL_free(c);
    284 }
    285 
    286 static int conn_new(BIO *bio) {
    287   bio->init = 0;
    288   bio->num = -1;
    289   bio->flags = 0;
    290   bio->ptr = (char *)BIO_CONNECT_new();
    291   return bio->ptr != NULL;
    292 }
    293 
    294 static void conn_close_socket(BIO *bio) {
    295   BIO_CONNECT *c = (BIO_CONNECT *) bio->ptr;
    296 
    297   if (bio->num == -1) {
    298     return;
    299   }
    300 
    301   /* Only do a shutdown if things were established */
    302   if (c->state == BIO_CONN_S_OK) {
    303     shutdown(bio->num, 2);
    304   }
    305   close(bio->num);
    306   bio->num = -1;
    307 }
    308 
    309 static int conn_free(BIO *bio) {
    310   if (bio == NULL) {
    311     return 0;
    312   }
    313 
    314   if (bio->shutdown) {
    315     conn_close_socket(bio);
    316   }
    317 
    318   BIO_CONNECT_free((BIO_CONNECT*) bio->ptr);
    319 
    320   return 1;
    321 }
    322 
    323 static int conn_read(BIO *bio, char *out, int out_len) {
    324   int ret = 0;
    325   BIO_CONNECT *data;
    326 
    327   data = (BIO_CONNECT *)bio->ptr;
    328   if (data->state != BIO_CONN_S_OK) {
    329     ret = conn_state(bio, data);
    330     if (ret <= 0) {
    331       return ret;
    332     }
    333   }
    334 
    335   bio_clear_socket_error();
    336   ret = recv(bio->num, out, out_len, 0);
    337   BIO_clear_retry_flags(bio);
    338   if (ret <= 0) {
    339     if (bio_fd_should_retry(ret)) {
    340       BIO_set_retry_read(bio);
    341     }
    342   }
    343 
    344   return ret;
    345 }
    346 
    347 static int conn_write(BIO *bio, const char *in, int in_len) {
    348   int ret;
    349   BIO_CONNECT *data;
    350 
    351   data = (BIO_CONNECT *)bio->ptr;
    352   if (data->state != BIO_CONN_S_OK) {
    353     ret = conn_state(bio, data);
    354     if (ret <= 0) {
    355       return ret;
    356     }
    357   }
    358 
    359   bio_clear_socket_error();
    360   ret = send(bio->num, in, in_len, 0);
    361   BIO_clear_retry_flags(bio);
    362   if (ret <= 0) {
    363     if (bio_fd_should_retry(ret)) {
    364       BIO_set_retry_write(bio);
    365     }
    366   }
    367 
    368   return ret;
    369 }
    370 
    371 static long conn_ctrl(BIO *bio, int cmd, long num, void *ptr) {
    372   int *ip;
    373   const char **pptr;
    374   long ret = 1;
    375   BIO_CONNECT *data;
    376 
    377   data = (BIO_CONNECT *)bio->ptr;
    378 
    379   switch (cmd) {
    380     case BIO_CTRL_RESET:
    381       ret = 0;
    382       data->state = BIO_CONN_S_BEFORE;
    383       conn_close_socket(bio);
    384       bio->flags = 0;
    385       break;
    386     case BIO_C_DO_STATE_MACHINE:
    387       /* use this one to start the connection */
    388       if (data->state != BIO_CONN_S_OK)
    389         ret = (long)conn_state(bio, data);
    390       else
    391         ret = 1;
    392       break;
    393     case BIO_C_GET_CONNECT:
    394       /* TODO(fork): can this be removed? (Or maybe this whole file). */
    395       if (ptr != NULL) {
    396         pptr = (const char **)ptr;
    397         if (num == 0) {
    398           *pptr = data->param_hostname;
    399         } else if (num == 1) {
    400           *pptr = data->param_port;
    401         } else if (num == 2) {
    402           *pptr = (char *) &data->ip[0];
    403         } else if (num == 3) {
    404           *((int *)ptr) = data->port;
    405         }
    406         if (!bio->init) {
    407           *pptr = "not initialized";
    408         }
    409         ret = 1;
    410       }
    411       break;
    412     case BIO_C_SET_CONNECT:
    413       if (ptr != NULL) {
    414         bio->init = 1;
    415         if (num == 0) {
    416           if (data->param_hostname != NULL) {
    417             OPENSSL_free(data->param_hostname);
    418           }
    419           data->param_hostname = BUF_strdup(ptr);
    420         } else if (num == 1) {
    421           if (data->param_port != NULL) {
    422             OPENSSL_free(data->param_port);
    423           }
    424           data->param_port = BUF_strdup(ptr);
    425         } else {
    426           ret = 0;
    427         }
    428       }
    429       break;
    430     case BIO_C_SET_NBIO:
    431       data->nbio = (int)num;
    432       break;
    433     case BIO_C_GET_FD:
    434       if (bio->init) {
    435         ip = (int *)ptr;
    436         if (ip != NULL) {
    437           *ip = bio->num;
    438         }
    439         ret = 1;
    440       } else {
    441         ret = 0;
    442       }
    443       break;
    444     case BIO_CTRL_GET_CLOSE:
    445       ret = bio->shutdown;
    446       break;
    447     case BIO_CTRL_SET_CLOSE:
    448       bio->shutdown = (int)num;
    449       break;
    450     case BIO_CTRL_PENDING:
    451     case BIO_CTRL_WPENDING:
    452       ret = 0;
    453       break;
    454     case BIO_CTRL_FLUSH:
    455       break;
    456     case BIO_CTRL_SET_CALLBACK: {
    457 #if 0 /* FIXME: Should this be used?  -- Richard Levitte */
    458 		OPENSSL_PUT_ERROR(BIO, XXX, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
    459 		ret = -1;
    460 #else
    461       ret = 0;
    462 #endif
    463     } break;
    464     case BIO_CTRL_GET_CALLBACK: {
    465       int (**fptr)(const BIO *bio, int state, int xret);
    466       fptr = (int (**)(const BIO *bio, int state, int xret))ptr;
    467       *fptr = data->info_callback;
    468     } break;
    469     default:
    470       ret = 0;
    471       break;
    472   }
    473   return (ret);
    474 }
    475 
    476 static long conn_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) {
    477   long ret = 1;
    478   BIO_CONNECT *data;
    479 
    480   data = (BIO_CONNECT *)bio->ptr;
    481 
    482   switch (cmd) {
    483     case BIO_CTRL_SET_CALLBACK: {
    484       data->info_callback = (int (*)(const struct bio_st *, int, int))fp;
    485     } break;
    486     default:
    487       ret = 0;
    488       break;
    489   }
    490   return ret;
    491 }
    492 
    493 static int conn_puts(BIO *bp, const char *str) {
    494   return conn_write(bp, str, strlen(str));
    495 }
    496 
    497 BIO *BIO_new_connect(const char *hostname) {
    498   BIO *ret;
    499 
    500   ret = BIO_new(BIO_s_connect());
    501   if (ret == NULL) {
    502     return NULL;
    503   }
    504   if (!BIO_set_conn_hostname(ret, hostname)) {
    505     BIO_free(ret);
    506     return NULL;
    507   }
    508   return ret;
    509 }
    510 
    511 static const BIO_METHOD methods_connectp = {
    512     BIO_TYPE_CONNECT, "socket connect",         conn_write, conn_read,
    513     conn_puts,        NULL /* connect_gets, */, conn_ctrl,  conn_new,
    514     conn_free,        conn_callback_ctrl,
    515 };
    516 
    517 const BIO_METHOD *BIO_s_connect(void) { return &methods_connectp; }
    518 
    519 int BIO_set_conn_hostname(BIO *bio, const char *name) {
    520   return BIO_ctrl(bio, BIO_C_SET_CONNECT, 0, (void*) name);
    521 }
    522 
    523 int BIO_set_conn_port(BIO *bio, const char *port_str) {
    524   return BIO_ctrl(bio, BIO_C_SET_CONNECT, 1, (void*) port_str);
    525 }
    526 
    527 int BIO_set_nbio(BIO *bio, int on) {
    528   return BIO_ctrl(bio, BIO_C_SET_NBIO, on, NULL);
    529 }
    530