X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fbio%2Fb_addr.c;h=511d9c197b40ce64be57e4cc907e52d48c2ca286;hp=e92876ab99260124cb074149e1f9d78daf5c0142;hb=7f616a00e9232392927099dca1eca70d0d058665;hpb=29620124ff1624af5411d8d2998fdd7b102a5d48 diff --git a/crypto/bio/b_addr.c b/crypto/bio/b_addr.c index e92876ab99..511d9c197b 100644 --- a/crypto/bio/b_addr.c +++ b/crypto/bio/b_addr.c @@ -1,64 +1,25 @@ -/* ==================================================================== - * Copyright (c) 2015 The OpenSSL Project. All rights reserved. - * - * 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 above 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 acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit. (http://www.openssl.org/)" - * - * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to - * endorse or promote products derived from this software without - * prior written permission. For written permission, please contact - * openssl-core@openssl.org. - * - * 5. Products derived from this software may not be called "OpenSSL" - * nor may "OpenSSL" appear in their names without prior written - * permission of the OpenSSL Project. - * - * 6. Redistributions of any form whatsoever must retain the following - * acknowledgment: - * "This product includes software developed by the OpenSSL Project - * for use in the OpenSSL Toolkit (http://www.openssl.org/)" - * - * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY - * EXPRESSED 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 OpenSSL PROJECT OR - * ITS 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. - * ==================================================================== - * - * This product includes cryptographic software written by Eric Young - * (eay@cryptsoft.com). This product includes software written by Tim - * Hudson (tjh@cryptsoft.com). +/* + * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. * + * 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 */ +#include #include #include "bio_lcl.h" +#include +#ifndef OPENSSL_NO_SOCK #include #include -#include +#include "internal/thread_once.h" + +CRYPTO_RWLOCK *bio_lookup_lock; +static CRYPTO_ONCE bio_lookup_init = CRYPTO_ONCE_STATIC_INIT; /* * Throughout this file and bio_lcl.h, the existence of the macro @@ -78,6 +39,11 @@ BIO_ADDR *BIO_ADDR_new(void) { BIO_ADDR *ret = OPENSSL_zalloc(sizeof(*ret)); + if (ret == NULL) { + BIOerr(BIO_F_BIO_ADDR_NEW, ERR_R_MALLOC_FAILURE); + return NULL; + } + ret->sa.sa_family = AF_UNSPEC; return ret; } @@ -100,18 +66,18 @@ void BIO_ADDR_clear(BIO_ADDR *ap) int BIO_ADDR_make(BIO_ADDR *ap, const struct sockaddr *sa) { if (sa->sa_family == AF_INET) { - ap->s_in = *(const struct sockaddr_in *)sa; + memcpy(&(ap->s_in), sa, sizeof(struct sockaddr_in)); return 1; } #ifdef AF_INET6 if (sa->sa_family == AF_INET6) { - ap->s_in6 = *(const struct sockaddr_in6 *)sa; + memcpy(&(ap->s_in6), sa, sizeof(struct sockaddr_in6)); return 1; } #endif #ifdef AF_UNIX - if (ap->sa.sa_family == AF_UNIX) { - ap->s_un = *(const struct sockaddr_un *)sa; + if (sa->sa_family == AF_UNIX) { + memcpy(&(ap->s_un), sa, sizeof(struct sockaddr_un)); return 1; } #endif @@ -241,7 +207,8 @@ static int addr_strings(const BIO_ADDR *ap, int numeric, flags)) != 0) { # ifdef EAI_SYSTEM if (ret == EAI_SYSTEM) { - SYSerr(SYS_F_GETNAMEINFO, get_last_socket_error()); + ERR_raise_data(ERR_LIB_SYS, get_last_socket_error(), + "calling getnameinfo()"); BIOerr(BIO_F_ADDR_STRINGS, ERR_R_SYS_LIB); } else # endif @@ -263,21 +230,35 @@ static int addr_strings(const BIO_ADDR *ap, int numeric, ntohs(BIO_ADDR_rawport(ap))); } - if (hostname) + if (hostname != NULL) *hostname = OPENSSL_strdup(host); - if (service) + if (service != NULL) *service = OPENSSL_strdup(serv); } else { #endif - if (hostname) + if (hostname != NULL) *hostname = OPENSSL_strdup(inet_ntoa(ap->s_in.sin_addr)); - if (service) { + if (service != NULL) { char serv[6]; /* port is 16 bits => max 5 decimal digits */ BIO_snprintf(serv, sizeof(serv), "%d", ntohs(ap->s_in.sin_port)); *service = OPENSSL_strdup(serv); } } + if ((hostname != NULL && *hostname == NULL) + || (service != NULL && *service == NULL)) { + if (hostname != NULL) { + OPENSSL_free(*hostname); + *hostname = NULL; + } + if (service != NULL) { + OPENSSL_free(*service); + *service = NULL; + } + BIOerr(BIO_F_ADDR_STRINGS, ERR_R_MALLOC_FAILURE); + return 0; + } + return 1; } @@ -578,18 +559,17 @@ int BIO_parse_hostserv(const char *hostserv, char **host, char **service, * family, such as AF_UNIX * * the return value is 1 on success, or 0 on failure, which - * only happens if a memory allocation error occured. + * only happens if a memory allocation error occurred. */ static int addrinfo_wrap(int family, int socktype, const void *where, size_t wherelen, unsigned short port, BIO_ADDRINFO **bai) { - OPENSSL_assert(bai != NULL); - - *bai = OPENSSL_zalloc(sizeof(**bai)); - if (*bai == NULL) + if ((*bai = OPENSSL_zalloc(sizeof(**bai))) == NULL) { + BIOerr(BIO_F_ADDRINFO_WRAP, ERR_R_MALLOC_FAILURE); return 0; + } (*bai)->bai_family = family; (*bai)->bai_socktype = socktype; @@ -622,8 +602,23 @@ static int addrinfo_wrap(int family, int socktype, return 1; } +DEFINE_RUN_ONCE_STATIC(do_bio_lookup_init) +{ + if (!OPENSSL_init_crypto(0, NULL)) + return 0; + bio_lookup_lock = CRYPTO_THREAD_lock_new(); + return bio_lookup_lock != NULL; +} + +int BIO_lookup(const char *host, const char *service, + enum BIO_lookup_type lookup_type, + int family, int socktype, BIO_ADDRINFO **res) +{ + return BIO_lookup_ex(host, service, lookup_type, family, socktype, 0, res); +} + /*- - * BIO_lookup - look up the node and service you want to connect to. + * BIO_lookup_ex - look up the node and service you want to connect to. * @node: the node you want to connect to. * @service: the service you want to connect to. * @lookup_type: declare intent with the result, client or server. @@ -631,6 +626,10 @@ static int addrinfo_wrap(int family, int socktype, * AF_INET, AF_INET6 or AF_UNIX. * @socktype: The socket type you want to use. Can be SOCK_STREAM, SOCK_DGRAM * or 0 for all. + * @protocol: The protocol to use, e.g. IPPROTO_TCP or IPPROTO_UDP or 0 for all. + * Note that some platforms may not return IPPROTO_SCTP without + * explicitly requesting it (i.e. IPPROTO_SCTP may not be returned + * with 0 for the protocol) * @res: Storage place for the resulting list of returned addresses * * This will do a lookup of the node and service that you want to connect to. @@ -640,9 +639,8 @@ static int addrinfo_wrap(int family, int socktype, * * The return value is 1 on success or 0 in case of error. */ -int BIO_lookup(const char *host, const char *service, - enum BIO_lookup_type lookup_type, - int family, int socktype, BIO_ADDRINFO **res) +int BIO_lookup_ex(const char *host, const char *service, int lookup_type, + int family, int socktype, int protocol, BIO_ADDRINFO **res) { int ret = 0; /* Assume failure */ @@ -659,7 +657,7 @@ int BIO_lookup(const char *host, const char *service, #endif break; default: - BIOerr(BIO_F_BIO_LOOKUP, BIO_R_UNSUPPORTED_PROTOCOL_FAMILY); + BIOerr(BIO_F_BIO_LOOKUP_EX, BIO_R_UNSUPPORTED_PROTOCOL_FAMILY); return 0; } @@ -668,7 +666,7 @@ int BIO_lookup(const char *host, const char *service, if (addrinfo_wrap(family, socktype, host, strlen(host), 0, res)) return 1; else - BIOerr(BIO_F_BIO_LOOKUP, ERR_R_MALLOC_FAILURE); + BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_MALLOC_FAILURE); return 0; } #endif @@ -677,21 +675,21 @@ int BIO_lookup(const char *host, const char *service, return 0; if (1) { - int gai_ret = 0; #ifdef AI_PASSIVE + int gai_ret = 0; struct addrinfo hints; - hints.ai_flags = 0; -# ifdef AI_ADDRCONFIG - hints.ai_flags = AI_ADDRCONFIG; -# endif + memset(&hints, 0, sizeof(hints)); + hints.ai_family = family; hints.ai_socktype = socktype; - hints.ai_protocol = 0; - hints.ai_addrlen = 0; - hints.ai_addr = NULL; - hints.ai_canonname = NULL; - hints.ai_next = NULL; + hints.ai_protocol = protocol; +#ifdef AI_ADDRCONFIG +#ifdef AF_UNSPEC + if (family == AF_UNSPEC) +#endif + hints.ai_flags |= AI_ADDRCONFIG; +#endif if (lookup_type == BIO_LOOKUP_SERVER) hints.ai_flags |= AI_PASSIVE; @@ -699,48 +697,74 @@ int BIO_lookup(const char *host, const char *service, /* Note that |res| SHOULD be a 'struct addrinfo **' thanks to * macro magic in bio_lcl.h */ + retry: switch ((gai_ret = getaddrinfo(host, service, &hints, res))) { # ifdef EAI_SYSTEM case EAI_SYSTEM: - SYSerr(SYS_F_GETADDRINFO, get_last_socket_error()); - BIOerr(BIO_F_BIO_LOOKUP, ERR_R_SYS_LIB); + ERR_raise_data(ERR_LIB_SYS, get_last_socket_error(), + "calling getaddrinfo()"); + BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_SYS_LIB); break; # endif case 0: ret = 1; /* Success */ break; default: - BIOerr(BIO_F_BIO_LOOKUP, ERR_R_SYS_LIB); +# if defined(AI_ADDRCONFIG) && defined(AI_NUMERICHOST) + if (hints.ai_flags & AI_ADDRCONFIG) { + hints.ai_flags &= ~AI_ADDRCONFIG; + hints.ai_flags |= AI_NUMERICHOST; + goto retry; + } +# endif + BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_SYS_LIB); ERR_add_error_data(1, gai_strerror(gai_ret)); break; } } else { #endif const struct hostent *he; +/* + * Because struct hostent is defined for 32-bit pointers only with + * VMS C, we need to make sure that '&he_fallback_address' and + * '&he_fallback_addresses' are 32-bit pointers + */ +#if defined(OPENSSL_SYS_VMS) && defined(__DECC) +# pragma pointer_size save +# pragma pointer_size 32 +#endif /* Windows doesn't seem to have in_addr_t */ #ifdef OPENSSL_SYS_WINDOWS static uint32_t he_fallback_address; - static const uint32_t *he_fallback_addresses[] = - { &he_fallback_address, NULL }; + static const char *he_fallback_addresses[] = + { (char *)&he_fallback_address, NULL }; #else static in_addr_t he_fallback_address; - static const in_addr_t *he_fallback_addresses[] = - { &he_fallback_address, NULL }; + static const char *he_fallback_addresses[] = + { (char *)&he_fallback_address, NULL }; #endif static const struct hostent he_fallback = { NULL, NULL, AF_INET, sizeof(he_fallback_address), (char **)&he_fallback_addresses }; +#if defined(OPENSSL_SYS_VMS) && defined(__DECC) +# pragma pointer_size restore +#endif + struct servent *se; - /* Apprently, on WIN64, s_proto and s_port have traded places... */ + /* Apparently, on WIN64, s_proto and s_port have traded places... */ #ifdef _WIN64 struct servent se_fallback = { NULL, NULL, NULL, 0 }; #else struct servent se_fallback = { NULL, NULL, 0, NULL }; #endif - char *proto = NULL; - CRYPTO_w_lock(CRYPTO_LOCK_GETHOSTBYNAME); - CRYPTO_w_lock(CRYPTO_LOCK_GETSERVBYNAME); + if (!RUN_ONCE(&bio_lookup_init, do_bio_lookup_init)) { + BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_MALLOC_FAILURE); + ret = 0; + goto err; + } + + CRYPTO_THREAD_write_lock(bio_lookup_lock); he_fallback_address = INADDR_ANY; if (host == NULL) { he = &he_fallback; @@ -752,18 +776,39 @@ int BIO_lookup(const char *host, const char *service, he_fallback_address = INADDR_ANY; break; default: - OPENSSL_assert(("We forgot to handle a lookup type!" == 0)); - break; + /* We forgot to handle a lookup type! */ + assert("We forgot to handle a lookup type!" == NULL); + BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_INTERNAL_ERROR); + ret = 0; + goto err; } } else { he = gethostbyname(host); if (he == NULL) { #ifndef OPENSSL_SYS_WINDOWS - BIOerr(BIO_F_BIO_LOOKUP, ERR_R_SYS_LIB); - ERR_add_error_data(1, hstrerror(h_errno)); + /* + * This might be misleading, because h_errno is used as if + * it was errno. To minimize mixup add 1000. Underlying + * reason for this is that hstrerror is declared obsolete, + * not to mention that a) h_errno is not always guaranteed + * to be meaningless; b) hstrerror can reside in yet another + * library, linking for sake of hstrerror is an overkill; + * c) this path is not executed on contemporary systems + * anyway [above getaddrinfo/gai_strerror is]. We just let + * system administrator figure this out... + */ +# if defined(OPENSSL_SYS_VXWORKS) + /* h_errno doesn't exist on VxWorks */ + ERR_raise_data(ERR_LIB_SYS, 1000, + "calling gethostbyname()"); +# else + ERR_raise_data(ERR_LIB_SYS, 1000 + h_errno, + "calling gethostbyname()"); +# endif #else - SYSerr(SYS_F_GETHOSTBYNAME, WSAGetLastError()); + ERR_raise_data(ERR_LIB_SYS, get_last_socket_error(), + "calling gethostbyname()"); #endif ret = 0; goto err; @@ -772,39 +817,49 @@ int BIO_lookup(const char *host, const char *service, if (service == NULL) { se_fallback.s_port = 0; - se_fallback.s_proto = proto; + se_fallback.s_proto = NULL; se = &se_fallback; } else { char *endp = NULL; long portnum = strtol(service, &endp, 10); +/* + * Because struct servent is defined for 32-bit pointers only with + * VMS C, we need to make sure that 'proto' is a 32-bit pointer. + */ +#if defined(OPENSSL_SYS_VMS) && defined(__DECC) +# pragma pointer_size save +# pragma pointer_size 32 +#endif + char *proto = NULL; +#if defined(OPENSSL_SYS_VMS) && defined(__DECC) +# pragma pointer_size restore +#endif + + switch (socktype) { + case SOCK_STREAM: + proto = "tcp"; + break; + case SOCK_DGRAM: + proto = "udp"; + break; + } + if (endp != service && *endp == '\0' && portnum > 0 && portnum < 65536) { - se_fallback.s_port = htons(portnum); + se_fallback.s_port = htons((unsigned short)portnum); se_fallback.s_proto = proto; se = &se_fallback; } else if (endp == service) { - switch (socktype) { - case SOCK_STREAM: - proto = "tcp"; - break; - case SOCK_DGRAM: - proto = "udp"; - break; - } se = getservbyname(service, proto); if (se == NULL) { -#ifndef OPENSSL_SYS_WINDOWS - BIOerr(BIO_F_BIO_LOOKUP, ERR_R_SYS_LIB); - ERR_add_error_data(1, hstrerror(h_errno)); -#else - SYSerr(SYS_F_GETSERVBYNAME, WSAGetLastError()); -#endif + ERR_raise_data(ERR_LIB_SYS, get_last_socket_error(), + "calling getservbyname()"); goto err; } } else { - BIOerr(BIO_F_BIO_LOOKUP, BIO_R_MALFORMED_HOST_OR_SERVICE); + BIOerr(BIO_F_BIO_LOOKUP_EX, BIO_R_MALFORMED_HOST_OR_SERVICE); goto err; } } @@ -812,7 +867,19 @@ int BIO_lookup(const char *host, const char *service, *res = NULL; { +/* + * Because hostent::h_addr_list is an array of 32-bit pointers with VMS C, + * we must make sure our iterator designates the same element type, hence + * the pointer size dance. + */ +#if defined(OPENSSL_SYS_VMS) && defined(__DECC) +# pragma pointer_size save +# pragma pointer_size 32 +#endif char **addrlistp; +#if defined(OPENSSL_SYS_VMS) && defined(__DECC) +# pragma pointer_size restore +#endif size_t addresses; BIO_ADDRINFO *tmp_bai = NULL; @@ -834,7 +901,7 @@ int BIO_lookup(const char *host, const char *service, addrinfo_malloc_err: BIO_ADDRINFO_free(*res); *res = NULL; - BIOerr(BIO_F_BIO_LOOKUP, ERR_R_MALLOC_FAILURE); + BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_MALLOC_FAILURE); ret = 0; goto err; } @@ -842,9 +909,10 @@ int BIO_lookup(const char *host, const char *service, ret = 1; } err: - CRYPTO_w_unlock(CRYPTO_LOCK_GETSERVBYNAME); - CRYPTO_w_unlock(CRYPTO_LOCK_GETHOSTBYNAME); + CRYPTO_THREAD_unlock(bio_lookup_lock); } return ret; } + +#endif /* OPENSSL_NO_SOCK */