"Fossies" - the Fresh Open Source Software Archive

Member "openssl-1.1.1g/crypto/bio/bss_acpt.c" (21 Apr 2020, 16395 Bytes) of package /linux/misc/openssl-1.1.1g.tar.gz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "bss_acpt.c" see the Fossies "Dox" file reference documentation and the last Fossies "Diffs" side-by-side code changes report: 1.1.1f_vs_1.1.1g.

    1 /*
    2  * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
    3  *
    4  * Licensed under the OpenSSL license (the "License").  You may not use
    5  * this file except in compliance with the License.  You can obtain a copy
    6  * in the file LICENSE in the source distribution or at
    7  * https://www.openssl.org/source/license.html
    8  */
    9 
   10 #include <stdio.h>
   11 #include <errno.h>
   12 #include "bio_local.h"
   13 
   14 #ifndef OPENSSL_NO_SOCK
   15 
   16 typedef struct bio_accept_st {
   17     int state;
   18     int accept_family;
   19     int bind_mode;     /* Socket mode for BIO_listen */
   20     int accepted_mode; /* Socket mode for BIO_accept (set on accepted sock) */
   21     char *param_addr;
   22     char *param_serv;
   23 
   24     int accept_sock;
   25 
   26     BIO_ADDRINFO *addr_first;
   27     const BIO_ADDRINFO *addr_iter;
   28     BIO_ADDR cache_accepting_addr;   /* Useful if we asked for port 0 */
   29     char *cache_accepting_name, *cache_accepting_serv;
   30     BIO_ADDR cache_peer_addr;
   31     char *cache_peer_name, *cache_peer_serv;
   32 
   33     BIO *bio_chain;
   34 } BIO_ACCEPT;
   35 
   36 static int acpt_write(BIO *h, const char *buf, int num);
   37 static int acpt_read(BIO *h, char *buf, int size);
   38 static int acpt_puts(BIO *h, const char *str);
   39 static long acpt_ctrl(BIO *h, int cmd, long arg1, void *arg2);
   40 static int acpt_new(BIO *h);
   41 static int acpt_free(BIO *data);
   42 static int acpt_state(BIO *b, BIO_ACCEPT *c);
   43 static void acpt_close_socket(BIO *data);
   44 static BIO_ACCEPT *BIO_ACCEPT_new(void);
   45 static void BIO_ACCEPT_free(BIO_ACCEPT *a);
   46 
   47 # define ACPT_S_BEFORE                   1
   48 # define ACPT_S_GET_ADDR                 2
   49 # define ACPT_S_CREATE_SOCKET            3
   50 # define ACPT_S_LISTEN                   4
   51 # define ACPT_S_ACCEPT                   5
   52 # define ACPT_S_OK                       6
   53 
   54 static const BIO_METHOD methods_acceptp = {
   55     BIO_TYPE_ACCEPT,
   56     "socket accept",
   57     /* TODO: Convert to new style write function */
   58     bwrite_conv,
   59     acpt_write,
   60     /* TODO: Convert to new style read function */
   61     bread_conv,
   62     acpt_read,
   63     acpt_puts,
   64     NULL,                       /* connect_gets,         */
   65     acpt_ctrl,
   66     acpt_new,
   67     acpt_free,
   68     NULL,                       /* connect_callback_ctrl */
   69 };
   70 
   71 const BIO_METHOD *BIO_s_accept(void)
   72 {
   73     return &methods_acceptp;
   74 }
   75 
   76 static int acpt_new(BIO *bi)
   77 {
   78     BIO_ACCEPT *ba;
   79 
   80     bi->init = 0;
   81     bi->num = (int)INVALID_SOCKET;
   82     bi->flags = 0;
   83     if ((ba = BIO_ACCEPT_new()) == NULL)
   84         return 0;
   85     bi->ptr = (char *)ba;
   86     ba->state = ACPT_S_BEFORE;
   87     bi->shutdown = 1;
   88     return 1;
   89 }
   90 
   91 static BIO_ACCEPT *BIO_ACCEPT_new(void)
   92 {
   93     BIO_ACCEPT *ret;
   94 
   95     if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL) {
   96         BIOerr(BIO_F_BIO_ACCEPT_NEW, ERR_R_MALLOC_FAILURE);
   97         return NULL;
   98     }
   99     ret->accept_family = BIO_FAMILY_IPANY;
  100     ret->accept_sock = (int)INVALID_SOCKET;
  101     return ret;
  102 }
  103 
  104 static void BIO_ACCEPT_free(BIO_ACCEPT *a)
  105 {
  106     if (a == NULL)
  107         return;
  108     OPENSSL_free(a->param_addr);
  109     OPENSSL_free(a->param_serv);
  110     BIO_ADDRINFO_free(a->addr_first);
  111     OPENSSL_free(a->cache_accepting_name);
  112     OPENSSL_free(a->cache_accepting_serv);
  113     OPENSSL_free(a->cache_peer_name);
  114     OPENSSL_free(a->cache_peer_serv);
  115     BIO_free(a->bio_chain);
  116     OPENSSL_free(a);
  117 }
  118 
  119 static void acpt_close_socket(BIO *bio)
  120 {
  121     BIO_ACCEPT *c;
  122 
  123     c = (BIO_ACCEPT *)bio->ptr;
  124     if (c->accept_sock != (int)INVALID_SOCKET) {
  125         shutdown(c->accept_sock, 2);
  126         closesocket(c->accept_sock);
  127         c->accept_sock = (int)INVALID_SOCKET;
  128         bio->num = (int)INVALID_SOCKET;
  129     }
  130 }
  131 
  132 static int acpt_free(BIO *a)
  133 {
  134     BIO_ACCEPT *data;
  135 
  136     if (a == NULL)
  137         return 0;
  138     data = (BIO_ACCEPT *)a->ptr;
  139 
  140     if (a->shutdown) {
  141         acpt_close_socket(a);
  142         BIO_ACCEPT_free(data);
  143         a->ptr = NULL;
  144         a->flags = 0;
  145         a->init = 0;
  146     }
  147     return 1;
  148 }
  149 
  150 static int acpt_state(BIO *b, BIO_ACCEPT *c)
  151 {
  152     BIO *bio = NULL, *dbio;
  153     int s = -1, ret = -1;
  154 
  155     for (;;) {
  156         switch (c->state) {
  157         case ACPT_S_BEFORE:
  158             if (c->param_addr == NULL && c->param_serv == NULL) {
  159                 BIOerr(BIO_F_ACPT_STATE, BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED);
  160                 ERR_add_error_data(4,
  161                                    "hostname=", c->param_addr,
  162                                    " service=", c->param_serv);
  163                 goto exit_loop;
  164             }
  165 
  166             /* Because we're starting a new bind, any cached name and serv
  167              * are now obsolete and need to be cleaned out.
  168              * QUESTION: should this be done in acpt_close_socket() instead?
  169              */
  170             OPENSSL_free(c->cache_accepting_name);
  171             c->cache_accepting_name = NULL;
  172             OPENSSL_free(c->cache_accepting_serv);
  173             c->cache_accepting_serv = NULL;
  174             OPENSSL_free(c->cache_peer_name);
  175             c->cache_peer_name = NULL;
  176             OPENSSL_free(c->cache_peer_serv);
  177             c->cache_peer_serv = NULL;
  178 
  179             c->state = ACPT_S_GET_ADDR;
  180             break;
  181 
  182         case ACPT_S_GET_ADDR:
  183             {
  184                 int family = AF_UNSPEC;
  185                 switch (c->accept_family) {
  186                 case BIO_FAMILY_IPV6:
  187                     if (1) { /* This is a trick we use to avoid bit rot.
  188                               * at least the "else" part will always be
  189                               * compiled.
  190                               */
  191 #ifdef AF_INET6
  192                         family = AF_INET6;
  193                     } else {
  194 #endif
  195                         BIOerr(BIO_F_ACPT_STATE, BIO_R_UNAVAILABLE_IP_FAMILY);
  196                         goto exit_loop;
  197                     }
  198                     break;
  199                 case BIO_FAMILY_IPV4:
  200                     family = AF_INET;
  201                     break;
  202                 case BIO_FAMILY_IPANY:
  203                     family = AF_UNSPEC;
  204                     break;
  205                 default:
  206                     BIOerr(BIO_F_ACPT_STATE, BIO_R_UNSUPPORTED_IP_FAMILY);
  207                     goto exit_loop;
  208                 }
  209                 if (BIO_lookup(c->param_addr, c->param_serv, BIO_LOOKUP_SERVER,
  210                                family, SOCK_STREAM, &c->addr_first) == 0)
  211                     goto exit_loop;
  212             }
  213             if (c->addr_first == NULL) {
  214                 BIOerr(BIO_F_ACPT_STATE, BIO_R_LOOKUP_RETURNED_NOTHING);
  215                 goto exit_loop;
  216             }
  217             /* We're currently not iterating, but set this as preparation
  218              * for possible future development in that regard
  219              */
  220             c->addr_iter = c->addr_first;
  221             c->state = ACPT_S_CREATE_SOCKET;
  222             break;
  223 
  224         case ACPT_S_CREATE_SOCKET:
  225             s = BIO_socket(BIO_ADDRINFO_family(c->addr_iter),
  226                            BIO_ADDRINFO_socktype(c->addr_iter),
  227                            BIO_ADDRINFO_protocol(c->addr_iter), 0);
  228             if (s == (int)INVALID_SOCKET) {
  229                 SYSerr(SYS_F_SOCKET, get_last_socket_error());
  230                 ERR_add_error_data(4,
  231                                    "hostname=", c->param_addr,
  232                                    " service=", c->param_serv);
  233                 BIOerr(BIO_F_ACPT_STATE, BIO_R_UNABLE_TO_CREATE_SOCKET);
  234                 goto exit_loop;
  235             }
  236             c->accept_sock = s;
  237             b->num = s;
  238             c->state = ACPT_S_LISTEN;
  239             s = -1;
  240             break;
  241 
  242         case ACPT_S_LISTEN:
  243             {
  244                 if (!BIO_listen(c->accept_sock,
  245                                 BIO_ADDRINFO_address(c->addr_iter),
  246                                 c->bind_mode)) {
  247                     BIO_closesocket(c->accept_sock);
  248                     goto exit_loop;
  249                 }
  250             }
  251 
  252             {
  253                 union BIO_sock_info_u info;
  254 
  255                 info.addr = &c->cache_accepting_addr;
  256                 if (!BIO_sock_info(c->accept_sock, BIO_SOCK_INFO_ADDRESS,
  257                                    &info)) {
  258                     BIO_closesocket(c->accept_sock);
  259                     goto exit_loop;
  260                 }
  261             }
  262 
  263             c->cache_accepting_name =
  264                 BIO_ADDR_hostname_string(&c->cache_accepting_addr, 1);
  265             c->cache_accepting_serv =
  266                 BIO_ADDR_service_string(&c->cache_accepting_addr, 1);
  267             c->state = ACPT_S_ACCEPT;
  268             s = -1;
  269             ret = 1;
  270             goto end;
  271 
  272         case ACPT_S_ACCEPT:
  273             if (b->next_bio != NULL) {
  274                 c->state = ACPT_S_OK;
  275                 break;
  276             }
  277             BIO_clear_retry_flags(b);
  278             b->retry_reason = 0;
  279 
  280             OPENSSL_free(c->cache_peer_name);
  281             c->cache_peer_name = NULL;
  282             OPENSSL_free(c->cache_peer_serv);
  283             c->cache_peer_serv = NULL;
  284 
  285             s = BIO_accept_ex(c->accept_sock, &c->cache_peer_addr,
  286                               c->accepted_mode);
  287 
  288             /* If the returned socket is invalid, this might still be
  289              * retryable
  290              */
  291             if (s < 0) {
  292                 if (BIO_sock_should_retry(s)) {
  293                     BIO_set_retry_special(b);
  294                     b->retry_reason = BIO_RR_ACCEPT;
  295                     goto end;
  296                 }
  297             }
  298 
  299             /* If it wasn't retryable, we fail */
  300             if (s < 0) {
  301                 ret = s;
  302                 goto exit_loop;
  303             }
  304 
  305             bio = BIO_new_socket(s, BIO_CLOSE);
  306             if (bio == NULL)
  307                 goto exit_loop;
  308 
  309             BIO_set_callback(bio, BIO_get_callback(b));
  310             BIO_set_callback_arg(bio, BIO_get_callback_arg(b));
  311 
  312             /*
  313              * If the accept BIO has an bio_chain, we dup it and put the new
  314              * socket at the end.
  315              */
  316             if (c->bio_chain != NULL) {
  317                 if ((dbio = BIO_dup_chain(c->bio_chain)) == NULL)
  318                     goto exit_loop;
  319                 if (!BIO_push(dbio, bio))
  320                     goto exit_loop;
  321                 bio = dbio;
  322             }
  323             if (BIO_push(b, bio) == NULL)
  324                 goto exit_loop;
  325 
  326             c->cache_peer_name =
  327                 BIO_ADDR_hostname_string(&c->cache_peer_addr, 1);
  328             c->cache_peer_serv =
  329                 BIO_ADDR_service_string(&c->cache_peer_addr, 1);
  330             c->state = ACPT_S_OK;
  331             bio = NULL;
  332             ret = 1;
  333             goto end;
  334 
  335         case ACPT_S_OK:
  336             if (b->next_bio == NULL) {
  337                 c->state = ACPT_S_ACCEPT;
  338                 break;
  339             }
  340             ret = 1;
  341             goto end;
  342 
  343         default:
  344             ret = 0;
  345             goto end;
  346         }
  347     }
  348 
  349   exit_loop:
  350     if (bio != NULL)
  351         BIO_free(bio);
  352     else if (s >= 0)
  353         BIO_closesocket(s);
  354   end:
  355     return ret;
  356 }
  357 
  358 static int acpt_read(BIO *b, char *out, int outl)
  359 {
  360     int ret = 0;
  361     BIO_ACCEPT *data;
  362 
  363     BIO_clear_retry_flags(b);
  364     data = (BIO_ACCEPT *)b->ptr;
  365 
  366     while (b->next_bio == NULL) {
  367         ret = acpt_state(b, data);
  368         if (ret <= 0)
  369             return ret;
  370     }
  371 
  372     ret = BIO_read(b->next_bio, out, outl);
  373     BIO_copy_next_retry(b);
  374     return ret;
  375 }
  376 
  377 static int acpt_write(BIO *b, const char *in, int inl)
  378 {
  379     int ret;
  380     BIO_ACCEPT *data;
  381 
  382     BIO_clear_retry_flags(b);
  383     data = (BIO_ACCEPT *)b->ptr;
  384 
  385     while (b->next_bio == NULL) {
  386         ret = acpt_state(b, data);
  387         if (ret <= 0)
  388             return ret;
  389     }
  390 
  391     ret = BIO_write(b->next_bio, in, inl);
  392     BIO_copy_next_retry(b);
  393     return ret;
  394 }
  395 
  396 static long acpt_ctrl(BIO *b, int cmd, long num, void *ptr)
  397 {
  398     int *ip;
  399     long ret = 1;
  400     BIO_ACCEPT *data;
  401     char **pp;
  402 
  403     data = (BIO_ACCEPT *)b->ptr;
  404 
  405     switch (cmd) {
  406     case BIO_CTRL_RESET:
  407         ret = 0;
  408         data->state = ACPT_S_BEFORE;
  409         acpt_close_socket(b);
  410         BIO_ADDRINFO_free(data->addr_first);
  411         data->addr_first = NULL;
  412         b->flags = 0;
  413         break;
  414     case BIO_C_DO_STATE_MACHINE:
  415         /* use this one to start the connection */
  416         ret = (long)acpt_state(b, data);
  417         break;
  418     case BIO_C_SET_ACCEPT:
  419         if (ptr != NULL) {
  420             if (num == 0) {
  421                 char *hold_serv = data->param_serv;
  422                 /* We affect the hostname regardless.  However, the input
  423                  * string might contain a host:service spec, so we must
  424                  * parse it, which might or might not affect the service
  425                  */
  426                 OPENSSL_free(data->param_addr);
  427                 data->param_addr = NULL;
  428                 ret = BIO_parse_hostserv(ptr,
  429                                          &data->param_addr,
  430                                          &data->param_serv,
  431                                          BIO_PARSE_PRIO_SERV);
  432                 if (hold_serv != data->param_serv)
  433                     OPENSSL_free(hold_serv);
  434                 b->init = 1;
  435             } else if (num == 1) {
  436                 OPENSSL_free(data->param_serv);
  437                 data->param_serv = BUF_strdup(ptr);
  438                 b->init = 1;
  439             } else if (num == 2) {
  440                 data->bind_mode |= BIO_SOCK_NONBLOCK;
  441             } else if (num == 3) {
  442                 BIO_free(data->bio_chain);
  443                 data->bio_chain = (BIO *)ptr;
  444             } else if (num == 4) {
  445                 data->accept_family = *(int *)ptr;
  446             }
  447         } else {
  448             if (num == 2) {
  449                 data->bind_mode &= ~BIO_SOCK_NONBLOCK;
  450             }
  451         }
  452         break;
  453     case BIO_C_SET_NBIO:
  454         if (num != 0)
  455             data->accepted_mode |= BIO_SOCK_NONBLOCK;
  456         else
  457             data->accepted_mode &= ~BIO_SOCK_NONBLOCK;
  458         break;
  459     case BIO_C_SET_FD:
  460         b->num = *((int *)ptr);
  461         data->accept_sock = b->num;
  462         data->state = ACPT_S_ACCEPT;
  463         b->shutdown = (int)num;
  464         b->init = 1;
  465         break;
  466     case BIO_C_GET_FD:
  467         if (b->init) {
  468             ip = (int *)ptr;
  469             if (ip != NULL)
  470                 *ip = data->accept_sock;
  471             ret = data->accept_sock;
  472         } else
  473             ret = -1;
  474         break;
  475     case BIO_C_GET_ACCEPT:
  476         if (b->init) {
  477             if (num == 0 && ptr != NULL) {
  478                 pp = (char **)ptr;
  479                 *pp = data->cache_accepting_name;
  480             } else if (num == 1 && ptr != NULL) {
  481                 pp = (char **)ptr;
  482                 *pp = data->cache_accepting_serv;
  483             } else if (num == 2 && ptr != NULL) {
  484                 pp = (char **)ptr;
  485                 *pp = data->cache_peer_name;
  486             } else if (num == 3 && ptr != NULL) {
  487                 pp = (char **)ptr;
  488                 *pp = data->cache_peer_serv;
  489             } else if (num == 4) {
  490                 switch (BIO_ADDRINFO_family(data->addr_iter)) {
  491 #ifdef AF_INET6
  492                 case AF_INET6:
  493                     ret = BIO_FAMILY_IPV6;
  494                     break;
  495 #endif
  496                 case AF_INET:
  497                     ret = BIO_FAMILY_IPV4;
  498                     break;
  499                 case 0:
  500                     ret = data->accept_family;
  501                     break;
  502                 default:
  503                     ret = -1;
  504                     break;
  505                 }
  506             } else
  507                 ret = -1;
  508         } else
  509             ret = -1;
  510         break;
  511     case BIO_CTRL_GET_CLOSE:
  512         ret = b->shutdown;
  513         break;
  514     case BIO_CTRL_SET_CLOSE:
  515         b->shutdown = (int)num;
  516         break;
  517     case BIO_CTRL_PENDING:
  518     case BIO_CTRL_WPENDING:
  519         ret = 0;
  520         break;
  521     case BIO_CTRL_FLUSH:
  522         break;
  523     case BIO_C_SET_BIND_MODE:
  524         data->bind_mode = (int)num;
  525         break;
  526     case BIO_C_GET_BIND_MODE:
  527         ret = (long)data->bind_mode;
  528         break;
  529     case BIO_CTRL_DUP:
  530         break;
  531     case BIO_CTRL_EOF:
  532         if (b->next_bio == NULL)
  533             ret = 0;
  534         else
  535             ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
  536         break;
  537     default:
  538         ret = 0;
  539         break;
  540     }
  541     return ret;
  542 }
  543 
  544 static int acpt_puts(BIO *bp, const char *str)
  545 {
  546     int n, ret;
  547 
  548     n = strlen(str);
  549     ret = acpt_write(bp, str, n);
  550     return ret;
  551 }
  552 
  553 BIO *BIO_new_accept(const char *str)
  554 {
  555     BIO *ret;
  556 
  557     ret = BIO_new(BIO_s_accept());
  558     if (ret == NULL)
  559         return NULL;
  560     if (BIO_set_accept_name(ret, str))
  561         return ret;
  562     BIO_free(ret);
  563     return NULL;
  564 }
  565 
  566 #endif