BIO acpt_state(): Allow retrying addresses (e.g., using IPv6 vs. IPv4) on creating...
[openssl.git] / crypto / bio / bss_acpt.c
index 70168ecd596a49c6de9aa5ad7f18151fd38bdc94..834c2ffef1a6df780e67b1f876b91edc1c84ffa6 100644 (file)
@@ -1,63 +1,17 @@
-/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
- * All rights reserved.
+/*
+ * Copyright 1995-2020 The OpenSSL Project Authors. All Rights Reserved.
  *
- * This package is an SSL implementation written
- * by Eric Young (eay@cryptsoft.com).
- * The implementation was written so as to conform with Netscapes SSL.
- *
- * This library is free for commercial and non-commercial use as long as
- * the following conditions are aheared to.  The following conditions
- * apply to all code found in this distribution, be it the RC4, RSA,
- * lhash, DES, etc., code; not just the SSL code.  The SSL documentation
- * included with this distribution is covered by the same copyright terms
- * except that the holder is Tim Hudson (tjh@cryptsoft.com).
- *
- * Copyright remains Eric Young's, and as such any Copyright notices in
- * the code are not to be removed.
- * If this package is used in a product, Eric Young should be given attribution
- * as the author of the parts of the library used.
- * This can be in the form of a textual message at program startup or
- * in documentation (online or textual) provided with the package.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- *    must display the following acknowledgement:
- *    "This product includes cryptographic software written by
- *     Eric Young (eay@cryptsoft.com)"
- *    The word 'cryptographic' can be left out if the rouines from the library
- *    being used are not cryptographic related :-).
- * 4. If you include any Windows specific code (or a derivative thereof) from
- *    the apps directory (application code) you must include an acknowledgement:
- *    "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
- *
- * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- *
- * The licence and distribution terms for any publically available version or
- * derivative of this code cannot be changed.  i.e. this code cannot simply be
- * copied and put under another distribution licence
- * [including the GNU Public Licence.]
+ * Licensed under the Apache License 2.0 (the "License").  You may not use
+ * this file except in compliance with the License.  You can obtain a copy
+ * in the file LICENSE in the source distribution or at
+ * https://www.openssl.org/source/license.html
  */
 
+#define OPENSSL_SUPPRESS_DEPRECATED
+
 #include <stdio.h>
 #include <errno.h>
-#include "bio_lcl.h"
+#include "bio_local.h"
 
 #ifndef OPENSSL_NO_SOCK
 
@@ -102,19 +56,23 @@ static void BIO_ACCEPT_free(BIO_ACCEPT *a);
 static const BIO_METHOD methods_acceptp = {
     BIO_TYPE_ACCEPT,
     "socket accept",
+    /* TODO: Convert to new style write function */
+    bwrite_conv,
     acpt_write,
+    /* TODO: Convert to new style read function */
+    bread_conv,
     acpt_read,
     acpt_puts,
-    NULL,                       /* connect_gets, */
+    NULL,                       /* connect_gets,         */
     acpt_ctrl,
     acpt_new,
     acpt_free,
-    NULL,
+    NULL,                       /* connect_callback_ctrl */
 };
 
 const BIO_METHOD *BIO_s_accept(void)
 {
-    return (&methods_acceptp);
+    return &methods_acceptp;
 }
 
 static int acpt_new(BIO *bi)
@@ -125,29 +83,30 @@ static int acpt_new(BIO *bi)
     bi->num = (int)INVALID_SOCKET;
     bi->flags = 0;
     if ((ba = BIO_ACCEPT_new()) == NULL)
-        return (0);
+        return 0;
     bi->ptr = (char *)ba;
     ba->state = ACPT_S_BEFORE;
     bi->shutdown = 1;
-    return (1);
+    return 1;
 }
 
 static BIO_ACCEPT *BIO_ACCEPT_new(void)
 {
     BIO_ACCEPT *ret;
 
-    if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL)
-        return (NULL);
+    if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL) {
+        ERR_raise(ERR_LIB_BIO, ERR_R_MALLOC_FAILURE);
+        return NULL;
+    }
     ret->accept_family = BIO_FAMILY_IPANY;
     ret->accept_sock = (int)INVALID_SOCKET;
-    return (ret);
+    return ret;
 }
 
 static void BIO_ACCEPT_free(BIO_ACCEPT *a)
 {
     if (a == NULL)
         return;
-
     OPENSSL_free(a->param_addr);
     OPENSSL_free(a->param_serv);
     BIO_ADDRINFO_free(a->addr_first);
@@ -177,7 +136,7 @@ static int acpt_free(BIO *a)
     BIO_ACCEPT *data;
 
     if (a == NULL)
-        return (0);
+        return 0;
     data = (BIO_ACCEPT *)a->ptr;
 
     if (a->shutdown) {
@@ -187,7 +146,7 @@ static int acpt_free(BIO *a)
         a->flags = 0;
         a->init = 0;
     }
-    return (1);
+    return 1;
 }
 
 static int acpt_state(BIO *b, BIO_ACCEPT *c)
