X-Git-Url: https://git.openssl.org/gitweb/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fbio%2Fb_addr.c;h=9832c0c89c6ad5086a5bf7304f00c0e2ee4e8491;hp=bb6719eb2a3c24bb87515b5c49f5f860fea9f87d;hb=55bd917bc4213bc668f48b87d8c6feb9918fef8f;hpb=b1322259d93cf6b6286f9febcd468b6a9f577d91 diff --git a/crypto/bio/b_addr.c b/crypto/bio/b_addr.c index bb6719eb2a..9832c0c89c 100644 --- a/crypto/bio/b_addr.c +++ b/crypto/bio/b_addr.c @@ -1,5 +1,5 @@ /* - * Copyright 2016 The OpenSSL Project Authors. All Rights Reserved. + * Copyright 2016-2018 The OpenSSL Project Authors. All Rights Reserved. * * Licensed under the OpenSSL license (the "License"). You may not use * this file except in compliance with the License. You can obtain a copy @@ -7,6 +7,7 @@ * https://www.openssl.org/source/license.html */ +#include #include #include "bio_lcl.h" @@ -15,7 +16,7 @@ #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; @@ -65,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 @@ -228,21 +229,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; } @@ -550,11 +565,10 @@ static int addrinfo_wrap(int family, int socktype, 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; @@ -587,13 +601,22 @@ static int addrinfo_wrap(int family, int socktype, return 1; } -static void do_bio_lookup_init(void) +DEFINE_RUN_ONCE_STATIC(do_bio_lookup_init) { + OPENSSL_init_crypto(0, NULL); 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. @@ -601,6 +624,10 @@ static void do_bio_lookup_init(void) * 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. @@ -610,9 +637,8 @@ static void do_bio_lookup_init(void) * * 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 */ @@ -629,7 +655,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; } @@ -638,7 +664,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 @@ -647,16 +673,15 @@ 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; - memset(&hints, 0, sizeof hints); -# 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 = protocol; if (lookup_type == BIO_LOOKUP_SERVER) hints.ai_flags |= AI_PASSIVE; @@ -668,14 +693,14 @@ int BIO_lookup(const char *host, const char *service, # ifdef EAI_SYSTEM case EAI_SYSTEM: SYSerr(SYS_F_GETADDRINFO, get_last_socket_error()); - BIOerr(BIO_F_BIO_LOOKUP, ERR_R_SYS_LIB); + 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); + BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_SYS_LIB); ERR_add_error_data(1, gai_strerror(gai_ret)); break; } @@ -694,12 +719,12 @@ int BIO_lookup(const char *host, const char *service, /* 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), @@ -716,7 +741,11 @@ int BIO_lookup(const char *host, const char *service, struct servent se_fallback = { NULL, NULL, 0, NULL }; #endif - CRYPTO_THREAD_run_once(&bio_lookup_init, do_bio_lookup_init); + 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; @@ -730,16 +759,29 @@ 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... + */ + SYSerr(SYS_F_GETHOSTBYNAME, 1000 + h_errno); #else SYSerr(SYS_F_GETHOSTBYNAME, WSAGetLastError()); #endif @@ -780,7 +822,7 @@ int BIO_lookup(const char *host, const char *service, 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) { @@ -788,15 +830,14 @@ int BIO_lookup(const char *host, const char *service, if (se == NULL) { #ifndef OPENSSL_SYS_WINDOWS - BIOerr(BIO_F_BIO_LOOKUP, ERR_R_SYS_LIB); - ERR_add_error_data(1, hstrerror(h_errno)); + SYSerr(SYS_F_GETSERVBYNAME, errno); #else SYSerr(SYS_F_GETSERVBYNAME, WSAGetLastError()); #endif 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; } } @@ -838,7 +879,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; }