X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=crypto%2Fbio%2Fb_addr.c;h=1813f5a9bb641c7a122aa54046b2a5d0aa5e7efc;hp=ed267e96f62f0b45179309be9ce3cf6b06b460e7;hb=cb1d435cac2a9a7bd6019f9f23648c8075251109;hpb=28a0841bf58e3813b2e07ad22f19484308e2f70a diff --git a/crypto/bio/b_addr.c b/crypto/bio/b_addr.c index ed267e96f6..1813f5a9bb 100644 --- a/crypto/bio/b_addr.c +++ b/crypto/bio/b_addr.c @@ -55,9 +55,15 @@ #include #include "bio_lcl.h" +#include "internal/threads.h" +#ifndef OPENSSL_NO_SOCK #include #include +#include + +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 @@ -75,7 +81,14 @@ BIO_ADDR *BIO_ADDR_new(void) { - BIO_ADDR *ret = (BIO_ADDR *)OPENSSL_zalloc(sizeof(BIO_ADDR)); + 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; } @@ -84,6 +97,12 @@ void BIO_ADDR_free(BIO_ADDR *ap) OPENSSL_free(ap); } +void BIO_ADDR_clear(BIO_ADDR *ap) +{ + memset(ap, 0, sizeof(*ap)); + ap->sa.sa_family = AF_UNSPEC; +} + /* * BIO_ADDR_make - non-public routine to fill a BIO_ADDR with the contents * of a struct sockaddr. @@ -91,18 +110,18 @@ void BIO_ADDR_free(BIO_ADDR *ap) int BIO_ADDR_make(BIO_ADDR *ap, const struct sockaddr *sa) { if (sa->sa_family == AF_INET) { - ap->sin = *(const struct sockaddr_in *)sa; + ap->s_in = *(const struct sockaddr_in *)sa; return 1; } #ifdef AF_INET6 if (sa->sa_family == AF_INET6) { - ap->sin6 = *(const struct sockaddr_in6 *)sa; + ap->s_in6 = *(const struct sockaddr_in6 *)sa; return 1; } #endif #ifdef AF_UNIX if (ap->sa.sa_family == AF_UNIX) { - ap->sun = *(const struct sockaddr_un *)sa; + ap->s_un = *(const struct sockaddr_un *)sa; return 1; } #endif @@ -116,31 +135,31 @@ int BIO_ADDR_rawmake(BIO_ADDR *ap, int family, { #ifdef AF_UNIX if (family == AF_UNIX) { - if (wherelen + 1 > sizeof(ap->sun.sun_path)) + if (wherelen + 1 > sizeof(ap->s_un.sun_path)) return 0; - memset(&ap->sun, 0, sizeof(ap->sun)); - ap->sun.sun_family = family; - strncpy(ap->sun.sun_path, where, sizeof(ap->sun.sun_path) - 1); + memset(&ap->s_un, 0, sizeof(ap->s_un)); + ap->s_un.sun_family = family; + strncpy(ap->s_un.sun_path, where, sizeof(ap->s_un.sun_path) - 1); return 1; } #endif if (family == AF_INET) { if (wherelen != sizeof(struct in_addr)) return 0; - memset(&ap->sin, 0, sizeof(ap->sin)); - ap->sin.sin_family = family; - ap->sin.sin_port = port; - ap->sin.sin_addr = *(struct in_addr *)where; + memset(&ap->s_in, 0, sizeof(ap->s_in)); + ap->s_in.sin_family = family; + ap->s_in.sin_port = port; + ap->s_in.sin_addr = *(struct in_addr *)where; return 1; } #ifdef AF_INET6 if (family == AF_INET6) { if (wherelen != sizeof(struct in6_addr)) return 0; - memset(&ap->sin6, 0, sizeof(ap->sin6)); - ap->sin6.sin6_family = family; - ap->sin6.sin6_port = port; - ap->sin6.sin6_addr = *(struct in6_addr *)where; + memset(&ap->s_in6, 0, sizeof(ap->s_in6)); + ap->s_in6.sin6_family = family; + ap->s_in6.sin6_port = port; + ap->s_in6.sin6_addr = *(struct in6_addr *)where; return 1; } #endif @@ -159,19 +178,19 @@ int BIO_ADDR_rawaddress(const BIO_ADDR *ap, void *p, size_t *l) const void *addrptr = NULL; if (ap->sa.sa_family == AF_INET) { - len = sizeof(ap->sin.sin_addr); - addrptr = &ap->sin.sin_addr; + len = sizeof(ap->s_in.sin_addr); + addrptr = &ap->s_in.sin_addr; } #ifdef AF_INET6 else if (ap->sa.sa_family == AF_INET6) { - len = sizeof(ap->sin6.sin6_addr); - addrptr = &ap->sin6.sin6_addr; + len = sizeof(ap->s_in6.sin6_addr); + addrptr = &ap->s_in6.sin6_addr; } #endif #ifdef AF_UNIX else if (ap->sa.sa_family == AF_UNIX) { - len = strlen(ap->sun.sun_path); - addrptr = &ap->sun.sun_path; + len = strlen(ap->s_un.sun_path); + addrptr = &ap->s_un.sun_path; } #endif @@ -190,10 +209,10 @@ int BIO_ADDR_rawaddress(const BIO_ADDR *ap, void *p, size_t *l) unsigned short BIO_ADDR_rawport(const BIO_ADDR *ap) { if (ap->sa.sa_family == AF_INET) - return ap->sin.sin_port; + return ap->s_in.sin_port; #ifdef AF_INET6 if (ap->sa.sa_family == AF_INET6) - return ap->sin6.sin6_port; + return ap->s_in6.sin6_port; #endif return 0; } @@ -214,10 +233,13 @@ unsigned short BIO_ADDR_rawport(const BIO_ADDR *ap) static int addr_strings(const BIO_ADDR *ap, int numeric, char **hostname, char **service) { + if (BIO_sock_init() != 1) + return 0; + if (1) { #ifdef AI_PASSIVE int ret = 0; - char host[NI_MAXHOST], serv[NI_MAXSERV]; + char host[NI_MAXHOST] = "", serv[NI_MAXSERV] = ""; int flags = 0; if (numeric) @@ -239,6 +261,18 @@ static int addr_strings(const BIO_ADDR *ap, int numeric, } return 0; } + + /* VMS getnameinfo() has a bug, it doesn't fill in serv, which + * leaves it with whatever garbage that happens to be there. + * However, we initialise serv with the empty string (serv[0] + * is therefore NUL), so it gets real easy to detect when things + * didn't go the way one might expect. + */ + if (serv[0] == '\0') { + BIO_snprintf(serv, sizeof(serv), "%d", + ntohs(BIO_ADDR_rawport(ap))); + } + if (hostname) *hostname = OPENSSL_strdup(host); if (service) @@ -246,10 +280,10 @@ static int addr_strings(const BIO_ADDR *ap, int numeric, } else { #endif if (hostname) - *hostname = OPENSSL_strdup(inet_ntoa(ap->sin.sin_addr)); + *hostname = OPENSSL_strdup(inet_ntoa(ap->s_in.sin_addr)); if (service) { char serv[6]; /* port is 16 bits => max 5 decimal digits */ - BIO_snprintf(serv, sizeof(serv), "%d", ntohs(ap->sin.sin_port)); + BIO_snprintf(serv, sizeof(serv), "%d", ntohs(ap->s_in.sin_port)); *service = OPENSSL_strdup(serv); } } @@ -281,7 +315,7 @@ char *BIO_ADDR_path_string(const BIO_ADDR *ap) { #ifdef AF_UNIX if (ap->sa.sa_family == AF_UNIX) - return OPENSSL_strdup(ap->sun.sun_path); + return OPENSSL_strdup(ap->s_un.sun_path); #endif return NULL; } @@ -316,21 +350,21 @@ struct sockaddr *BIO_ADDR_sockaddr_noconst(BIO_ADDR *ap) socklen_t BIO_ADDR_sockaddr_size(const BIO_ADDR *ap) { if (ap->sa.sa_family == AF_INET) - return sizeof(ap->sin); + return sizeof(ap->s_in); #ifdef AF_INET6 if (ap->sa.sa_family == AF_INET6) - return sizeof(ap->sin6); + return sizeof(ap->s_in6); #endif #ifdef AF_UNIX if (ap->sa.sa_family == AF_UNIX) - return sizeof(ap->sun); + return sizeof(ap->s_un); #endif return sizeof(*ap); } /********************************************************************** * - * Address into database + * Address info database * */ @@ -357,8 +391,24 @@ int BIO_ADDRINFO_socktype(const BIO_ADDRINFO *bai) int BIO_ADDRINFO_protocol(const BIO_ADDRINFO *bai) { - if (bai != NULL) - return bai->bai_protocol; + if (bai != NULL) { + if (bai->bai_protocol != 0) + return bai->bai_protocol; + +#ifdef AF_UNIX + if (bai->bai_family == AF_UNIX) + return 0; +#endif + + switch (bai->bai_socktype) { + case SOCK_STREAM: + return IPPROTO_TCP; + case SOCK_DGRAM: + return IPPROTO_UDP; + default: + break; + } + } return 0; } @@ -495,7 +545,7 @@ int BIO_parse_hostserv(const char *hostserv, char **host, char **service, } } - if (strchr(p, ':')) + if (p != NULL && strchr(p, ':')) goto spec_err; if (h != NULL && host != NULL) { @@ -538,7 +588,7 @@ 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, @@ -547,10 +597,10 @@ static int addrinfo_wrap(int family, int socktype, { OPENSSL_assert(bai != NULL); - *bai = (BIO_ADDRINFO *)OPENSSL_zalloc(sizeof(**bai)); - + *bai = OPENSSL_zalloc(sizeof(**bai)); if (*bai == NULL) return 0; + (*bai)->bai_family = family; (*bai)->bai_socktype = socktype; if (socktype == SOCK_STREAM) @@ -582,6 +632,11 @@ static int addrinfo_wrap(int family, int socktype, return 1; } +static void do_bio_lookup_init(void) +{ + bio_lookup_lock = CRYPTO_THREAD_lock_new(); +} + /*- * BIO_lookup - look up the node and service you want to connect to. * @node: the node you want to connect to. @@ -633,21 +688,20 @@ int BIO_lookup(const char *host, const char *service, } #endif + if (BIO_sock_init() != 1) + return 0; + if (1) { + int gai_ret = 0; #ifdef AI_PASSIVE struct addrinfo hints; + memset(&hints, 0, sizeof hints); - hints.ai_flags = 0; # ifdef AI_ADDRCONFIG hints.ai_flags = AI_ADDRCONFIG; # endif 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; if (lookup_type == BIO_LOOKUP_SERVER) hints.ai_flags |= AI_PASSIVE; @@ -655,7 +709,7 @@ 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 */ - switch (getaddrinfo(host, service, &hints, res)) { + switch ((gai_ret = getaddrinfo(host, service, &hints, res))) { # ifdef EAI_SYSTEM case EAI_SYSTEM: SYSerr(SYS_F_GETADDRINFO, get_last_socket_error()); @@ -667,34 +721,50 @@ int BIO_lookup(const char *host, const char *service, break; default: BIOerr(BIO_F_BIO_LOOKUP, ERR_R_SYS_LIB); - ERR_add_error_data(1, gai_strerror(ret)); + ERR_add_error_data(1, gai_strerror(gai_ret)); break; } } else { #endif - struct hostent *he; + 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 - uint32_t he_fallback_address = INADDR_ANY; - uint32_t *he_fallback_addresses[] = { &he_fallback_address, NULL }; + static uint32_t he_fallback_address; + static const uint32_t *he_fallback_addresses[] = + { &he_fallback_address, NULL }; #else - in_addr_t he_fallback_address = INADDR_ANY; - in_addr_t *he_fallback_addresses[] = { &he_fallback_address, NULL }; + static in_addr_t he_fallback_address; + static const in_addr_t *he_fallback_addresses[] = + { &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 hostent he_fallback = { NULL, NULL, AF_INET, - sizeof(he_fallback_address), - (char **)&he_fallback_addresses }; + 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); + CRYPTO_THREAD_run_once(&bio_lookup_init, do_bio_lookup_init); + + CRYPTO_THREAD_write_lock(bio_lookup_lock); + he_fallback_address = INADDR_ANY; if (host == NULL) { he = &he_fallback; switch(lookup_type) { @@ -712,8 +782,12 @@ int BIO_lookup(const char *host, const char *service, 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)); +#else + SYSerr(SYS_F_GETHOSTBYNAME, WSAGetLastError()); +#endif ret = 0; goto err; } @@ -721,31 +795,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_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 goto err; } } else { @@ -757,7 +849,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; @@ -787,9 +891,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 */