@@ -199,10 +158,10 @@ static int acpt_state(BIO *b, BIO_ACCEPT *c)
         switch (c->state) {
         case ACPT_S_BEFORE:
             if (c->param_addr == NULL && c->param_serv == NULL) {
-                BIOerr(BIO_F_ACPT_STATE, BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED);
-                ERR_add_error_data(4,
-                                   "hostname=", c->param_addr,
-                                   " service=", c->param_serv);
+                ERR_raise_data(ERR_LIB_BIO,
+                               BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED,
+                               "hostname=%s, service=%s",
+                               c->param_addr, c->param_serv);
                 goto exit_loop;
             }
 
@@ -235,7 +194,7 @@ static int acpt_state(BIO *b, BIO_ACCEPT *c)
                         family = AF_INET6;
                     } else {
 #endif
-                        BIOerr(BIO_F_ACPT_STATE, BIO_R_UNAVAILABLE_IP_FAMILY);
+                        ERR_raise(ERR_LIB_BIO, BIO_R_UNAVAILABLE_IP_FAMILY);
                         goto exit_loop;
                     }
                     break;
@@ -246,7 +205,7 @@ static int acpt_state(BIO *b, BIO_ACCEPT *c)
                     family = AF_UNSPEC;
                     break;
                 default:
