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 #include <string.h>
     63 
     64 #if !defined(OPENSSL_WINDOWS)
     65 #include <sys/socket.h>
     66 #include <netinet/in.h>
     67 #include <arpa/inet.h>
     68 #include <unistd.h>
     69 #else
     70 #pragma warning(push, 3)
     71 #include <winsock2.h>
     72 #include <ws2tcpip.h>
     73 #pragma warning(pop)
     74 #endif
     75 
     76 #include <openssl/buf.h>
     77 #include <openssl/err.h>
     78 #include <openssl/mem.h>
     79 
     80 #include "internal.h"
     81 
     82 
     83 enum {
     84   BIO_CONN_S_BEFORE,
     85   BIO_CONN_S_BLOCKED_CONNECT,
     86   BIO_CONN_S_OK,
     87 };
     88 
     89 typedef struct bio_connect_st {
     90   int state;
     91 
     92   char *param_hostname;
     93   char *param_port;
     94   int nbio;
     95 
     96   unsigned short port;
     97 
     98   struct sockaddr_storage them;
     99   socklen_t them_length;
    100 
    101   /* the file descriptor is kept in bio->num in order to match the socket
    102    * BIO. */
    103 
    104   /* info_callback is called when the connection is initially made
    105    * callback(BIO,state,ret);  The callback should return 'ret', state is for
    106    * compatibility with the SSL info_callback. */
    107   int (*info_callback)(const BIO *bio, int state, int ret);
    108 } BIO_CONNECT;
    109 
    110 #if !defined(OPENSSL_WINDOWS)
    111 static int closesocket(int sock) {
    112   return close(sock);
    113 }
    114 #endif
    115 
    116 /* split_host_and_port sets |*out_host| and |*out_port| to the host and port
    117  * parsed from |name|. It returns one on success or zero on error. Even when
    118  * successful, |*out_port| may be NULL on return if no port was specified. */
    119 static int split_host_and_port(char **out_host, char **out_port, const char *name) {
    120   const char *host, *port = NULL;
    121   size_t host_len = 0;
    122 
    123   *out_host = NULL;
    124   *out_port = NULL;
    125 
    126   if (name[0] == '[') {  /* bracketed IPv6 address */
    127     const char *close = strchr(name, ']');
    128     if (close == NULL) {
    129       return 0;
    130     }
    131     host = name + 1;
    132     host_len = close - host;
    133     if (close[1] == ':') {  /* [IP]:port */
    134       port = close + 2;
    135     } else if (close[1] != 0) {
    136       return 0;
    137     }
    138   } else {
    139     const char *colon = strchr(name, ':');
    140     if (colon == NULL || strchr(colon + 1, ':') != NULL) {  /* IPv6 address */
    141       host = name;
    142       host_len = strlen(name);
    143     } else {  /* host:port */
    144       host = name;
    145       host_len = colon - name;
    146       port = colon + 1;
    147     }
    148   }
    149 
    150   *out_host = BUF_strndup(host, host_len);
    151   if (*out_host == NULL) {
    152     return 0;
    153   }
    154   if (port == NULL) {
    155     *out_port = NULL;
    156     return 1;
    157   }
    158   *out_port = OPENSSL_strdup(port);
    159   if (*out_port == NULL) {
    160     OPENSSL_free(*out_host);
    161     *out_host = NULL;
    162     return 0;
    163   }
    164   return 1;
    165 }
    166 
    167 static int conn_state(BIO *bio, BIO_CONNECT *c) {
    168   int ret = -1, i;
    169   int (*cb)(const BIO *, int, int) = NULL;
    170 
    171   if (c->info_callback != NULL) {
    172     cb = c->info_callback;
    173   }
    174 
    175   for (;;) {
    176     switch (c->state) {
    177       case BIO_CONN_S_BEFORE:
    178         /* If there's a hostname and a port, assume that both are
    179          * exactly what they say. If there is only a hostname, try
    180          * (just once) to split it into a hostname and port. */
    181 
    182         if (c->param_hostname == NULL) {
    183           OPENSSL_PUT_ERROR(BIO, BIO_R_NO_HOSTNAME_SPECIFIED);
    184           goto exit_loop;
    185         }
    186 
    187         if (c->param_port == NULL) {
    188           char *host, *port;
    189           if (!split_host_and_port(&host, &port, c->param_hostname) ||
    190               port == NULL) {
    191             OPENSSL_free(host);
    192             OPENSSL_free(port);
    193             OPENSSL_PUT_ERROR(BIO, BIO_R_NO_PORT_SPECIFIED);
    194             ERR_add_error_data(2, "host=", c->param_hostname);
    195             goto exit_loop;
    196           }
    197 
    198           OPENSSL_free(c->param_port);
    199           c->param_port = port;
    200           OPENSSL_free(c->param_hostname);
    201           c->param_hostname = host;
    202         }
    203 
    204         if (!bio_ip_and_port_to_socket_and_addr(
    205                 &bio->num, &c->them, &c->them_length, c->param_hostname,
    206                 c->param_port)) {
    207           OPENSSL_PUT_ERROR(BIO, BIO_R_UNABLE_TO_CREATE_SOCKET);
    208           ERR_add_error_data(4, "host=", c->param_hostname, ":", c->param_port);
    209           goto exit_loop;
    210         }
    211 
    212         if (c->nbio) {
    213           if (!bio_socket_nbio(bio->num, 1)) {
    214             OPENSSL_PUT_ERROR(BIO, BIO_R_ERROR_SETTING_NBIO);
    215             ERR_add_error_data(4, "host=", c->param_hostname, ":",
    216                                c->param_port);
    217             goto exit_loop;
    218           }
    219         }
    220 
    221         i = 1;
    222         ret = setsockopt(bio->num, SOL_SOCKET, SO_KEEPALIVE, (char *)&i,
    223                          sizeof(i));
    224         if (ret < 0) {
    225           OPENSSL_PUT_SYSTEM_ERROR();
    226           OPENSSL_PUT_ERROR(BIO, BIO_R_KEEPALIVE);
    227           ERR_add_error_data(4, "host=", c->param_hostname, ":", c->param_port);
    228           goto exit_loop;
    229         }
    230 
    231         BIO_clear_retry_flags(bio);
    232         ret = connect(bio->num, (struct sockaddr*) &c->them, c->them_length);
    233         if (ret < 0) {
    234           if (bio_fd_should_retry(ret)) {
    235             BIO_set_flags(bio, (BIO_FLAGS_IO_SPECIAL | BIO_FLAGS_SHOULD_RETRY));
    236             c->state = BIO_CONN_S_BLOCKED_CONNECT;
    237             bio->retry_reason = BIO_RR_CONNECT;
    238           } else {
    239             OPENSSL_PUT_SYSTEM_ERROR();
    240             OPENSSL_PUT_ERROR(BIO, BIO_R_CONNECT_ERROR);
    241             ERR_add_error_data(4, "host=", c->param_hostname, ":",
    242                                c->param_port);
    243           }
    244           goto exit_loop;
    245         } else {
    246           c->state = BIO_CONN_S_OK;
    247         }
    248         break;
    249 
    250       case BIO_CONN_S_BLOCKED_CONNECT:
    251         i = bio_sock_error(bio->num);
    252         if (i) {
    253           if (bio_fd_should_retry(ret)) {
    254             BIO_set_flags(bio, (BIO_FLAGS_IO_SPECIAL | BIO_FLAGS_SHOULD_RETRY));
    255             c->state = BIO_CONN_S_BLOCKED_CONNECT;
    256             bio->retry_reason = BIO_RR_CONNECT;
    257             ret = -1;
    258           } else {
    259             BIO_clear_retry_flags(bio);
    260             OPENSSL_PUT_SYSTEM_ERROR();
    261             OPENSSL_PUT_ERROR(BIO, BIO_R_NBIO_CONNECT_ERROR);
    262             ERR_add_error_data(4, "host=", c->param_hostname, ":", c->param_port);
    263             ret = 0;
    264           }
    265           goto exit_loop;
    266         } else {
    267           c->state = BIO_CONN_S_OK;
    268         }
    269         break;
    270 
    271       case BIO_CONN_S_OK:
    272         ret = 1;
    273         goto exit_loop;
    274       default:
    275         assert(0);
    276         goto exit_loop;
    277     }
    278 
    279     if (cb != NULL) {
    280       ret = cb((BIO *)bio, c->state, ret);
    281       if (ret == 0) {
    282         goto end;
    283       }
    284     }
    285   }
    286 
    287 exit_loop:
    288   if (cb != NULL) {
    289     ret = cb((BIO *)bio, c->state, ret);
    290   }
    291 
    292 end:
    293   return ret;
    294 }
    295 
    296 static BIO_CONNECT *BIO_CONNECT_new(void) {
    297   BIO_CONNECT *ret = OPENSSL_malloc(sizeof(BIO_CONNECT));
    298 
    299   if (ret == NULL) {
    300     return NULL;
    301   }
    302   memset(ret, 0, sizeof(BIO_CONNECT));
    303 
    304   ret->state = BIO_CONN_S_BEFORE;
    305   return ret;
    306 }
    307 
    308 static void BIO_CONNECT_free(BIO_CONNECT *c) {
    309   if (c == NULL) {
    310     return;
    311   }
    312 
    313   OPENSSL_free(c->param_hostname);
    314   OPENSSL_free(c->param_port);
    315   OPENSSL_free(c);
    316 }
    317 
    318 static int conn_new(BIO *bio) {
    319   bio->init = 0;
    320   bio->num = -1;
    321   bio->flags = 0;
    322   bio->ptr = (char *)BIO_CONNECT_new();
    323   return bio->ptr != NULL;
    324 }
    325 
    326 static void conn_close_socket(BIO *bio) {
    327   BIO_CONNECT *c = (BIO_CONNECT *) bio->ptr;
    328 
    329   if (bio->num == -1) {
    330     return;
    331   }
    332 
    333   /* Only do a shutdown if things were established */
    334   if (c->state == BIO_CONN_S_OK) {
    335     shutdown(bio->num, 2);
    336   }
    337   closesocket(bio->num);
    338   bio->num = -1;
    339 }
    340 
    341 static int conn_free(BIO *bio) {
    342   if (bio == NULL) {
    343     return 0;
    344   }
    345 
    346   if (bio->shutdown) {
    347     conn_close_socket(bio);
    348   }
    349 
    350   BIO_CONNECT_free((BIO_CONNECT*) bio->ptr);
    351 
    352   return 1;
    353 }
    354 
    355 static int conn_read(BIO *bio, char *out, int out_len) {
    356   int ret = 0;
    357   BIO_CONNECT *data;
    358 
    359   data = (BIO_CONNECT *)bio->ptr;
    360   if (data->state != BIO_CONN_S_OK) {
    361     ret = conn_state(bio, data);
    362     if (ret <= 0) {
    363       return ret;
    364     }
    365   }
    366 
    367   bio_clear_socket_error();
    368   ret = recv(bio->num, out, out_len, 0);
    369   BIO_clear_retry_flags(bio);
    370   if (ret <= 0) {
    371     if (bio_fd_should_retry(ret)) {
    372       BIO_set_retry_read(bio);
    373     }
    374   }
    375 
    376   return ret;
    377 }
    378 
    379 static int conn_write(BIO *bio, const char *in, int in_len) {
    380   int ret;
    381   BIO_CONNECT *data;
    382 
    383   data = (BIO_CONNECT *)bio->ptr;
    384   if (data->state != BIO_CONN_S_OK) {
    385     ret = conn_state(bio, data);
    386     if (ret <= 0) {
    387       return ret;
    388     }
    389   }
    390 
    391   bio_clear_socket_error();
    392   ret = send(bio->num, in, in_len, 0);
    393   BIO_clear_retry_flags(bio);
    394   if (ret <= 0) {
    395     if (bio_fd_should_retry(ret)) {
    396       BIO_set_retry_write(bio);
    397     }
    398   }
    399 
    400   return ret;
    401 }
    402 
    403 static long conn_ctrl(BIO *bio, int cmd, long num, void *ptr) {
    404   int *ip;
    405   long ret = 1;
    406   BIO_CONNECT *data;
    407 
    408   data = (BIO_CONNECT *)bio->ptr;
    409 
    410   switch (cmd) {
    411     case BIO_CTRL_RESET:
    412       ret = 0;
    413       data->state = BIO_CONN_S_BEFORE;
    414       conn_close_socket(bio);
    415       bio->flags = 0;
    416       break;
    417     case BIO_C_DO_STATE_MACHINE:
    418       /* use this one to start the connection */
    419       if (data->state != BIO_CONN_S_OK) {
    420         ret = (long)conn_state(bio, data);
    421       } else {
    422         ret = 1;
    423       }
    424       break;
    425     case BIO_C_SET_CONNECT:
    426       if (ptr != NULL) {
    427         bio->init = 1;
    428         if (num == 0) {
    429           OPENSSL_free(data->param_hostname);
    430           data->param_hostname = BUF_strdup(ptr);
    431           if (data->param_hostname == NULL) {
    432             ret = 0;
    433           }
    434         } else if (num == 1) {
    435           OPENSSL_free(data->param_port);
    436           data->param_port = BUF_strdup(ptr);
    437           if (data->param_port == NULL) {
    438             ret = 0;
    439           }
    440         } else {
    441           ret = 0;
    442         }
    443       }
    444       break;
    445     case BIO_C_SET_NBIO:
    446       data->nbio = (int)num;
    447       break;
    448     case BIO_C_GET_FD:
    449       if (bio->init) {
    450         ip = (int *)ptr;
    451         if (ip != NULL) {
    452           *ip = bio->num;
    453         }
    454         ret = bio->num;
    455       } else {
    456         ret = -1;
    457       }
    458       break;
    459     case BIO_CTRL_GET_CLOSE:
    460       ret = bio->shutdown;
    461       break;
    462     case BIO_CTRL_SET_CLOSE:
    463       bio->shutdown = (int)num;
    464       break;
    465     case BIO_CTRL_PENDING:
    466     case BIO_CTRL_WPENDING:
    467       ret = 0;
    468       break;
    469     case BIO_CTRL_FLUSH:
    470       break;
    471     case BIO_CTRL_SET_CALLBACK: {
    472 #if 0 /* FIXME: Should this be used?  -- Richard Levitte */
    473 		OPENSSL_PUT_ERROR(BIO, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
    474 		ret = -1;
    475 #else
    476       ret = 0;
    477 #endif
    478     } break;
    479     case BIO_CTRL_GET_CALLBACK: {
    480       int (**fptr)(const BIO *bio, int state, int xret);
    481       fptr = (int (**)(const BIO *bio, int state, int xret))ptr;
    482       *fptr = data->info_callback;
    483     } break;
    484     default:
    485       ret = 0;
    486       break;
    487   }
    488   return (ret);
    489 }
    490 
    491 static long conn_callback_ctrl(BIO *bio, int cmd, bio_info_cb fp) {
    492   long ret = 1;
    493   BIO_CONNECT *data;
    494 
    495   data = (BIO_CONNECT *)bio->ptr;
    496 
    497   switch (cmd) {
    498     case BIO_CTRL_SET_CALLBACK: {
    499       data->info_callback = (int (*)(const struct bio_st *, int, int))fp;
    500     } break;
    501     default:
    502       ret = 0;
    503       break;
    504   }
    505   return ret;
    506 }
    507 
    508 static int conn_puts(BIO *bp, const char *str) {
    509   return conn_write(bp, str, strlen(str));
    510 }
    511 
    512 BIO *BIO_new_connect(const char *hostname) {
    513   BIO *ret;
    514 
    515   ret = BIO_new(BIO_s_connect());
    516   if (ret == NULL) {
    517     return NULL;
    518   }
    519   if (!BIO_set_conn_hostname(ret, hostname)) {
    520     BIO_free(ret);
    521     return NULL;
    522   }
    523   return ret;
    524 }
    525 
    526 static const BIO_METHOD methods_connectp = {
    527     BIO_TYPE_CONNECT, "socket connect",         conn_write, conn_read,
    528     conn_puts,        NULL /* connect_gets, */, conn_ctrl,  conn_new,
    529     conn_free,        conn_callback_ctrl,
    530 };
    531 
    532 const BIO_METHOD *BIO_s_connect(void) { return &methods_connectp; }
    533 
    534 int BIO_set_conn_hostname(BIO *bio, const char *name) {
    535   return BIO_ctrl(bio, BIO_C_SET_CONNECT, 0, (void*) name);
    536 }
    537 
    538 int BIO_set_conn_port(BIO *bio, const char *port_str) {
    539   return BIO_ctrl(bio, BIO_C_SET_CONNECT, 1, (void*) port_str);
    540 }
    541 
    542 int BIO_set_nbio(BIO *bio, int on) {
    543   return BIO_ctrl(bio, BIO_C_SET_NBIO, on, NULL);
    544 }
    545