-                    BIOerr(BIO_F_ACPT_STATE, BIO_R_UNSUPPORTED_IP_FAMILY);
+                    ERR_raise(ERR_LIB_BIO, BIO_R_UNSUPPORTED_IP_FAMILY);
                     goto exit_loop;
                 }
                 if (BIO_lookup(c->param_addr, c->param_serv, BIO_LOOKUP_SERVER,
@@ -254,31 +213,37 @@ static int acpt_state(BIO *b, BIO_ACCEPT *c)
                     goto exit_loop;
             }
             if (c->addr_first == NULL) {
-                BIOerr(BIO_F_ACPT_STATE, BIO_R_LOOKUP_RETURNED_NOTHING);
+                ERR_raise(ERR_LIB_BIO, BIO_R_LOOKUP_RETURNED_NOTHING);
                 goto exit_loop;
             }
-            /* We're currently not iterating, but set this as preparation
-             * for possible future development in that regard
-             */
             c->addr_iter = c->addr_first;
             c->state = ACPT_S_CREATE_SOCKET;
             break;
 
         case ACPT_S_CREATE_SOCKET:
-            ret = BIO_socket(BIO_ADDRINFO_family(c->addr_iter),
-                             BIO_ADDRINFO_socktype(c->addr_iter),
-                             BIO_ADDRINFO_protocol(c->addr_iter), 0);
-            if (ret == (int)INVALID_SOCKET) {
-                SYSerr(SYS_F_SOCKET, get_last_socket_error());
-                ERR_add_error_data(4,
-                                   "hostname=", c->param_addr,
-                                   " service=", c->param_serv);
-                BIOerr(BIO_F_ACPT_STATE, BIO_R_UNABLE_TO_CREATE_SOCKET);
+            ERR_set_mark();
+            s = BIO_socket(BIO_ADDRINFO_family(c->addr_iter),
+                           BIO_ADDRINFO_socktype(c->addr_iter),
+                           BIO_ADDRINFO_protocol(c->addr_iter), 0);
+            if (s == (int)INVALID_SOCKET) {
+                if ((c->addr_iter = BIO_ADDRINFO_next(c->addr_iter)) != NULL) {
+                    /*
+                     * if there are more addresses to try, do that first
+                     */
+                    ERR_pop_to_mark();
+                    break;
+                }
+                ERR_clear_last_mark();
+                ERR_raise_data(ERR_LIB_SYS, get_last_socket_error(),
+                               "calling socket(%s, %s)",
+                                c->param_addr, c->param_serv);
+                ERR_raise(ERR_LIB_BIO, BIO_R_UNABLE_TO_CREATE_SOCKET);
                 goto exit_loop;
             }
-            c->accept_sock = ret;
-            b->num = ret;
+            c->accept_sock = s;
+            b->num = s;
             c->state = ACPT_S_LISTEN;
+            s = -1;
             break;
 
         case ACPT_S_LISTEN:
@@ -319,6 +284,11 @@ static int acpt_state(BIO *b, BIO_ACCEPT *c)
             BIO_clear_retry_flags(b);
             b->retry_reason = 0;
 
+            OPENSSL_free(c->cache_peer_name);
+            c->cache_peer_name = NULL;
+            OPENSSL_free(c->cache_peer_serv);
+            c->cache_peer_serv = NULL;
+
             s = BIO_accept_ex(c->accept_sock, &c->cache_peer_addr,
                               c->accepted_mode);
 
@@ -343,9 +313,11 @@ static int acpt_state(BIO *b, BIO_ACCEPT *c)
             if (bio == NULL)
                 goto exit_loop;
 
+            BIO_set_callback_ex(bio, BIO_get_callback_ex(b));
+#ifndef OPENSSL_NO_DEPRECATED_3_0
             BIO_set_callback(bio, BIO_get_callback(b));
+#endif
             BIO_set_callback_arg(bio, BIO_get_callback_arg(b));
-
             /*
              * If the accept BIO has an bio_chain, we dup it and put the new
              * socket at the end.
@@ -403,12 +375,12 @@ static int acpt_read(BIO *b, char *out, int outl)
     while (b->next_bio == NULL) {
         ret = acpt_state(b, data);
         if (ret <= 0)
-            return (ret);
+            return ret;
     }
 
     ret = BIO_read(b->next_bio, out, outl);
     BIO_copy_next_retry(b);
-    return (ret);
+    return ret;
 }
 
 static int acpt_write(BIO *b, const char *in, int inl)
@@ -422,12 +394,12 @@ static int acpt_write(BIO *b, const char *in, int inl)
     while (b->next_bio == NULL) {
         ret = acpt_state(b, data);
         if (ret <= 0)
-            return (ret);
+            return ret;
     }
 
     ret = BIO_write(b->next_bio, in, inl);
     BIO_copy_next_retry(b);
-    return (ret);
+    return ret;
 }
 
 static long acpt_ctrl(BIO *b, int cmd, long num, void *ptr)
@@ -471,8 +443,10 @@ static long acpt_ctrl(BIO *b, int cmd, long num, void *ptr)
                 b->init = 1;
             } else if (num == 1) {
                 OPENSSL_free(data->param_serv);
-                data->param_serv = BUF_strdup(ptr);
-                b->init = 1;
+                if ((data->param_serv = OPENSSL_strdup(ptr)) == NULL)
+                    ret = 0;
+                else
+                    b->init = 1;
             } else if (num == 2) {
                 data->bind_mode |= BIO_SOCK_NONBLOCK;
             } else if (num == 3) {
@@ -494,7 +468,6 @@ static long acpt_ctrl(BIO *b, int cmd, long num, void *ptr)
             data->accepted_mode &= ~BIO_SOCK_NONBLOCK;
         break;
     case BIO_C_SET_FD:
-        b->init = 1;
         b->num = *((int *)ptr);
         data->accept_sock = b->num;
         data->state = ACPT_S_ACCEPT;
@@ -565,19 +538,18 @@ static long acpt_ctrl(BIO *b, int cmd, long num, void *ptr)
         ret = (long)data->bind_mode;
         break;
     case BIO_CTRL_DUP:
-/*-     dbio=(BIO *)ptr;
-        if (data->param_port) EAY EAY
-                BIO_set_port(dbio,data->param_port);
-        if (data->param_hostname)
-                BIO_set_hostname(dbio,data->param_hostname);
-        BIO_set_nbio(dbio,data->nbio); */
         break;
-
+    case BIO_CTRL_EOF:
+        if (b->next_bio == NULL)
+            ret = 0;
+        else
+            ret = BIO_ctrl(b->next_bio, cmd, num, ptr);
+        break;
     default:
         ret = 0;
         break;
     }
-    return (ret);
+    return ret;
 }
 
 static int acpt_puts(BIO *bp, const char *str)
@@ -586,7 +558,7 @@ static int acpt_puts(BIO *bp, const char *str)
 
     n = strlen(str);
     ret = acpt_write(bp, str, n);
-    return (ret);
+    return ret;
 }
 
 BIO *BIO_new_accept(const char *str)
@@ -595,11 +567,11 @@ BIO *BIO_new_accept(const char *str)
 
     ret = BIO_new(BIO_s_accept());
     if (ret == NULL)
-        return (NULL);
-    if (BIO_set_accept_port(ret, str))
-        return (ret);
+        return NULL;
+    if (BIO_set_accept_name(ret, str))
+        return ret;
     BIO_free(ret);
-    return (NULL);
+    return NULL;
 }
 
 #endif