diff options
author | deshevoy <deshevoy@yandex-team.ru> | 2022-02-10 16:46:57 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:46:57 +0300 |
commit | 28148f76dbfcc644d96427d41c92f36cbf2fdc6e (patch) | |
tree | b83306b6e37edeea782e9eed673d89286c4fef35 /contrib/libs/openssl/crypto/bio | |
parent | e988f30484abe5fdeedcc7a5d3c226c01a21800c (diff) | |
download | ydb-28148f76dbfcc644d96427d41c92f36cbf2fdc6e.tar.gz |
Restoring authorship annotation for <deshevoy@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/libs/openssl/crypto/bio')
23 files changed, 10571 insertions, 10571 deletions
diff --git a/contrib/libs/openssl/crypto/bio/b_addr.c b/contrib/libs/openssl/crypto/bio/b_addr.c index f836b64103..8ea32bce40 100644 --- a/contrib/libs/openssl/crypto/bio/b_addr.c +++ b/contrib/libs/openssl/crypto/bio/b_addr.c @@ -1,724 +1,724 @@ -/* +/* * Copyright 2016-2021 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 - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - + * + * Licensed under the OpenSSL license (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 + */ + #ifndef _GNU_SOURCE # define _GNU_SOURCE #endif -#include <assert.h> -#include <string.h> - +#include <assert.h> +#include <string.h> + #include "bio_local.h" -#include <openssl/crypto.h> - -#ifndef OPENSSL_NO_SOCK -#include <openssl/err.h> -#include <openssl/buffer.h> -#include "internal/thread_once.h" - -CRYPTO_RWLOCK *bio_lookup_lock; -static CRYPTO_ONCE bio_lookup_init = CRYPTO_ONCE_STATIC_INIT; - -/* +#include <openssl/crypto.h> + +#ifndef OPENSSL_NO_SOCK +#include <openssl/err.h> +#include <openssl/buffer.h> +#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_local.h, the existence of the macro - * AI_PASSIVE is used to detect the availability of struct addrinfo, - * getnameinfo() and getaddrinfo(). If that macro doesn't exist, - * we use our own implementation instead, using gethostbyname, - * getservbyname and a few other. - */ - -/********************************************************************** - * - * Address structure - * - */ - -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; -} - -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. - */ -int BIO_ADDR_make(BIO_ADDR *ap, const struct sockaddr *sa) -{ - if (sa->sa_family == AF_INET) { - memcpy(&(ap->s_in), sa, sizeof(struct sockaddr_in)); - return 1; - } -#ifdef AF_INET6 - if (sa->sa_family == AF_INET6) { - memcpy(&(ap->s_in6), sa, sizeof(struct sockaddr_in6)); - return 1; - } -#endif -#ifdef AF_UNIX - if (sa->sa_family == AF_UNIX) { - memcpy(&(ap->s_un), sa, sizeof(struct sockaddr_un)); - return 1; - } -#endif - - return 0; -} - -int BIO_ADDR_rawmake(BIO_ADDR *ap, int family, - const void *where, size_t wherelen, - unsigned short port) -{ -#ifdef AF_UNIX - if (family == AF_UNIX) { - if (wherelen + 1 > sizeof(ap->s_un.sun_path)) - return 0; - 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->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->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 - - return 0; -} - -int BIO_ADDR_family(const BIO_ADDR *ap) -{ - return ap->sa.sa_family; -} - -int BIO_ADDR_rawaddress(const BIO_ADDR *ap, void *p, size_t *l) -{ - size_t len = 0; - const void *addrptr = NULL; - - if (ap->sa.sa_family == AF_INET) { - 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->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->s_un.sun_path); - addrptr = &ap->s_un.sun_path; - } -#endif - - if (addrptr == NULL) - return 0; - - if (p != NULL) { - memcpy(p, addrptr, len); - } - if (l != NULL) - *l = len; - - return 1; -} - -unsigned short BIO_ADDR_rawport(const BIO_ADDR *ap) -{ - if (ap->sa.sa_family == AF_INET) - return ap->s_in.sin_port; -#ifdef AF_INET6 - if (ap->sa.sa_family == AF_INET6) - return ap->s_in6.sin6_port; -#endif - return 0; -} - -/*- - * addr_strings - helper function to get host and service names - * @ap: the BIO_ADDR that has the input info - * @numeric: 0 if actual names should be returned, 1 if the numeric - * representation should be returned. - * @hostname: a pointer to a pointer to a memory area to store the - * host name or numeric representation. Unused if NULL. - * @service: a pointer to a pointer to a memory area to store the - * service name or numeric representation. Unused if NULL. - * - * The return value is 0 on failure, with the error code in the error - * stack, and 1 on success. - */ -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] = ""; - int flags = 0; - - if (numeric) - flags |= NI_NUMERICHOST | NI_NUMERICSERV; - - if ((ret = getnameinfo(BIO_ADDR_sockaddr(ap), - BIO_ADDR_sockaddr_size(ap), - host, sizeof(host), serv, sizeof(serv), - flags)) != 0) { -# ifdef EAI_SYSTEM - if (ret == EAI_SYSTEM) { - SYSerr(SYS_F_GETNAMEINFO, get_last_socket_error()); - BIOerr(BIO_F_ADDR_STRINGS, ERR_R_SYS_LIB); - } else -# endif - { - BIOerr(BIO_F_ADDR_STRINGS, ERR_R_SYS_LIB); - ERR_add_error_data(1, gai_strerror(ret)); - } - 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 != NULL) - *hostname = OPENSSL_strdup(host); - if (service != NULL) - *service = OPENSSL_strdup(serv); - } else { -#endif - if (hostname != NULL) - *hostname = OPENSSL_strdup(inet_ntoa(ap->s_in.sin_addr)); - 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; -} - -char *BIO_ADDR_hostname_string(const BIO_ADDR *ap, int numeric) -{ - char *hostname = NULL; - - if (addr_strings(ap, numeric, &hostname, NULL)) - return hostname; - - return NULL; -} - -char *BIO_ADDR_service_string(const BIO_ADDR *ap, int numeric) -{ - char *service = NULL; - - if (addr_strings(ap, numeric, NULL, &service)) - return service; - - return NULL; -} - -char *BIO_ADDR_path_string(const BIO_ADDR *ap) -{ -#ifdef AF_UNIX - if (ap->sa.sa_family == AF_UNIX) - return OPENSSL_strdup(ap->s_un.sun_path); -#endif - return NULL; -} - -/* - * BIO_ADDR_sockaddr - non-public routine to return the struct sockaddr - * for a given BIO_ADDR. In reality, this is simply a type safe cast. - * The returned struct sockaddr is const, so it can't be tampered with. - */ -const struct sockaddr *BIO_ADDR_sockaddr(const BIO_ADDR *ap) -{ - return &(ap->sa); -} - -/* - * BIO_ADDR_sockaddr_noconst - non-public function that does the same - * as BIO_ADDR_sockaddr, but returns a non-const. USE WITH CARE, as - * it allows you to tamper with the data (and thereby the contents - * of the input BIO_ADDR). - */ -struct sockaddr *BIO_ADDR_sockaddr_noconst(BIO_ADDR *ap) -{ - return &(ap->sa); -} - -/* - * BIO_ADDR_sockaddr_size - non-public function that returns the size - * of the struct sockaddr the BIO_ADDR is using. If the protocol family - * isn't set or is something other than AF_INET, AF_INET6 or AF_UNIX, - * the size of the BIO_ADDR type is returned. - */ -socklen_t BIO_ADDR_sockaddr_size(const BIO_ADDR *ap) -{ - if (ap->sa.sa_family == AF_INET) - return sizeof(ap->s_in); -#ifdef AF_INET6 - if (ap->sa.sa_family == AF_INET6) - return sizeof(ap->s_in6); -#endif -#ifdef AF_UNIX - if (ap->sa.sa_family == AF_UNIX) - return sizeof(ap->s_un); -#endif - return sizeof(*ap); -} - -/********************************************************************** - * - * Address info database - * - */ - -const BIO_ADDRINFO *BIO_ADDRINFO_next(const BIO_ADDRINFO *bai) -{ - if (bai != NULL) - return bai->bai_next; - return NULL; -} - -int BIO_ADDRINFO_family(const BIO_ADDRINFO *bai) -{ - if (bai != NULL) - return bai->bai_family; - return 0; -} - -int BIO_ADDRINFO_socktype(const BIO_ADDRINFO *bai) -{ - if (bai != NULL) - return bai->bai_socktype; - return 0; -} - -int BIO_ADDRINFO_protocol(const BIO_ADDRINFO *bai) -{ - 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; -} - -/* - * BIO_ADDRINFO_sockaddr_size - non-public function that returns the size - * of the struct sockaddr inside the BIO_ADDRINFO. - */ -socklen_t BIO_ADDRINFO_sockaddr_size(const BIO_ADDRINFO *bai) -{ - if (bai != NULL) - return bai->bai_addrlen; - return 0; -} - -/* - * BIO_ADDRINFO_sockaddr - non-public function that returns bai_addr - * as the struct sockaddr it is. - */ -const struct sockaddr *BIO_ADDRINFO_sockaddr(const BIO_ADDRINFO *bai) -{ - if (bai != NULL) - return bai->bai_addr; - return NULL; -} - -const BIO_ADDR *BIO_ADDRINFO_address(const BIO_ADDRINFO *bai) -{ - if (bai != NULL) - return (BIO_ADDR *)bai->bai_addr; - return NULL; -} - -void BIO_ADDRINFO_free(BIO_ADDRINFO *bai) -{ - if (bai == NULL) - return; - -#ifdef AI_PASSIVE -# ifdef AF_UNIX -# define _cond bai->bai_family != AF_UNIX -# else -# define _cond 1 -# endif - if (_cond) { - freeaddrinfo(bai); - return; - } -#endif - - /* Free manually when we know that addrinfo_wrap() was used. - * See further comment above addrinfo_wrap() - */ - while (bai != NULL) { - BIO_ADDRINFO *next = bai->bai_next; - OPENSSL_free(bai->bai_addr); - OPENSSL_free(bai); - bai = next; - } -} - -/********************************************************************** - * - * Service functions - * - */ - -/*- - * The specs in hostserv can take these forms: - * - * host:service => *host = "host", *service = "service" - * host:* => *host = "host", *service = NULL - * host: => *host = "host", *service = NULL - * :service => *host = NULL, *service = "service" - * *:service => *host = NULL, *service = "service" - * - * in case no : is present in the string, the result depends on - * hostserv_prio, as follows: - * - * when hostserv_prio == BIO_PARSE_PRIO_HOST - * host => *host = "host", *service untouched - * - * when hostserv_prio == BIO_PARSE_PRIO_SERV - * service => *host untouched, *service = "service" - * - */ -int BIO_parse_hostserv(const char *hostserv, char **host, char **service, - enum BIO_hostserv_priorities hostserv_prio) -{ - const char *h = NULL; size_t hl = 0; - const char *p = NULL; size_t pl = 0; - - if (*hostserv == '[') { - if ((p = strchr(hostserv, ']')) == NULL) - goto spec_err; - h = hostserv + 1; - hl = p - h; - p++; - if (*p == '\0') - p = NULL; - else if (*p != ':') - goto spec_err; - else { - p++; - pl = strlen(p); - } - } else { - const char *p2 = strrchr(hostserv, ':'); - p = strchr(hostserv, ':'); - - /*- - * Check for more than one colon. There are three possible - * interpretations: - * 1. IPv6 address with port number, last colon being separator. - * 2. IPv6 address only. - * 3. IPv6 address only if hostserv_prio == BIO_PARSE_PRIO_HOST, - * IPv6 address and port number if hostserv_prio == BIO_PARSE_PRIO_SERV - * Because of this ambiguity, we currently choose to make it an - * error. - */ - if (p != p2) - goto amb_err; - - if (p != NULL) { - h = hostserv; - hl = p - h; - p++; - pl = strlen(p); - } else if (hostserv_prio == BIO_PARSE_PRIO_HOST) { - h = hostserv; - hl = strlen(h); - } else { - p = hostserv; - pl = strlen(p); - } - } - - if (p != NULL && strchr(p, ':')) - goto spec_err; - - if (h != NULL && host != NULL) { - if (hl == 0 - || (hl == 1 && h[0] == '*')) { - *host = NULL; - } else { - *host = OPENSSL_strndup(h, hl); - if (*host == NULL) - goto memerr; - } - } - if (p != NULL && service != NULL) { - if (pl == 0 - || (pl == 1 && p[0] == '*')) { - *service = NULL; - } else { - *service = OPENSSL_strndup(p, pl); - if (*service == NULL) - goto memerr; - } - } - - return 1; - amb_err: - BIOerr(BIO_F_BIO_PARSE_HOSTSERV, BIO_R_AMBIGUOUS_HOST_OR_SERVICE); - return 0; - spec_err: - BIOerr(BIO_F_BIO_PARSE_HOSTSERV, BIO_R_MALFORMED_HOST_OR_SERVICE); - return 0; - memerr: - BIOerr(BIO_F_BIO_PARSE_HOSTSERV, ERR_R_MALLOC_FAILURE); - return 0; -} - -/* addrinfo_wrap is used to build our own addrinfo "chain". - * (it has only one entry, so calling it a chain may be a stretch) - * It should ONLY be called when getaddrinfo() and friends - * aren't available, OR when dealing with a non IP protocol - * family, such as AF_UNIX - * - * the return value is 1 on success, or 0 on failure, which - * 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) -{ - 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; - if (socktype == SOCK_STREAM) - (*bai)->bai_protocol = IPPROTO_TCP; - if (socktype == SOCK_DGRAM) - (*bai)->bai_protocol = IPPROTO_UDP; -#ifdef AF_UNIX - if (family == AF_UNIX) - (*bai)->bai_protocol = 0; -#endif - { - /* Magic: We know that BIO_ADDR_sockaddr_noconst is really - just an advanced cast of BIO_ADDR* to struct sockaddr * - by the power of union, so while it may seem that we're - creating a memory leak here, we are not. It will be - all right. */ - BIO_ADDR *addr = BIO_ADDR_new(); - if (addr != NULL) { - BIO_ADDR_rawmake(addr, family, where, wherelen, port); - (*bai)->bai_addr = BIO_ADDR_sockaddr_noconst(addr); - } - } - (*bai)->bai_next = NULL; - if ((*bai)->bai_addr == NULL) { - BIO_ADDRINFO_free(*bai); - *bai = NULL; - return 0; - } - 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_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. - * @family: the address family you want to use. Use AF_UNSPEC for any, or - * 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. - * It returns a linked list of different addresses you can try to connect to. - * - * When no longer needed you should call BIO_ADDRINFO_free() to free the result. - * - * The return value is 1 on success or 0 in case of error. - */ -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 */ - - switch(family) { - case AF_INET: -#ifdef AF_INET6 - case AF_INET6: -#endif -#ifdef AF_UNIX - case AF_UNIX: -#endif -#ifdef AF_UNSPEC - case AF_UNSPEC: -#endif - break; - default: - BIOerr(BIO_F_BIO_LOOKUP_EX, BIO_R_UNSUPPORTED_PROTOCOL_FAMILY); - return 0; - } - -#ifdef AF_UNIX - if (family == AF_UNIX) { - if (addrinfo_wrap(family, socktype, host, strlen(host), 0, res)) - return 1; - else - BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_MALLOC_FAILURE); - return 0; - } -#endif - - if (BIO_sock_init() != 1) - return 0; - - if (1) { -#ifdef AI_PASSIVE + * AI_PASSIVE is used to detect the availability of struct addrinfo, + * getnameinfo() and getaddrinfo(). If that macro doesn't exist, + * we use our own implementation instead, using gethostbyname, + * getservbyname and a few other. + */ + +/********************************************************************** + * + * Address structure + * + */ + +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; +} + +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. + */ +int BIO_ADDR_make(BIO_ADDR *ap, const struct sockaddr *sa) +{ + if (sa->sa_family == AF_INET) { + memcpy(&(ap->s_in), sa, sizeof(struct sockaddr_in)); + return 1; + } +#ifdef AF_INET6 + if (sa->sa_family == AF_INET6) { + memcpy(&(ap->s_in6), sa, sizeof(struct sockaddr_in6)); + return 1; + } +#endif +#ifdef AF_UNIX + if (sa->sa_family == AF_UNIX) { + memcpy(&(ap->s_un), sa, sizeof(struct sockaddr_un)); + return 1; + } +#endif + + return 0; +} + +int BIO_ADDR_rawmake(BIO_ADDR *ap, int family, + const void *where, size_t wherelen, + unsigned short port) +{ +#ifdef AF_UNIX + if (family == AF_UNIX) { + if (wherelen + 1 > sizeof(ap->s_un.sun_path)) + return 0; + 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->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->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 + + return 0; +} + +int BIO_ADDR_family(const BIO_ADDR *ap) +{ + return ap->sa.sa_family; +} + +int BIO_ADDR_rawaddress(const BIO_ADDR *ap, void *p, size_t *l) +{ + size_t len = 0; + const void *addrptr = NULL; + + if (ap->sa.sa_family == AF_INET) { + 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->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->s_un.sun_path); + addrptr = &ap->s_un.sun_path; + } +#endif + + if (addrptr == NULL) + return 0; + + if (p != NULL) { + memcpy(p, addrptr, len); + } + if (l != NULL) + *l = len; + + return 1; +} + +unsigned short BIO_ADDR_rawport(const BIO_ADDR *ap) +{ + if (ap->sa.sa_family == AF_INET) + return ap->s_in.sin_port; +#ifdef AF_INET6 + if (ap->sa.sa_family == AF_INET6) + return ap->s_in6.sin6_port; +#endif + return 0; +} + +/*- + * addr_strings - helper function to get host and service names + * @ap: the BIO_ADDR that has the input info + * @numeric: 0 if actual names should be returned, 1 if the numeric + * representation should be returned. + * @hostname: a pointer to a pointer to a memory area to store the + * host name or numeric representation. Unused if NULL. + * @service: a pointer to a pointer to a memory area to store the + * service name or numeric representation. Unused if NULL. + * + * The return value is 0 on failure, with the error code in the error + * stack, and 1 on success. + */ +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] = ""; + int flags = 0; + + if (numeric) + flags |= NI_NUMERICHOST | NI_NUMERICSERV; + + if ((ret = getnameinfo(BIO_ADDR_sockaddr(ap), + BIO_ADDR_sockaddr_size(ap), + host, sizeof(host), serv, sizeof(serv), + flags)) != 0) { +# ifdef EAI_SYSTEM + if (ret == EAI_SYSTEM) { + SYSerr(SYS_F_GETNAMEINFO, get_last_socket_error()); + BIOerr(BIO_F_ADDR_STRINGS, ERR_R_SYS_LIB); + } else +# endif + { + BIOerr(BIO_F_ADDR_STRINGS, ERR_R_SYS_LIB); + ERR_add_error_data(1, gai_strerror(ret)); + } + 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 != NULL) + *hostname = OPENSSL_strdup(host); + if (service != NULL) + *service = OPENSSL_strdup(serv); + } else { +#endif + if (hostname != NULL) + *hostname = OPENSSL_strdup(inet_ntoa(ap->s_in.sin_addr)); + 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; +} + +char *BIO_ADDR_hostname_string(const BIO_ADDR *ap, int numeric) +{ + char *hostname = NULL; + + if (addr_strings(ap, numeric, &hostname, NULL)) + return hostname; + + return NULL; +} + +char *BIO_ADDR_service_string(const BIO_ADDR *ap, int numeric) +{ + char *service = NULL; + + if (addr_strings(ap, numeric, NULL, &service)) + return service; + + return NULL; +} + +char *BIO_ADDR_path_string(const BIO_ADDR *ap) +{ +#ifdef AF_UNIX + if (ap->sa.sa_family == AF_UNIX) + return OPENSSL_strdup(ap->s_un.sun_path); +#endif + return NULL; +} + +/* + * BIO_ADDR_sockaddr - non-public routine to return the struct sockaddr + * for a given BIO_ADDR. In reality, this is simply a type safe cast. + * The returned struct sockaddr is const, so it can't be tampered with. + */ +const struct sockaddr *BIO_ADDR_sockaddr(const BIO_ADDR *ap) +{ + return &(ap->sa); +} + +/* + * BIO_ADDR_sockaddr_noconst - non-public function that does the same + * as BIO_ADDR_sockaddr, but returns a non-const. USE WITH CARE, as + * it allows you to tamper with the data (and thereby the contents + * of the input BIO_ADDR). + */ +struct sockaddr *BIO_ADDR_sockaddr_noconst(BIO_ADDR *ap) +{ + return &(ap->sa); +} + +/* + * BIO_ADDR_sockaddr_size - non-public function that returns the size + * of the struct sockaddr the BIO_ADDR is using. If the protocol family + * isn't set or is something other than AF_INET, AF_INET6 or AF_UNIX, + * the size of the BIO_ADDR type is returned. + */ +socklen_t BIO_ADDR_sockaddr_size(const BIO_ADDR *ap) +{ + if (ap->sa.sa_family == AF_INET) + return sizeof(ap->s_in); +#ifdef AF_INET6 + if (ap->sa.sa_family == AF_INET6) + return sizeof(ap->s_in6); +#endif +#ifdef AF_UNIX + if (ap->sa.sa_family == AF_UNIX) + return sizeof(ap->s_un); +#endif + return sizeof(*ap); +} + +/********************************************************************** + * + * Address info database + * + */ + +const BIO_ADDRINFO *BIO_ADDRINFO_next(const BIO_ADDRINFO *bai) +{ + if (bai != NULL) + return bai->bai_next; + return NULL; +} + +int BIO_ADDRINFO_family(const BIO_ADDRINFO *bai) +{ + if (bai != NULL) + return bai->bai_family; + return 0; +} + +int BIO_ADDRINFO_socktype(const BIO_ADDRINFO *bai) +{ + if (bai != NULL) + return bai->bai_socktype; + return 0; +} + +int BIO_ADDRINFO_protocol(const BIO_ADDRINFO *bai) +{ + 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; +} + +/* + * BIO_ADDRINFO_sockaddr_size - non-public function that returns the size + * of the struct sockaddr inside the BIO_ADDRINFO. + */ +socklen_t BIO_ADDRINFO_sockaddr_size(const BIO_ADDRINFO *bai) +{ + if (bai != NULL) + return bai->bai_addrlen; + return 0; +} + +/* + * BIO_ADDRINFO_sockaddr - non-public function that returns bai_addr + * as the struct sockaddr it is. + */ +const struct sockaddr *BIO_ADDRINFO_sockaddr(const BIO_ADDRINFO *bai) +{ + if (bai != NULL) + return bai->bai_addr; + return NULL; +} + +const BIO_ADDR *BIO_ADDRINFO_address(const BIO_ADDRINFO *bai) +{ + if (bai != NULL) + return (BIO_ADDR *)bai->bai_addr; + return NULL; +} + +void BIO_ADDRINFO_free(BIO_ADDRINFO *bai) +{ + if (bai == NULL) + return; + +#ifdef AI_PASSIVE +# ifdef AF_UNIX +# define _cond bai->bai_family != AF_UNIX +# else +# define _cond 1 +# endif + if (_cond) { + freeaddrinfo(bai); + return; + } +#endif + + /* Free manually when we know that addrinfo_wrap() was used. + * See further comment above addrinfo_wrap() + */ + while (bai != NULL) { + BIO_ADDRINFO *next = bai->bai_next; + OPENSSL_free(bai->bai_addr); + OPENSSL_free(bai); + bai = next; + } +} + +/********************************************************************** + * + * Service functions + * + */ + +/*- + * The specs in hostserv can take these forms: + * + * host:service => *host = "host", *service = "service" + * host:* => *host = "host", *service = NULL + * host: => *host = "host", *service = NULL + * :service => *host = NULL, *service = "service" + * *:service => *host = NULL, *service = "service" + * + * in case no : is present in the string, the result depends on + * hostserv_prio, as follows: + * + * when hostserv_prio == BIO_PARSE_PRIO_HOST + * host => *host = "host", *service untouched + * + * when hostserv_prio == BIO_PARSE_PRIO_SERV + * service => *host untouched, *service = "service" + * + */ +int BIO_parse_hostserv(const char *hostserv, char **host, char **service, + enum BIO_hostserv_priorities hostserv_prio) +{ + const char *h = NULL; size_t hl = 0; + const char *p = NULL; size_t pl = 0; + + if (*hostserv == '[') { + if ((p = strchr(hostserv, ']')) == NULL) + goto spec_err; + h = hostserv + 1; + hl = p - h; + p++; + if (*p == '\0') + p = NULL; + else if (*p != ':') + goto spec_err; + else { + p++; + pl = strlen(p); + } + } else { + const char *p2 = strrchr(hostserv, ':'); + p = strchr(hostserv, ':'); + + /*- + * Check for more than one colon. There are three possible + * interpretations: + * 1. IPv6 address with port number, last colon being separator. + * 2. IPv6 address only. + * 3. IPv6 address only if hostserv_prio == BIO_PARSE_PRIO_HOST, + * IPv6 address and port number if hostserv_prio == BIO_PARSE_PRIO_SERV + * Because of this ambiguity, we currently choose to make it an + * error. + */ + if (p != p2) + goto amb_err; + + if (p != NULL) { + h = hostserv; + hl = p - h; + p++; + pl = strlen(p); + } else if (hostserv_prio == BIO_PARSE_PRIO_HOST) { + h = hostserv; + hl = strlen(h); + } else { + p = hostserv; + pl = strlen(p); + } + } + + if (p != NULL && strchr(p, ':')) + goto spec_err; + + if (h != NULL && host != NULL) { + if (hl == 0 + || (hl == 1 && h[0] == '*')) { + *host = NULL; + } else { + *host = OPENSSL_strndup(h, hl); + if (*host == NULL) + goto memerr; + } + } + if (p != NULL && service != NULL) { + if (pl == 0 + || (pl == 1 && p[0] == '*')) { + *service = NULL; + } else { + *service = OPENSSL_strndup(p, pl); + if (*service == NULL) + goto memerr; + } + } + + return 1; + amb_err: + BIOerr(BIO_F_BIO_PARSE_HOSTSERV, BIO_R_AMBIGUOUS_HOST_OR_SERVICE); + return 0; + spec_err: + BIOerr(BIO_F_BIO_PARSE_HOSTSERV, BIO_R_MALFORMED_HOST_OR_SERVICE); + return 0; + memerr: + BIOerr(BIO_F_BIO_PARSE_HOSTSERV, ERR_R_MALLOC_FAILURE); + return 0; +} + +/* addrinfo_wrap is used to build our own addrinfo "chain". + * (it has only one entry, so calling it a chain may be a stretch) + * It should ONLY be called when getaddrinfo() and friends + * aren't available, OR when dealing with a non IP protocol + * family, such as AF_UNIX + * + * the return value is 1 on success, or 0 on failure, which + * 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) +{ + 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; + if (socktype == SOCK_STREAM) + (*bai)->bai_protocol = IPPROTO_TCP; + if (socktype == SOCK_DGRAM) + (*bai)->bai_protocol = IPPROTO_UDP; +#ifdef AF_UNIX + if (family == AF_UNIX) + (*bai)->bai_protocol = 0; +#endif + { + /* Magic: We know that BIO_ADDR_sockaddr_noconst is really + just an advanced cast of BIO_ADDR* to struct sockaddr * + by the power of union, so while it may seem that we're + creating a memory leak here, we are not. It will be + all right. */ + BIO_ADDR *addr = BIO_ADDR_new(); + if (addr != NULL) { + BIO_ADDR_rawmake(addr, family, where, wherelen, port); + (*bai)->bai_addr = BIO_ADDR_sockaddr_noconst(addr); + } + } + (*bai)->bai_next = NULL; + if ((*bai)->bai_addr == NULL) { + BIO_ADDRINFO_free(*bai); + *bai = NULL; + return 0; + } + 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_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. + * @family: the address family you want to use. Use AF_UNSPEC for any, or + * 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. + * It returns a linked list of different addresses you can try to connect to. + * + * When no longer needed you should call BIO_ADDRINFO_free() to free the result. + * + * The return value is 1 on success or 0 in case of error. + */ +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 */ + + switch(family) { + case AF_INET: +#ifdef AF_INET6 + case AF_INET6: +#endif +#ifdef AF_UNIX + case AF_UNIX: +#endif +#ifdef AF_UNSPEC + case AF_UNSPEC: +#endif + break; + default: + BIOerr(BIO_F_BIO_LOOKUP_EX, BIO_R_UNSUPPORTED_PROTOCOL_FAMILY); + return 0; + } + +#ifdef AF_UNIX + if (family == AF_UNIX) { + if (addrinfo_wrap(family, socktype, host, strlen(host), 0, res)) + return 1; + else + BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_MALLOC_FAILURE); + return 0; + } +#endif + + if (BIO_sock_init() != 1) + return 0; + + if (1) { +#ifdef AI_PASSIVE int gai_ret = 0, old_ret = 0; - struct addrinfo hints; - - memset(&hints, 0, sizeof(hints)); - - hints.ai_family = family; - hints.ai_socktype = socktype; - hints.ai_protocol = protocol; + struct addrinfo hints; + + memset(&hints, 0, sizeof(hints)); + + hints.ai_family = family; + hints.ai_socktype = socktype; + hints.ai_protocol = protocol; # ifdef AI_ADDRCONFIG # ifdef AF_UNSPEC if (host != NULL && family == AF_UNSPEC) # endif hints.ai_flags |= AI_ADDRCONFIG; # endif - - if (lookup_type == BIO_LOOKUP_SERVER) - hints.ai_flags |= AI_PASSIVE; - - /* Note that |res| SHOULD be a 'struct addrinfo **' thanks to + + if (lookup_type == BIO_LOOKUP_SERVER) + hints.ai_flags |= AI_PASSIVE; + + /* Note that |res| SHOULD be a 'struct addrinfo **' thanks to * macro magic in bio_local.h - */ + */ # if defined(AI_ADDRCONFIG) && defined(AI_NUMERICHOST) retry: # endif - 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_EX, ERR_R_SYS_LIB); - break; -# endif + 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_EX, ERR_R_SYS_LIB); + break; +# endif # ifdef EAI_MEMORY case EAI_MEMORY: BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_MALLOC_FAILURE); break; # endif - case 0: - ret = 1; /* Success */ - break; - default: + case 0: + ret = 1; /* Success */ + break; + default: # if defined(AI_ADDRCONFIG) && defined(AI_NUMERICHOST) if (hints.ai_flags & AI_ADDRCONFIG) { hints.ai_flags &= ~AI_ADDRCONFIG; @@ -727,202 +727,202 @@ int BIO_lookup_ex(const char *host, const char *service, int lookup_type, goto retry; } # endif - BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_SYS_LIB); + BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_SYS_LIB); ERR_add_error_data(1, gai_strerror(old_ret ? old_ret : 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 char *he_fallback_addresses[] = - { (char *)&he_fallback_address, NULL }; -#else - static in_addr_t he_fallback_address; - 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; - /* 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 - - 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; - switch(lookup_type) { - case BIO_LOOKUP_CLIENT: - he_fallback_address = INADDR_LOOPBACK; - break; - case BIO_LOOKUP_SERVER: - he_fallback_address = INADDR_ANY; - break; - default: - /* 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 - /* - * 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 */ - SYSerr(SYS_F_GETHOSTBYNAME, 1000 ); -# else - SYSerr(SYS_F_GETHOSTBYNAME, 1000 + h_errno); -# endif -#else - SYSerr(SYS_F_GETHOSTBYNAME, WSAGetLastError()); -#endif - ret = 0; - goto err; - } - } - - if (service == NULL) { - se_fallback.s_port = 0; - 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((unsigned short)portnum); - se_fallback.s_proto = proto; - se = &se_fallback; - } else if (endp == service) { - se = getservbyname(service, proto); - - if (se == NULL) { -#ifndef OPENSSL_SYS_WINDOWS - SYSerr(SYS_F_GETSERVBYNAME, errno); -#else - SYSerr(SYS_F_GETSERVBYNAME, WSAGetLastError()); -#endif - goto err; - } - } else { - BIOerr(BIO_F_BIO_LOOKUP_EX, BIO_R_MALFORMED_HOST_OR_SERVICE); - goto err; - } - } - - *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; - - /* The easiest way to create a linked list from an - array is to start from the back */ - for(addrlistp = he->h_addr_list; *addrlistp != NULL; - addrlistp++) - ; - - for(addresses = addrlistp - he->h_addr_list; - addrlistp--, addresses-- > 0; ) { - if (!addrinfo_wrap(he->h_addrtype, socktype, - *addrlistp, he->h_length, - se->s_port, &tmp_bai)) - goto addrinfo_malloc_err; - tmp_bai->bai_next = *res; - *res = tmp_bai; - continue; - addrinfo_malloc_err: - BIO_ADDRINFO_free(*res); - *res = NULL; - BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_MALLOC_FAILURE); - ret = 0; - goto err; - } - - ret = 1; - } - err: - CRYPTO_THREAD_unlock(bio_lookup_lock); - } - - return ret; -} - -#endif /* OPENSSL_NO_SOCK */ + 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 char *he_fallback_addresses[] = + { (char *)&he_fallback_address, NULL }; +#else + static in_addr_t he_fallback_address; + 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; + /* 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 + + 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; + switch(lookup_type) { + case BIO_LOOKUP_CLIENT: + he_fallback_address = INADDR_LOOPBACK; + break; + case BIO_LOOKUP_SERVER: + he_fallback_address = INADDR_ANY; + break; + default: + /* 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 + /* + * 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 */ + SYSerr(SYS_F_GETHOSTBYNAME, 1000 ); +# else + SYSerr(SYS_F_GETHOSTBYNAME, 1000 + h_errno); +# endif +#else + SYSerr(SYS_F_GETHOSTBYNAME, WSAGetLastError()); +#endif + ret = 0; + goto err; + } + } + + if (service == NULL) { + se_fallback.s_port = 0; + 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((unsigned short)portnum); + se_fallback.s_proto = proto; + se = &se_fallback; + } else if (endp == service) { + se = getservbyname(service, proto); + + if (se == NULL) { +#ifndef OPENSSL_SYS_WINDOWS + SYSerr(SYS_F_GETSERVBYNAME, errno); +#else + SYSerr(SYS_F_GETSERVBYNAME, WSAGetLastError()); +#endif + goto err; + } + } else { + BIOerr(BIO_F_BIO_LOOKUP_EX, BIO_R_MALFORMED_HOST_OR_SERVICE); + goto err; + } + } + + *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; + + /* The easiest way to create a linked list from an + array is to start from the back */ + for(addrlistp = he->h_addr_list; *addrlistp != NULL; + addrlistp++) + ; + + for(addresses = addrlistp - he->h_addr_list; + addrlistp--, addresses-- > 0; ) { + if (!addrinfo_wrap(he->h_addrtype, socktype, + *addrlistp, he->h_length, + se->s_port, &tmp_bai)) + goto addrinfo_malloc_err; + tmp_bai->bai_next = *res; + *res = tmp_bai; + continue; + addrinfo_malloc_err: + BIO_ADDRINFO_free(*res); + *res = NULL; + BIOerr(BIO_F_BIO_LOOKUP_EX, ERR_R_MALLOC_FAILURE); + ret = 0; + goto err; + } + + ret = 1; + } + err: + CRYPTO_THREAD_unlock(bio_lookup_lock); + } + + return ret; +} + +#endif /* OPENSSL_NO_SOCK */ diff --git a/contrib/libs/openssl/crypto/bio/b_dump.c b/contrib/libs/openssl/crypto/bio/b_dump.c index 9bd61eaeb1..f175e244b2 100644 --- a/contrib/libs/openssl/crypto/bio/b_dump.c +++ b/contrib/libs/openssl/crypto/bio/b_dump.c @@ -1,148 +1,148 @@ -/* - * Copyright 1995-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 - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -/* - * Stolen from tjh's ssl/ssl_trc.c stuff. - */ - -#include <stdio.h> +/* + * Copyright 1995-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 + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Stolen from tjh's ssl/ssl_trc.c stuff. + */ + +#include <stdio.h> #include "bio_local.h" - -#define DUMP_WIDTH 16 -#define DUMP_WIDTH_LESS_INDENT(i) (DUMP_WIDTH - ((i - (i > 6 ? 6 : i) + 3) / 4)) - -#define SPACE(buf, pos, n) (sizeof(buf) - (pos) > (n)) - -int BIO_dump_cb(int (*cb) (const void *data, size_t len, void *u), - void *u, const char *s, int len) -{ - return BIO_dump_indent_cb(cb, u, s, len, 0); -} - -int BIO_dump_indent_cb(int (*cb) (const void *data, size_t len, void *u), - void *u, const char *s, int len, int indent) -{ - int ret = 0; - char buf[288 + 1]; - int i, j, rows, n; - unsigned char ch; - int dump_width; - - if (indent < 0) - indent = 0; + +#define DUMP_WIDTH 16 +#define DUMP_WIDTH_LESS_INDENT(i) (DUMP_WIDTH - ((i - (i > 6 ? 6 : i) + 3) / 4)) + +#define SPACE(buf, pos, n) (sizeof(buf) - (pos) > (n)) + +int BIO_dump_cb(int (*cb) (const void *data, size_t len, void *u), + void *u, const char *s, int len) +{ + return BIO_dump_indent_cb(cb, u, s, len, 0); +} + +int BIO_dump_indent_cb(int (*cb) (const void *data, size_t len, void *u), + void *u, const char *s, int len, int indent) +{ + int ret = 0; + char buf[288 + 1]; + int i, j, rows, n; + unsigned char ch; + int dump_width; + + if (indent < 0) + indent = 0; else if (indent > 64) indent = 64; - - dump_width = DUMP_WIDTH_LESS_INDENT(indent); - rows = len / dump_width; - if ((rows * dump_width) < len) - rows++; - for (i = 0; i < rows; i++) { - n = BIO_snprintf(buf, sizeof(buf), "%*s%04x - ", indent, "", - i * dump_width); - for (j = 0; j < dump_width; j++) { - if (SPACE(buf, n, 3)) { - if (((i * dump_width) + j) >= len) { - strcpy(buf + n, " "); - } else { - ch = ((unsigned char)*(s + i * dump_width + j)) & 0xff; - BIO_snprintf(buf + n, 4, "%02x%c", ch, - j == 7 ? '-' : ' '); - } - n += 3; - } - } - if (SPACE(buf, n, 2)) { - strcpy(buf + n, " "); - n += 2; - } - for (j = 0; j < dump_width; j++) { - if (((i * dump_width) + j) >= len) - break; - if (SPACE(buf, n, 1)) { - ch = ((unsigned char)*(s + i * dump_width + j)) & 0xff; -#ifndef CHARSET_EBCDIC - buf[n++] = ((ch >= ' ') && (ch <= '~')) ? ch : '.'; -#else - buf[n++] = ((ch >= os_toascii[' ']) && (ch <= os_toascii['~'])) - ? os_toebcdic[ch] - : '.'; -#endif - buf[n] = '\0'; - } - } - if (SPACE(buf, n, 1)) { - buf[n++] = '\n'; - buf[n] = '\0'; - } - /* - * if this is the last call then update the ddt_dump thing so that we - * will move the selection point in the debug window - */ - ret += cb((void *)buf, n, u); - } - return ret; -} - -#ifndef OPENSSL_NO_STDIO -static int write_fp(const void *data, size_t len, void *fp) -{ - return UP_fwrite(data, len, 1, fp); -} - -int BIO_dump_fp(FILE *fp, const char *s, int len) -{ - return BIO_dump_cb(write_fp, fp, s, len); -} - -int BIO_dump_indent_fp(FILE *fp, const char *s, int len, int indent) -{ - return BIO_dump_indent_cb(write_fp, fp, s, len, indent); -} -#endif - -static int write_bio(const void *data, size_t len, void *bp) -{ - return BIO_write((BIO *)bp, (const char *)data, len); -} - -int BIO_dump(BIO *bp, const char *s, int len) -{ - return BIO_dump_cb(write_bio, bp, s, len); -} - -int BIO_dump_indent(BIO *bp, const char *s, int len, int indent) -{ - return BIO_dump_indent_cb(write_bio, bp, s, len, indent); -} - -int BIO_hex_string(BIO *out, int indent, int width, unsigned char *data, - int datalen) -{ - int i, j = 0; - - if (datalen < 1) - return 1; - - for (i = 0; i < datalen - 1; i++) { - if (i && !j) - BIO_printf(out, "%*s", indent, ""); - - BIO_printf(out, "%02X:", data[i]); - - j = (j + 1) % width; - if (!j) - BIO_printf(out, "\n"); - } - - if (i && !j) - BIO_printf(out, "%*s", indent, ""); - BIO_printf(out, "%02X", data[datalen - 1]); - return 1; -} + + dump_width = DUMP_WIDTH_LESS_INDENT(indent); + rows = len / dump_width; + if ((rows * dump_width) < len) + rows++; + for (i = 0; i < rows; i++) { + n = BIO_snprintf(buf, sizeof(buf), "%*s%04x - ", indent, "", + i * dump_width); + for (j = 0; j < dump_width; j++) { + if (SPACE(buf, n, 3)) { + if (((i * dump_width) + j) >= len) { + strcpy(buf + n, " "); + } else { + ch = ((unsigned char)*(s + i * dump_width + j)) & 0xff; + BIO_snprintf(buf + n, 4, "%02x%c", ch, + j == 7 ? '-' : ' '); + } + n += 3; + } + } + if (SPACE(buf, n, 2)) { + strcpy(buf + n, " "); + n += 2; + } + for (j = 0; j < dump_width; j++) { + if (((i * dump_width) + j) >= len) + break; + if (SPACE(buf, n, 1)) { + ch = ((unsigned char)*(s + i * dump_width + j)) & 0xff; +#ifndef CHARSET_EBCDIC + buf[n++] = ((ch >= ' ') && (ch <= '~')) ? ch : '.'; +#else + buf[n++] = ((ch >= os_toascii[' ']) && (ch <= os_toascii['~'])) + ? os_toebcdic[ch] + : '.'; +#endif + buf[n] = '\0'; + } + } + if (SPACE(buf, n, 1)) { + buf[n++] = '\n'; + buf[n] = '\0'; + } + /* + * if this is the last call then update the ddt_dump thing so that we + * will move the selection point in the debug window + */ + ret += cb((void *)buf, n, u); + } + return ret; +} + +#ifndef OPENSSL_NO_STDIO +static int write_fp(const void *data, size_t len, void *fp) +{ + return UP_fwrite(data, len, 1, fp); +} + +int BIO_dump_fp(FILE *fp, const char *s, int len) +{ + return BIO_dump_cb(write_fp, fp, s, len); +} + +int BIO_dump_indent_fp(FILE *fp, const char *s, int len, int indent) +{ + return BIO_dump_indent_cb(write_fp, fp, s, len, indent); +} +#endif + +static int write_bio(const void *data, size_t len, void *bp) +{ + return BIO_write((BIO *)bp, (const char *)data, len); +} + +int BIO_dump(BIO *bp, const char *s, int len) +{ + return BIO_dump_cb(write_bio, bp, s, len); +} + +int BIO_dump_indent(BIO *bp, const char *s, int len, int indent) +{ + return BIO_dump_indent_cb(write_bio, bp, s, len, indent); +} + +int BIO_hex_string(BIO *out, int indent, int width, unsigned char *data, + int datalen) +{ + int i, j = 0; + + if (datalen < 1) + return 1; + + for (i = 0; i < datalen - 1; i++) { + if (i && !j) + BIO_printf(out, "%*s", indent, ""); + + BIO_printf(out, "%02X:", data[i]); + + j = (j + 1) % width; + if (!j) + BIO_printf(out, "\n"); + } + + if (i && !j) + BIO_printf(out, "%*s", indent, ""); + BIO_printf(out, "%02X", data[datalen - 1]); + return 1; +} diff --git a/contrib/libs/openssl/crypto/bio/b_print.c b/contrib/libs/openssl/crypto/bio/b_print.c index 49d4e1c473..41b7f5e2f6 100644 --- a/contrib/libs/openssl/crypto/bio/b_print.c +++ b/contrib/libs/openssl/crypto/bio/b_print.c @@ -1,934 +1,934 @@ -/* +/* * Copyright 1995-2020 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 - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -#include <stdio.h> -#include <string.h> -#include "internal/cryptlib.h" + * + * Licensed under the OpenSSL license (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 <stdio.h> +#include <string.h> +#include "internal/cryptlib.h" #include "crypto/ctype.h" -#include "internal/numbers.h" -#include <openssl/bio.h> - -/* - * Copyright Patrick Powell 1995 - * This code is based on code written by Patrick Powell <papowell@astart.com> - * It may be used for any purpose as long as this notice remains intact - * on all source code distributions. - */ - -#ifdef HAVE_LONG_DOUBLE -# define LDOUBLE long double -#else -# define LDOUBLE double -#endif - -static int fmtstr(char **, char **, size_t *, size_t *, - const char *, int, int, int); -static int fmtint(char **, char **, size_t *, size_t *, - int64_t, int, int, int, int); -static int fmtfp(char **, char **, size_t *, size_t *, - LDOUBLE, int, int, int, int); -static int doapr_outch(char **, char **, size_t *, size_t *, int); -static int _dopr(char **sbuffer, char **buffer, - size_t *maxlen, size_t *retlen, int *truncated, - const char *format, va_list args); - -/* format read states */ -#define DP_S_DEFAULT 0 -#define DP_S_FLAGS 1 -#define DP_S_MIN 2 -#define DP_S_DOT 3 -#define DP_S_MAX 4 -#define DP_S_MOD 5 -#define DP_S_CONV 6 -#define DP_S_DONE 7 - -/* format flags - Bits */ -/* left-aligned padding */ -#define DP_F_MINUS (1 << 0) -/* print an explicit '+' for a value with positive sign */ -#define DP_F_PLUS (1 << 1) -/* print an explicit ' ' for a value with positive sign */ -#define DP_F_SPACE (1 << 2) -/* print 0/0x prefix for octal/hex and decimal point for floating point */ -#define DP_F_NUM (1 << 3) -/* print leading zeroes */ -#define DP_F_ZERO (1 << 4) -/* print HEX in UPPPERcase */ -#define DP_F_UP (1 << 5) -/* treat value as unsigned */ -#define DP_F_UNSIGNED (1 << 6) - -/* conversion flags */ -#define DP_C_SHORT 1 -#define DP_C_LONG 2 -#define DP_C_LDOUBLE 3 -#define DP_C_LLONG 4 -#define DP_C_SIZE 5 - -/* Floating point formats */ -#define F_FORMAT 0 -#define E_FORMAT 1 -#define G_FORMAT 2 - -/* some handy macros */ -#define char_to_int(p) (p - '0') -#define OSSL_MAX(p,q) ((p >= q) ? p : q) - -static int -_dopr(char **sbuffer, - char **buffer, - size_t *maxlen, - size_t *retlen, int *truncated, const char *format, va_list args) -{ - char ch; - int64_t value; - LDOUBLE fvalue; - char *strvalue; - int min; - int max; - int state; - int flags; - int cflags; - size_t currlen; - - state = DP_S_DEFAULT; - flags = currlen = cflags = min = 0; - max = -1; - ch = *format++; - - while (state != DP_S_DONE) { - if (ch == '\0' || (buffer == NULL && currlen >= *maxlen)) - state = DP_S_DONE; - - switch (state) { - case DP_S_DEFAULT: - if (ch == '%') - state = DP_S_FLAGS; - else - if (!doapr_outch(sbuffer, buffer, &currlen, maxlen, ch)) - return 0; - ch = *format++; - break; - case DP_S_FLAGS: - switch (ch) { - case '-': - flags |= DP_F_MINUS; - ch = *format++; - break; - case '+': - flags |= DP_F_PLUS; - ch = *format++; - break; - case ' ': - flags |= DP_F_SPACE; - ch = *format++; - break; - case '#': - flags |= DP_F_NUM; - ch = *format++; - break; - case '0': - flags |= DP_F_ZERO; - ch = *format++; - break; - default: - state = DP_S_MIN; - break; - } - break; - case DP_S_MIN: - if (ossl_isdigit(ch)) { - min = 10 * min + char_to_int(ch); - ch = *format++; - } else if (ch == '*') { - min = va_arg(args, int); - ch = *format++; - state = DP_S_DOT; - } else - state = DP_S_DOT; - break; - case DP_S_DOT: - if (ch == '.') { - state = DP_S_MAX; - ch = *format++; - } else - state = DP_S_MOD; - break; - case DP_S_MAX: - if (ossl_isdigit(ch)) { - if (max < 0) - max = 0; - max = 10 * max + char_to_int(ch); - ch = *format++; - } else if (ch == '*') { - max = va_arg(args, int); - ch = *format++; - state = DP_S_MOD; - } else - state = DP_S_MOD; - break; - case DP_S_MOD: - switch (ch) { - case 'h': - cflags = DP_C_SHORT; - ch = *format++; - break; - case 'l': - if (*format == 'l') { - cflags = DP_C_LLONG; - format++; - } else - cflags = DP_C_LONG; - ch = *format++; - break; - case 'q': - case 'j': - cflags = DP_C_LLONG; - ch = *format++; - break; - case 'L': - cflags = DP_C_LDOUBLE; - ch = *format++; - break; - case 'z': - cflags = DP_C_SIZE; - ch = *format++; - break; - default: - break; - } - state = DP_S_CONV; - break; - case DP_S_CONV: - switch (ch) { - case 'd': - case 'i': - switch (cflags) { - case DP_C_SHORT: - value = (short int)va_arg(args, int); - break; - case DP_C_LONG: - value = va_arg(args, long int); - break; - case DP_C_LLONG: - value = va_arg(args, int64_t); - break; - case DP_C_SIZE: - value = va_arg(args, ossl_ssize_t); - break; - default: - value = va_arg(args, int); - break; - } - if (!fmtint(sbuffer, buffer, &currlen, maxlen, value, 10, min, - max, flags)) - return 0; - break; - case 'X': - flags |= DP_F_UP; - /* FALLTHROUGH */ - case 'x': - case 'o': - case 'u': - flags |= DP_F_UNSIGNED; - switch (cflags) { - case DP_C_SHORT: - value = (unsigned short int)va_arg(args, unsigned int); - break; - case DP_C_LONG: - value = va_arg(args, unsigned long int); - break; - case DP_C_LLONG: - value = va_arg(args, uint64_t); - break; - case DP_C_SIZE: - value = va_arg(args, size_t); - break; - default: - value = va_arg(args, unsigned int); - break; - } - if (!fmtint(sbuffer, buffer, &currlen, maxlen, value, - ch == 'o' ? 8 : (ch == 'u' ? 10 : 16), - min, max, flags)) - return 0; - break; - case 'f': - if (cflags == DP_C_LDOUBLE) - fvalue = va_arg(args, LDOUBLE); - else - fvalue = va_arg(args, double); - if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max, - flags, F_FORMAT)) - return 0; - break; - case 'E': - flags |= DP_F_UP; - /* fall thru */ - case 'e': - if (cflags == DP_C_LDOUBLE) - fvalue = va_arg(args, LDOUBLE); - else - fvalue = va_arg(args, double); - if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max, - flags, E_FORMAT)) - return 0; - break; - case 'G': - flags |= DP_F_UP; - /* fall thru */ - case 'g': - if (cflags == DP_C_LDOUBLE) - fvalue = va_arg(args, LDOUBLE); - else - fvalue = va_arg(args, double); - if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max, - flags, G_FORMAT)) - return 0; - break; - case 'c': - if (!doapr_outch(sbuffer, buffer, &currlen, maxlen, - va_arg(args, int))) - return 0; - break; - case 's': - strvalue = va_arg(args, char *); - if (max < 0) { - if (buffer) - max = INT_MAX; - else - max = *maxlen; - } - if (!fmtstr(sbuffer, buffer, &currlen, maxlen, strvalue, - flags, min, max)) - return 0; - break; - case 'p': - value = (size_t)va_arg(args, void *); - if (!fmtint(sbuffer, buffer, &currlen, maxlen, - value, 16, min, max, flags | DP_F_NUM)) - return 0; - break; - case 'n': - { - int *num; - num = va_arg(args, int *); - *num = currlen; - } - break; - case '%': - if (!doapr_outch(sbuffer, buffer, &currlen, maxlen, ch)) - return 0; - break; - case 'w': - /* not supported yet, treat as next char */ - ch = *format++; - break; - default: - /* unknown, skip */ - break; - } - ch = *format++; - state = DP_S_DEFAULT; - flags = cflags = min = 0; - max = -1; - break; - case DP_S_DONE: - break; - default: - break; - } - } - /* - * We have to truncate if there is no dynamic buffer and we have filled the - * static buffer. - */ - if (buffer == NULL) { - *truncated = (currlen > *maxlen - 1); - if (*truncated) - currlen = *maxlen - 1; - } - if (!doapr_outch(sbuffer, buffer, &currlen, maxlen, '\0')) - return 0; - *retlen = currlen - 1; - return 1; -} - -static int -fmtstr(char **sbuffer, - char **buffer, - size_t *currlen, - size_t *maxlen, const char *value, int flags, int min, int max) -{ - int padlen; - size_t strln; - int cnt = 0; - - if (value == 0) - value = "<NULL>"; - - strln = OPENSSL_strnlen(value, max < 0 ? SIZE_MAX : (size_t)max); - - padlen = min - strln; - if (min < 0 || padlen < 0) - padlen = 0; - if (max >= 0) { - /* - * Calculate the maximum output including padding. - * Make sure max doesn't overflow into negativity - */ - if (max < INT_MAX - padlen) - max += padlen; - else - max = INT_MAX; - } - if (flags & DP_F_MINUS) - padlen = -padlen; - - while ((padlen > 0) && (max < 0 || cnt < max)) { - if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' ')) - return 0; - --padlen; - ++cnt; - } - while (strln > 0 && (max < 0 || cnt < max)) { - if (!doapr_outch(sbuffer, buffer, currlen, maxlen, *value++)) - return 0; - --strln; - ++cnt; - } - while ((padlen < 0) && (max < 0 || cnt < max)) { - if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' ')) - return 0; - ++padlen; - ++cnt; - } - return 1; -} - -static int -fmtint(char **sbuffer, - char **buffer, - size_t *currlen, - size_t *maxlen, int64_t value, int base, int min, int max, int flags) -{ - int signvalue = 0; - const char *prefix = ""; - uint64_t uvalue; - char convert[DECIMAL_SIZE(value) + 3]; - int place = 0; - int spadlen = 0; - int zpadlen = 0; - int caps = 0; - - if (max < 0) - max = 0; - uvalue = value; - if (!(flags & DP_F_UNSIGNED)) { - if (value < 0) { - signvalue = '-'; - uvalue = 0 - (uint64_t)value; - } else if (flags & DP_F_PLUS) - signvalue = '+'; - else if (flags & DP_F_SPACE) - signvalue = ' '; - } - if (flags & DP_F_NUM) { - if (base == 8) - prefix = "0"; - if (base == 16) - prefix = "0x"; - } - if (flags & DP_F_UP) - caps = 1; - do { - convert[place++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef") - [uvalue % (unsigned)base]; - uvalue = (uvalue / (unsigned)base); - } while (uvalue && (place < (int)sizeof(convert))); - if (place == sizeof(convert)) - place--; - convert[place] = 0; - - zpadlen = max - place; - spadlen = - min - OSSL_MAX(max, place) - (signvalue ? 1 : 0) - strlen(prefix); - if (zpadlen < 0) - zpadlen = 0; - if (spadlen < 0) - spadlen = 0; - if (flags & DP_F_ZERO) { - zpadlen = OSSL_MAX(zpadlen, spadlen); - spadlen = 0; - } - if (flags & DP_F_MINUS) - spadlen = -spadlen; - - /* spaces */ - while (spadlen > 0) { - if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' ')) - return 0; - --spadlen; - } - - /* sign */ - if (signvalue) - if (!doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue)) - return 0; - - /* prefix */ - while (*prefix) { - if (!doapr_outch(sbuffer, buffer, currlen, maxlen, *prefix)) - return 0; - prefix++; - } - - /* zeros */ - if (zpadlen > 0) { - while (zpadlen > 0) { - if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0')) - return 0; - --zpadlen; - } - } - /* digits */ - while (place > 0) { - if (!doapr_outch(sbuffer, buffer, currlen, maxlen, convert[--place])) - return 0; - } - - /* left justified spaces */ - while (spadlen < 0) { - if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' ')) - return 0; - ++spadlen; - } - return 1; -} - -static LDOUBLE abs_val(LDOUBLE value) -{ - LDOUBLE result = value; - if (value < 0) - result = -value; - return result; -} - -static LDOUBLE pow_10(int in_exp) -{ - LDOUBLE result = 1; - while (in_exp) { - result *= 10; - in_exp--; - } - return result; -} - -static long roundv(LDOUBLE value) -{ - long intpart; - intpart = (long)value; - value = value - intpart; - if (value >= 0.5) - intpart++; - return intpart; -} - -static int -fmtfp(char **sbuffer, - char **buffer, - size_t *currlen, - size_t *maxlen, LDOUBLE fvalue, int min, int max, int flags, int style) -{ - int signvalue = 0; - LDOUBLE ufvalue; - LDOUBLE tmpvalue; - char iconvert[20]; - char fconvert[20]; - char econvert[20]; - int iplace = 0; - int fplace = 0; - int eplace = 0; - int padlen = 0; - int zpadlen = 0; - long exp = 0; - unsigned long intpart; - unsigned long fracpart; - unsigned long max10; - int realstyle; - - if (max < 0) - max = 6; - - if (fvalue < 0) - signvalue = '-'; - else if (flags & DP_F_PLUS) - signvalue = '+'; - else if (flags & DP_F_SPACE) - signvalue = ' '; - - /* - * G_FORMAT sometimes prints like E_FORMAT and sometimes like F_FORMAT - * depending on the number to be printed. Work out which one it is and use - * that from here on. - */ - if (style == G_FORMAT) { - if (fvalue == 0.0) { - realstyle = F_FORMAT; - } else if (fvalue < 0.0001) { - realstyle = E_FORMAT; - } else if ((max == 0 && fvalue >= 10) - || (max > 0 && fvalue >= pow_10(max))) { - realstyle = E_FORMAT; - } else { - realstyle = F_FORMAT; - } - } else { - realstyle = style; - } - - if (style != F_FORMAT) { - tmpvalue = fvalue; - /* Calculate the exponent */ - if (fvalue != 0.0) { - while (tmpvalue < 1) { - tmpvalue *= 10; - exp--; - } - while (tmpvalue > 10) { - tmpvalue /= 10; - exp++; - } - } - if (style == G_FORMAT) { - /* - * In G_FORMAT the "precision" represents significant digits. We - * always have at least 1 significant digit. - */ - if (max == 0) - max = 1; - /* Now convert significant digits to decimal places */ - if (realstyle == F_FORMAT) { - max -= (exp + 1); - if (max < 0) { - /* - * Should not happen. If we're in F_FORMAT then exp < max? - */ - return 0; - } - } else { - /* - * In E_FORMAT there is always one significant digit in front - * of the decimal point, so: - * significant digits == 1 + decimal places - */ - max--; - } - } - if (realstyle == E_FORMAT) - fvalue = tmpvalue; - } - ufvalue = abs_val(fvalue); +#include "internal/numbers.h" +#include <openssl/bio.h> + +/* + * Copyright Patrick Powell 1995 + * This code is based on code written by Patrick Powell <papowell@astart.com> + * It may be used for any purpose as long as this notice remains intact + * on all source code distributions. + */ + +#ifdef HAVE_LONG_DOUBLE +# define LDOUBLE long double +#else +# define LDOUBLE double +#endif + +static int fmtstr(char **, char **, size_t *, size_t *, + const char *, int, int, int); +static int fmtint(char **, char **, size_t *, size_t *, + int64_t, int, int, int, int); +static int fmtfp(char **, char **, size_t *, size_t *, + LDOUBLE, int, int, int, int); +static int doapr_outch(char **, char **, size_t *, size_t *, int); +static int _dopr(char **sbuffer, char **buffer, + size_t *maxlen, size_t *retlen, int *truncated, + const char *format, va_list args); + +/* format read states */ +#define DP_S_DEFAULT 0 +#define DP_S_FLAGS 1 +#define DP_S_MIN 2 +#define DP_S_DOT 3 +#define DP_S_MAX 4 +#define DP_S_MOD 5 +#define DP_S_CONV 6 +#define DP_S_DONE 7 + +/* format flags - Bits */ +/* left-aligned padding */ +#define DP_F_MINUS (1 << 0) +/* print an explicit '+' for a value with positive sign */ +#define DP_F_PLUS (1 << 1) +/* print an explicit ' ' for a value with positive sign */ +#define DP_F_SPACE (1 << 2) +/* print 0/0x prefix for octal/hex and decimal point for floating point */ +#define DP_F_NUM (1 << 3) +/* print leading zeroes */ +#define DP_F_ZERO (1 << 4) +/* print HEX in UPPPERcase */ +#define DP_F_UP (1 << 5) +/* treat value as unsigned */ +#define DP_F_UNSIGNED (1 << 6) + +/* conversion flags */ +#define DP_C_SHORT 1 +#define DP_C_LONG 2 +#define DP_C_LDOUBLE 3 +#define DP_C_LLONG 4 +#define DP_C_SIZE 5 + +/* Floating point formats */ +#define F_FORMAT 0 +#define E_FORMAT 1 +#define G_FORMAT 2 + +/* some handy macros */ +#define char_to_int(p) (p - '0') +#define OSSL_MAX(p,q) ((p >= q) ? p : q) + +static int +_dopr(char **sbuffer, + char **buffer, + size_t *maxlen, + size_t *retlen, int *truncated, const char *format, va_list args) +{ + char ch; + int64_t value; + LDOUBLE fvalue; + char *strvalue; + int min; + int max; + int state; + int flags; + int cflags; + size_t currlen; + + state = DP_S_DEFAULT; + flags = currlen = cflags = min = 0; + max = -1; + ch = *format++; + + while (state != DP_S_DONE) { + if (ch == '\0' || (buffer == NULL && currlen >= *maxlen)) + state = DP_S_DONE; + + switch (state) { + case DP_S_DEFAULT: + if (ch == '%') + state = DP_S_FLAGS; + else + if (!doapr_outch(sbuffer, buffer, &currlen, maxlen, ch)) + return 0; + ch = *format++; + break; + case DP_S_FLAGS: + switch (ch) { + case '-': + flags |= DP_F_MINUS; + ch = *format++; + break; + case '+': + flags |= DP_F_PLUS; + ch = *format++; + break; + case ' ': + flags |= DP_F_SPACE; + ch = *format++; + break; + case '#': + flags |= DP_F_NUM; + ch = *format++; + break; + case '0': + flags |= DP_F_ZERO; + ch = *format++; + break; + default: + state = DP_S_MIN; + break; + } + break; + case DP_S_MIN: + if (ossl_isdigit(ch)) { + min = 10 * min + char_to_int(ch); + ch = *format++; + } else if (ch == '*') { + min = va_arg(args, int); + ch = *format++; + state = DP_S_DOT; + } else + state = DP_S_DOT; + break; + case DP_S_DOT: + if (ch == '.') { + state = DP_S_MAX; + ch = *format++; + } else + state = DP_S_MOD; + break; + case DP_S_MAX: + if (ossl_isdigit(ch)) { + if (max < 0) + max = 0; + max = 10 * max + char_to_int(ch); + ch = *format++; + } else if (ch == '*') { + max = va_arg(args, int); + ch = *format++; + state = DP_S_MOD; + } else + state = DP_S_MOD; + break; + case DP_S_MOD: + switch (ch) { + case 'h': + cflags = DP_C_SHORT; + ch = *format++; + break; + case 'l': + if (*format == 'l') { + cflags = DP_C_LLONG; + format++; + } else + cflags = DP_C_LONG; + ch = *format++; + break; + case 'q': + case 'j': + cflags = DP_C_LLONG; + ch = *format++; + break; + case 'L': + cflags = DP_C_LDOUBLE; + ch = *format++; + break; + case 'z': + cflags = DP_C_SIZE; + ch = *format++; + break; + default: + break; + } + state = DP_S_CONV; + break; + case DP_S_CONV: + switch (ch) { + case 'd': + case 'i': + switch (cflags) { + case DP_C_SHORT: + value = (short int)va_arg(args, int); + break; + case DP_C_LONG: + value = va_arg(args, long int); + break; + case DP_C_LLONG: + value = va_arg(args, int64_t); + break; + case DP_C_SIZE: + value = va_arg(args, ossl_ssize_t); + break; + default: + value = va_arg(args, int); + break; + } + if (!fmtint(sbuffer, buffer, &currlen, maxlen, value, 10, min, + max, flags)) + return 0; + break; + case 'X': + flags |= DP_F_UP; + /* FALLTHROUGH */ + case 'x': + case 'o': + case 'u': + flags |= DP_F_UNSIGNED; + switch (cflags) { + case DP_C_SHORT: + value = (unsigned short int)va_arg(args, unsigned int); + break; + case DP_C_LONG: + value = va_arg(args, unsigned long int); + break; + case DP_C_LLONG: + value = va_arg(args, uint64_t); + break; + case DP_C_SIZE: + value = va_arg(args, size_t); + break; + default: + value = va_arg(args, unsigned int); + break; + } + if (!fmtint(sbuffer, buffer, &currlen, maxlen, value, + ch == 'o' ? 8 : (ch == 'u' ? 10 : 16), + min, max, flags)) + return 0; + break; + case 'f': + if (cflags == DP_C_LDOUBLE) + fvalue = va_arg(args, LDOUBLE); + else + fvalue = va_arg(args, double); + if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max, + flags, F_FORMAT)) + return 0; + break; + case 'E': + flags |= DP_F_UP; + /* fall thru */ + case 'e': + if (cflags == DP_C_LDOUBLE) + fvalue = va_arg(args, LDOUBLE); + else + fvalue = va_arg(args, double); + if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max, + flags, E_FORMAT)) + return 0; + break; + case 'G': + flags |= DP_F_UP; + /* fall thru */ + case 'g': + if (cflags == DP_C_LDOUBLE) + fvalue = va_arg(args, LDOUBLE); + else + fvalue = va_arg(args, double); + if (!fmtfp(sbuffer, buffer, &currlen, maxlen, fvalue, min, max, + flags, G_FORMAT)) + return 0; + break; + case 'c': + if (!doapr_outch(sbuffer, buffer, &currlen, maxlen, + va_arg(args, int))) + return 0; + break; + case 's': + strvalue = va_arg(args, char *); + if (max < 0) { + if (buffer) + max = INT_MAX; + else + max = *maxlen; + } + if (!fmtstr(sbuffer, buffer, &currlen, maxlen, strvalue, + flags, min, max)) + return 0; + break; + case 'p': + value = (size_t)va_arg(args, void *); + if (!fmtint(sbuffer, buffer, &currlen, maxlen, + value, 16, min, max, flags | DP_F_NUM)) + return 0; + break; + case 'n': + { + int *num; + num = va_arg(args, int *); + *num = currlen; + } + break; + case '%': + if (!doapr_outch(sbuffer, buffer, &currlen, maxlen, ch)) + return 0; + break; + case 'w': + /* not supported yet, treat as next char */ + ch = *format++; + break; + default: + /* unknown, skip */ + break; + } + ch = *format++; + state = DP_S_DEFAULT; + flags = cflags = min = 0; + max = -1; + break; + case DP_S_DONE: + break; + default: + break; + } + } + /* + * We have to truncate if there is no dynamic buffer and we have filled the + * static buffer. + */ + if (buffer == NULL) { + *truncated = (currlen > *maxlen - 1); + if (*truncated) + currlen = *maxlen - 1; + } + if (!doapr_outch(sbuffer, buffer, &currlen, maxlen, '\0')) + return 0; + *retlen = currlen - 1; + return 1; +} + +static int +fmtstr(char **sbuffer, + char **buffer, + size_t *currlen, + size_t *maxlen, const char *value, int flags, int min, int max) +{ + int padlen; + size_t strln; + int cnt = 0; + + if (value == 0) + value = "<NULL>"; + + strln = OPENSSL_strnlen(value, max < 0 ? SIZE_MAX : (size_t)max); + + padlen = min - strln; + if (min < 0 || padlen < 0) + padlen = 0; + if (max >= 0) { + /* + * Calculate the maximum output including padding. + * Make sure max doesn't overflow into negativity + */ + if (max < INT_MAX - padlen) + max += padlen; + else + max = INT_MAX; + } + if (flags & DP_F_MINUS) + padlen = -padlen; + + while ((padlen > 0) && (max < 0 || cnt < max)) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' ')) + return 0; + --padlen; + ++cnt; + } + while (strln > 0 && (max < 0 || cnt < max)) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, *value++)) + return 0; + --strln; + ++cnt; + } + while ((padlen < 0) && (max < 0 || cnt < max)) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' ')) + return 0; + ++padlen; + ++cnt; + } + return 1; +} + +static int +fmtint(char **sbuffer, + char **buffer, + size_t *currlen, + size_t *maxlen, int64_t value, int base, int min, int max, int flags) +{ + int signvalue = 0; + const char *prefix = ""; + uint64_t uvalue; + char convert[DECIMAL_SIZE(value) + 3]; + int place = 0; + int spadlen = 0; + int zpadlen = 0; + int caps = 0; + + if (max < 0) + max = 0; + uvalue = value; + if (!(flags & DP_F_UNSIGNED)) { + if (value < 0) { + signvalue = '-'; + uvalue = 0 - (uint64_t)value; + } else if (flags & DP_F_PLUS) + signvalue = '+'; + else if (flags & DP_F_SPACE) + signvalue = ' '; + } + if (flags & DP_F_NUM) { + if (base == 8) + prefix = "0"; + if (base == 16) + prefix = "0x"; + } + if (flags & DP_F_UP) + caps = 1; + do { + convert[place++] = (caps ? "0123456789ABCDEF" : "0123456789abcdef") + [uvalue % (unsigned)base]; + uvalue = (uvalue / (unsigned)base); + } while (uvalue && (place < (int)sizeof(convert))); + if (place == sizeof(convert)) + place--; + convert[place] = 0; + + zpadlen = max - place; + spadlen = + min - OSSL_MAX(max, place) - (signvalue ? 1 : 0) - strlen(prefix); + if (zpadlen < 0) + zpadlen = 0; + if (spadlen < 0) + spadlen = 0; + if (flags & DP_F_ZERO) { + zpadlen = OSSL_MAX(zpadlen, spadlen); + spadlen = 0; + } + if (flags & DP_F_MINUS) + spadlen = -spadlen; + + /* spaces */ + while (spadlen > 0) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' ')) + return 0; + --spadlen; + } + + /* sign */ + if (signvalue) + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue)) + return 0; + + /* prefix */ + while (*prefix) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, *prefix)) + return 0; + prefix++; + } + + /* zeros */ + if (zpadlen > 0) { + while (zpadlen > 0) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0')) + return 0; + --zpadlen; + } + } + /* digits */ + while (place > 0) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, convert[--place])) + return 0; + } + + /* left justified spaces */ + while (spadlen < 0) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' ')) + return 0; + ++spadlen; + } + return 1; +} + +static LDOUBLE abs_val(LDOUBLE value) +{ + LDOUBLE result = value; + if (value < 0) + result = -value; + return result; +} + +static LDOUBLE pow_10(int in_exp) +{ + LDOUBLE result = 1; + while (in_exp) { + result *= 10; + in_exp--; + } + return result; +} + +static long roundv(LDOUBLE value) +{ + long intpart; + intpart = (long)value; + value = value - intpart; + if (value >= 0.5) + intpart++; + return intpart; +} + +static int +fmtfp(char **sbuffer, + char **buffer, + size_t *currlen, + size_t *maxlen, LDOUBLE fvalue, int min, int max, int flags, int style) +{ + int signvalue = 0; + LDOUBLE ufvalue; + LDOUBLE tmpvalue; + char iconvert[20]; + char fconvert[20]; + char econvert[20]; + int iplace = 0; + int fplace = 0; + int eplace = 0; + int padlen = 0; + int zpadlen = 0; + long exp = 0; + unsigned long intpart; + unsigned long fracpart; + unsigned long max10; + int realstyle; + + if (max < 0) + max = 6; + + if (fvalue < 0) + signvalue = '-'; + else if (flags & DP_F_PLUS) + signvalue = '+'; + else if (flags & DP_F_SPACE) + signvalue = ' '; + + /* + * G_FORMAT sometimes prints like E_FORMAT and sometimes like F_FORMAT + * depending on the number to be printed. Work out which one it is and use + * that from here on. + */ + if (style == G_FORMAT) { + if (fvalue == 0.0) { + realstyle = F_FORMAT; + } else if (fvalue < 0.0001) { + realstyle = E_FORMAT; + } else if ((max == 0 && fvalue >= 10) + || (max > 0 && fvalue >= pow_10(max))) { + realstyle = E_FORMAT; + } else { + realstyle = F_FORMAT; + } + } else { + realstyle = style; + } + + if (style != F_FORMAT) { + tmpvalue = fvalue; + /* Calculate the exponent */ + if (fvalue != 0.0) { + while (tmpvalue < 1) { + tmpvalue *= 10; + exp--; + } + while (tmpvalue > 10) { + tmpvalue /= 10; + exp++; + } + } + if (style == G_FORMAT) { + /* + * In G_FORMAT the "precision" represents significant digits. We + * always have at least 1 significant digit. + */ + if (max == 0) + max = 1; + /* Now convert significant digits to decimal places */ + if (realstyle == F_FORMAT) { + max -= (exp + 1); + if (max < 0) { + /* + * Should not happen. If we're in F_FORMAT then exp < max? + */ + return 0; + } + } else { + /* + * In E_FORMAT there is always one significant digit in front + * of the decimal point, so: + * significant digits == 1 + decimal places + */ + max--; + } + } + if (realstyle == E_FORMAT) + fvalue = tmpvalue; + } + ufvalue = abs_val(fvalue); /* * By subtracting 65535 (2^16-1) we cancel the low order 15 bits * of ULONG_MAX to avoid using imprecise floating point values. */ if (ufvalue >= (double)(ULONG_MAX - 65535) + 65536.0) { - /* Number too big */ - return 0; - } - intpart = (unsigned long)ufvalue; - - /* - * sorry, we only support 9 digits past the decimal because of our - * conversion method - */ - if (max > 9) - max = 9; - - /* - * we "cheat" by converting the fractional part to integer by multiplying - * by a factor of 10 - */ - max10 = roundv(pow_10(max)); - fracpart = roundv(pow_10(max) * (ufvalue - intpart)); - - if (fracpart >= max10) { - intpart++; - fracpart -= max10; - } - - /* convert integer part */ - do { - iconvert[iplace++] = "0123456789"[intpart % 10]; - intpart = (intpart / 10); - } while (intpart && (iplace < (int)sizeof(iconvert))); - if (iplace == sizeof(iconvert)) - iplace--; - iconvert[iplace] = 0; - - /* convert fractional part */ - while (fplace < max) { - if (style == G_FORMAT && fplace == 0 && (fracpart % 10) == 0) { - /* We strip trailing zeros in G_FORMAT */ - max--; - fracpart = fracpart / 10; - if (fplace < max) - continue; - break; - } - fconvert[fplace++] = "0123456789"[fracpart % 10]; - fracpart = (fracpart / 10); - } - - if (fplace == sizeof(fconvert)) - fplace--; - fconvert[fplace] = 0; - - /* convert exponent part */ - if (realstyle == E_FORMAT) { - int tmpexp; - if (exp < 0) - tmpexp = -exp; - else - tmpexp = exp; - - do { - econvert[eplace++] = "0123456789"[tmpexp % 10]; - tmpexp = (tmpexp / 10); - } while (tmpexp > 0 && eplace < (int)sizeof(econvert)); - /* Exponent is huge!! Too big to print */ - if (tmpexp > 0) - return 0; - /* Add a leading 0 for single digit exponents */ - if (eplace == 1) - econvert[eplace++] = '0'; - } - - /* - * -1 for decimal point (if we have one, i.e. max > 0), - * another -1 if we are printing a sign - */ - padlen = min - iplace - max - (max > 0 ? 1 : 0) - ((signvalue) ? 1 : 0); - /* Take some off for exponent prefix "+e" and exponent */ - if (realstyle == E_FORMAT) - padlen -= 2 + eplace; - zpadlen = max - fplace; - if (zpadlen < 0) - zpadlen = 0; - if (padlen < 0) - padlen = 0; - if (flags & DP_F_MINUS) - padlen = -padlen; - - if ((flags & DP_F_ZERO) && (padlen > 0)) { - if (signvalue) { - if (!doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue)) - return 0; - --padlen; - signvalue = 0; - } - while (padlen > 0) { - if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0')) - return 0; - --padlen; - } - } - while (padlen > 0) { - if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' ')) - return 0; - --padlen; - } - if (signvalue && !doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue)) - return 0; - - while (iplace > 0) { - if (!doapr_outch(sbuffer, buffer, currlen, maxlen, iconvert[--iplace])) - return 0; - } - - /* - * Decimal point. This should probably use locale to find the correct - * char to print out. - */ - if (max > 0 || (flags & DP_F_NUM)) { - if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '.')) - return 0; - - while (fplace > 0) { - if (!doapr_outch(sbuffer, buffer, currlen, maxlen, - fconvert[--fplace])) - return 0; - } - } - while (zpadlen > 0) { - if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0')) - return 0; - --zpadlen; - } - if (realstyle == E_FORMAT) { - char ech; - - if ((flags & DP_F_UP) == 0) - ech = 'e'; - else - ech = 'E'; - if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ech)) - return 0; - if (exp < 0) { - if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '-')) - return 0; - } else { - if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '+')) - return 0; - } - while (eplace > 0) { - if (!doapr_outch(sbuffer, buffer, currlen, maxlen, - econvert[--eplace])) - return 0; - } - } - - while (padlen < 0) { - if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' ')) - return 0; - ++padlen; - } - return 1; -} - -#define BUFFER_INC 1024 - -static int -doapr_outch(char **sbuffer, - char **buffer, size_t *currlen, size_t *maxlen, int c) -{ - /* If we haven't at least one buffer, someone has done a big booboo */ - if (!ossl_assert(*sbuffer != NULL || buffer != NULL)) - return 0; - - /* |currlen| must always be <= |*maxlen| */ - if (!ossl_assert(*currlen <= *maxlen)) - return 0; - - if (buffer && *currlen == *maxlen) { - if (*maxlen > INT_MAX - BUFFER_INC) - return 0; - - *maxlen += BUFFER_INC; - if (*buffer == NULL) { - if ((*buffer = OPENSSL_malloc(*maxlen)) == NULL) { - BIOerr(BIO_F_DOAPR_OUTCH, ERR_R_MALLOC_FAILURE); - return 0; - } - if (*currlen > 0) { - if (!ossl_assert(*sbuffer != NULL)) - return 0; - memcpy(*buffer, *sbuffer, *currlen); - } - *sbuffer = NULL; - } else { - char *tmpbuf; - tmpbuf = OPENSSL_realloc(*buffer, *maxlen); - if (tmpbuf == NULL) - return 0; - *buffer = tmpbuf; - } - } - - if (*currlen < *maxlen) { - if (*sbuffer) - (*sbuffer)[(*currlen)++] = (char)c; - else - (*buffer)[(*currlen)++] = (char)c; - } - - return 1; -} - -/***************************************************************************/ - -int BIO_printf(BIO *bio, const char *format, ...) -{ - va_list args; - int ret; - - va_start(args, format); - - ret = BIO_vprintf(bio, format, args); - - va_end(args); - return ret; -} - -int BIO_vprintf(BIO *bio, const char *format, va_list args) -{ - int ret; - size_t retlen; - char hugebuf[1024 * 2]; /* Was previously 10k, which is unreasonable - * in small-stack environments, like threads - * or DOS programs. */ - char *hugebufp = hugebuf; - size_t hugebufsize = sizeof(hugebuf); - char *dynbuf = NULL; - int ignored; - - dynbuf = NULL; - if (!_dopr(&hugebufp, &dynbuf, &hugebufsize, &retlen, &ignored, format, - args)) { - OPENSSL_free(dynbuf); - return -1; - } - if (dynbuf) { - ret = BIO_write(bio, dynbuf, (int)retlen); - OPENSSL_free(dynbuf); - } else { - ret = BIO_write(bio, hugebuf, (int)retlen); - } - return ret; -} - -/* - * As snprintf is not available everywhere, we provide our own - * implementation. This function has nothing to do with BIOs, but it's - * closely related to BIO_printf, and we need *some* name prefix ... (XXX the - * function should be renamed, but to what?) - */ -int BIO_snprintf(char *buf, size_t n, const char *format, ...) -{ - va_list args; - int ret; - - va_start(args, format); - - ret = BIO_vsnprintf(buf, n, format, args); - - va_end(args); - return ret; -} - -int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args) -{ - size_t retlen; - int truncated; - - if (!_dopr(&buf, NULL, &n, &retlen, &truncated, format, args)) - return -1; - - if (truncated) - /* - * In case of truncation, return -1 like traditional snprintf. - * (Current drafts for ISO/IEC 9899 say snprintf should return the - * number of characters that would have been written, had the buffer - * been large enough.) - */ - return -1; - else - return (retlen <= INT_MAX) ? (int)retlen : -1; -} + /* Number too big */ + return 0; + } + intpart = (unsigned long)ufvalue; + + /* + * sorry, we only support 9 digits past the decimal because of our + * conversion method + */ + if (max > 9) + max = 9; + + /* + * we "cheat" by converting the fractional part to integer by multiplying + * by a factor of 10 + */ + max10 = roundv(pow_10(max)); + fracpart = roundv(pow_10(max) * (ufvalue - intpart)); + + if (fracpart >= max10) { + intpart++; + fracpart -= max10; + } + + /* convert integer part */ + do { + iconvert[iplace++] = "0123456789"[intpart % 10]; + intpart = (intpart / 10); + } while (intpart && (iplace < (int)sizeof(iconvert))); + if (iplace == sizeof(iconvert)) + iplace--; + iconvert[iplace] = 0; + + /* convert fractional part */ + while (fplace < max) { + if (style == G_FORMAT && fplace == 0 && (fracpart % 10) == 0) { + /* We strip trailing zeros in G_FORMAT */ + max--; + fracpart = fracpart / 10; + if (fplace < max) + continue; + break; + } + fconvert[fplace++] = "0123456789"[fracpart % 10]; + fracpart = (fracpart / 10); + } + + if (fplace == sizeof(fconvert)) + fplace--; + fconvert[fplace] = 0; + + /* convert exponent part */ + if (realstyle == E_FORMAT) { + int tmpexp; + if (exp < 0) + tmpexp = -exp; + else + tmpexp = exp; + + do { + econvert[eplace++] = "0123456789"[tmpexp % 10]; + tmpexp = (tmpexp / 10); + } while (tmpexp > 0 && eplace < (int)sizeof(econvert)); + /* Exponent is huge!! Too big to print */ + if (tmpexp > 0) + return 0; + /* Add a leading 0 for single digit exponents */ + if (eplace == 1) + econvert[eplace++] = '0'; + } + + /* + * -1 for decimal point (if we have one, i.e. max > 0), + * another -1 if we are printing a sign + */ + padlen = min - iplace - max - (max > 0 ? 1 : 0) - ((signvalue) ? 1 : 0); + /* Take some off for exponent prefix "+e" and exponent */ + if (realstyle == E_FORMAT) + padlen -= 2 + eplace; + zpadlen = max - fplace; + if (zpadlen < 0) + zpadlen = 0; + if (padlen < 0) + padlen = 0; + if (flags & DP_F_MINUS) + padlen = -padlen; + + if ((flags & DP_F_ZERO) && (padlen > 0)) { + if (signvalue) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue)) + return 0; + --padlen; + signvalue = 0; + } + while (padlen > 0) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0')) + return 0; + --padlen; + } + } + while (padlen > 0) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' ')) + return 0; + --padlen; + } + if (signvalue && !doapr_outch(sbuffer, buffer, currlen, maxlen, signvalue)) + return 0; + + while (iplace > 0) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, iconvert[--iplace])) + return 0; + } + + /* + * Decimal point. This should probably use locale to find the correct + * char to print out. + */ + if (max > 0 || (flags & DP_F_NUM)) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '.')) + return 0; + + while (fplace > 0) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, + fconvert[--fplace])) + return 0; + } + } + while (zpadlen > 0) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '0')) + return 0; + --zpadlen; + } + if (realstyle == E_FORMAT) { + char ech; + + if ((flags & DP_F_UP) == 0) + ech = 'e'; + else + ech = 'E'; + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ech)) + return 0; + if (exp < 0) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '-')) + return 0; + } else { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, '+')) + return 0; + } + while (eplace > 0) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, + econvert[--eplace])) + return 0; + } + } + + while (padlen < 0) { + if (!doapr_outch(sbuffer, buffer, currlen, maxlen, ' ')) + return 0; + ++padlen; + } + return 1; +} + +#define BUFFER_INC 1024 + +static int +doapr_outch(char **sbuffer, + char **buffer, size_t *currlen, size_t *maxlen, int c) +{ + /* If we haven't at least one buffer, someone has done a big booboo */ + if (!ossl_assert(*sbuffer != NULL || buffer != NULL)) + return 0; + + /* |currlen| must always be <= |*maxlen| */ + if (!ossl_assert(*currlen <= *maxlen)) + return 0; + + if (buffer && *currlen == *maxlen) { + if (*maxlen > INT_MAX - BUFFER_INC) + return 0; + + *maxlen += BUFFER_INC; + if (*buffer == NULL) { + if ((*buffer = OPENSSL_malloc(*maxlen)) == NULL) { + BIOerr(BIO_F_DOAPR_OUTCH, ERR_R_MALLOC_FAILURE); + return 0; + } + if (*currlen > 0) { + if (!ossl_assert(*sbuffer != NULL)) + return 0; + memcpy(*buffer, *sbuffer, *currlen); + } + *sbuffer = NULL; + } else { + char *tmpbuf; + tmpbuf = OPENSSL_realloc(*buffer, *maxlen); + if (tmpbuf == NULL) + return 0; + *buffer = tmpbuf; + } + } + + if (*currlen < *maxlen) { + if (*sbuffer) + (*sbuffer)[(*currlen)++] = (char)c; + else + (*buffer)[(*currlen)++] = (char)c; + } + + return 1; +} + +/***************************************************************************/ + +int BIO_printf(BIO *bio, const char *format, ...) +{ + va_list args; + int ret; + + va_start(args, format); + + ret = BIO_vprintf(bio, format, args); + + va_end(args); + return ret; +} + +int BIO_vprintf(BIO *bio, const char *format, va_list args) +{ + int ret; + size_t retlen; + char hugebuf[1024 * 2]; /* Was previously 10k, which is unreasonable + * in small-stack environments, like threads + * or DOS programs. */ + char *hugebufp = hugebuf; + size_t hugebufsize = sizeof(hugebuf); + char *dynbuf = NULL; + int ignored; + + dynbuf = NULL; + if (!_dopr(&hugebufp, &dynbuf, &hugebufsize, &retlen, &ignored, format, + args)) { + OPENSSL_free(dynbuf); + return -1; + } + if (dynbuf) { + ret = BIO_write(bio, dynbuf, (int)retlen); + OPENSSL_free(dynbuf); + } else { + ret = BIO_write(bio, hugebuf, (int)retlen); + } + return ret; +} + +/* + * As snprintf is not available everywhere, we provide our own + * implementation. This function has nothing to do with BIOs, but it's + * closely related to BIO_printf, and we need *some* name prefix ... (XXX the + * function should be renamed, but to what?) + */ +int BIO_snprintf(char *buf, size_t n, const char *format, ...) +{ + va_list args; + int ret; + + va_start(args, format); + + ret = BIO_vsnprintf(buf, n, format, args); + + va_end(args); + return ret; +} + +int BIO_vsnprintf(char *buf, size_t n, const char *format, va_list args) +{ + size_t retlen; + int truncated; + + if (!_dopr(&buf, NULL, &n, &retlen, &truncated, format, args)) + return -1; + + if (truncated) + /* + * In case of truncation, return -1 like traditional snprintf. + * (Current drafts for ISO/IEC 9899 say snprintf should return the + * number of characters that would have been written, had the buffer + * been large enough.) + */ + return -1; + else + return (retlen <= INT_MAX) ? (int)retlen : -1; +} diff --git a/contrib/libs/openssl/crypto/bio/b_sock.c b/contrib/libs/openssl/crypto/bio/b_sock.c index 50ea7de346..df431e6d52 100644 --- a/contrib/libs/openssl/crypto/bio/b_sock.c +++ b/contrib/libs/openssl/crypto/bio/b_sock.c @@ -1,369 +1,369 @@ -/* - * Copyright 1995-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 - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> +/* + * Copyright 1995-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 + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> #include "bio_local.h" -#ifndef OPENSSL_NO_SOCK -# define SOCKET_PROTOCOL IPPROTO_TCP -# ifdef SO_MAXCONN -# define MAX_LISTEN SO_MAXCONN -# elif defined(SOMAXCONN) -# define MAX_LISTEN SOMAXCONN -# else -# define MAX_LISTEN 32 -# endif -# if defined(OPENSSL_SYS_WINDOWS) -static int wsa_init_done = 0; -# endif - -# if OPENSSL_API_COMPAT < 0x10100000L -int BIO_get_host_ip(const char *str, unsigned char *ip) -{ - BIO_ADDRINFO *res = NULL; - int ret = 0; - - if (BIO_sock_init() != 1) - return 0; /* don't generate another error code here */ - - if (BIO_lookup(str, NULL, BIO_LOOKUP_CLIENT, AF_INET, SOCK_STREAM, &res)) { - size_t l; - - if (BIO_ADDRINFO_family(res) != AF_INET) { - BIOerr(BIO_F_BIO_GET_HOST_IP, - BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET); - } else if (BIO_ADDR_rawaddress(BIO_ADDRINFO_address(res), NULL, &l)) { - /* - * Because only AF_INET addresses will reach this far, we can assert - * that l should be 4 - */ - if (ossl_assert(l == 4)) - ret = BIO_ADDR_rawaddress(BIO_ADDRINFO_address(res), ip, &l); - } - BIO_ADDRINFO_free(res); - } else { - ERR_add_error_data(2, "host=", str); - } - - return ret; -} - -int BIO_get_port(const char *str, unsigned short *port_ptr) -{ - BIO_ADDRINFO *res = NULL; - int ret = 0; - - if (str == NULL) { - BIOerr(BIO_F_BIO_GET_PORT, BIO_R_NO_PORT_DEFINED); - return 0; - } - - if (BIO_sock_init() != 1) - return 0; /* don't generate another error code here */ - - if (BIO_lookup(NULL, str, BIO_LOOKUP_CLIENT, AF_INET, SOCK_STREAM, &res)) { - if (BIO_ADDRINFO_family(res) != AF_INET) { - BIOerr(BIO_F_BIO_GET_PORT, - BIO_R_ADDRINFO_ADDR_IS_NOT_AF_INET); - } else { - *port_ptr = ntohs(BIO_ADDR_rawport(BIO_ADDRINFO_address(res))); - ret = 1; - } - BIO_ADDRINFO_free(res); - } else { - ERR_add_error_data(2, "host=", str); - } - - return ret; -} -# endif - -int BIO_sock_error(int sock) -{ - int j = 0, i; - socklen_t size = sizeof(j); - - /* - * Note: under Windows the third parameter is of type (char *) whereas - * under other systems it is (void *) if you don't have a cast it will - * choke the compiler: if you do have a cast then you can either go for - * (char *) or (void *). - */ - i = getsockopt(sock, SOL_SOCKET, SO_ERROR, (void *)&j, &size); - if (i < 0) - return get_last_socket_error(); - else - return j; -} - -# if OPENSSL_API_COMPAT < 0x10100000L -struct hostent *BIO_gethostbyname(const char *name) -{ - /* - * Caching gethostbyname() results forever is wrong, so we have to let - * the true gethostbyname() worry about this - */ - return gethostbyname(name); -} -# endif - -int BIO_sock_init(void) -{ -# ifdef OPENSSL_SYS_WINDOWS - static struct WSAData wsa_state; - - if (!wsa_init_done) { - int err; - - wsa_init_done = 1; - memset(&wsa_state, 0, sizeof(wsa_state)); - /* - * Not making wsa_state available to the rest of the code is formally - * wrong. But the structures we use are [believed to be] invariable - * among Winsock DLLs, while API availability is [expected to be] - * probed at run-time with DSO_global_lookup. - */ - if (WSAStartup(0x0202, &wsa_state) != 0) { - err = WSAGetLastError(); - SYSerr(SYS_F_WSASTARTUP, err); - BIOerr(BIO_F_BIO_SOCK_INIT, BIO_R_WSASTARTUP); - return -1; - } - } -# endif /* OPENSSL_SYS_WINDOWS */ -# ifdef WATT32 - extern int _watt_do_exit; - _watt_do_exit = 0; /* don't make sock_init() call exit() */ - if (sock_init()) - return -1; -# endif - - return 1; -} - -void bio_sock_cleanup_int(void) -{ -# ifdef OPENSSL_SYS_WINDOWS - if (wsa_init_done) { - wsa_init_done = 0; - WSACleanup(); - } -# endif -} - -int BIO_socket_ioctl(int fd, long type, void *arg) -{ - int i; - -# ifdef __DJGPP__ - i = ioctlsocket(fd, type, (char *)arg); -# else -# if defined(OPENSSL_SYS_VMS) - /*- - * 2011-02-18 SMS. - * VMS ioctl() can't tolerate a 64-bit "void *arg", but we - * observe that all the consumers pass in an "unsigned long *", - * so we arrange a local copy with a short pointer, and use - * that, instead. - */ -# if __INITIAL_POINTER_SIZE == 64 -# define ARG arg_32p -# pragma pointer_size save -# pragma pointer_size 32 - unsigned long arg_32; - unsigned long *arg_32p; -# pragma pointer_size restore - arg_32p = &arg_32; - arg_32 = *((unsigned long *)arg); -# else /* __INITIAL_POINTER_SIZE == 64 */ -# define ARG arg -# endif /* __INITIAL_POINTER_SIZE == 64 [else] */ -# else /* defined(OPENSSL_SYS_VMS) */ -# define ARG arg -# endif /* defined(OPENSSL_SYS_VMS) [else] */ - - i = ioctlsocket(fd, type, ARG); -# endif /* __DJGPP__ */ - if (i < 0) - SYSerr(SYS_F_IOCTLSOCKET, get_last_socket_error()); - return i; -} - -# if OPENSSL_API_COMPAT < 0x10100000L -int BIO_get_accept_socket(char *host, int bind_mode) -{ - int s = INVALID_SOCKET; - char *h = NULL, *p = NULL; - BIO_ADDRINFO *res = NULL; - - if (!BIO_parse_hostserv(host, &h, &p, BIO_PARSE_PRIO_SERV)) - return INVALID_SOCKET; - - if (BIO_sock_init() != 1) - return INVALID_SOCKET; - - if (BIO_lookup(h, p, BIO_LOOKUP_SERVER, AF_UNSPEC, SOCK_STREAM, &res) != 0) - goto err; - - if ((s = BIO_socket(BIO_ADDRINFO_family(res), BIO_ADDRINFO_socktype(res), - BIO_ADDRINFO_protocol(res), 0)) == INVALID_SOCKET) { - s = INVALID_SOCKET; - goto err; - } - - if (!BIO_listen(s, BIO_ADDRINFO_address(res), - bind_mode ? BIO_SOCK_REUSEADDR : 0)) { - BIO_closesocket(s); - s = INVALID_SOCKET; - } - - err: - BIO_ADDRINFO_free(res); - OPENSSL_free(h); - OPENSSL_free(p); - - return s; -} - -int BIO_accept(int sock, char **ip_port) -{ - BIO_ADDR res; - int ret = -1; - - ret = BIO_accept_ex(sock, &res, 0); - if (ret == (int)INVALID_SOCKET) { - if (BIO_sock_should_retry(ret)) { - ret = -2; - goto end; - } - SYSerr(SYS_F_ACCEPT, get_last_socket_error()); - BIOerr(BIO_F_BIO_ACCEPT, BIO_R_ACCEPT_ERROR); - goto end; - } - - if (ip_port != NULL) { - char *host = BIO_ADDR_hostname_string(&res, 1); - char *port = BIO_ADDR_service_string(&res, 1); - if (host != NULL && port != NULL) - *ip_port = OPENSSL_zalloc(strlen(host) + strlen(port) + 2); - else - *ip_port = NULL; - - if (*ip_port == NULL) { - BIOerr(BIO_F_BIO_ACCEPT, ERR_R_MALLOC_FAILURE); - BIO_closesocket(ret); - ret = (int)INVALID_SOCKET; - } else { - strcpy(*ip_port, host); - strcat(*ip_port, ":"); - strcat(*ip_port, port); - } - OPENSSL_free(host); - OPENSSL_free(port); - } - - end: - return ret; -} -# endif - -int BIO_set_tcp_ndelay(int s, int on) -{ - int ret = 0; -# if defined(TCP_NODELAY) && (defined(IPPROTO_TCP) || defined(SOL_TCP)) - int opt; - -# ifdef SOL_TCP - opt = SOL_TCP; -# else -# ifdef IPPROTO_TCP - opt = IPPROTO_TCP; -# endif -# endif - - ret = setsockopt(s, opt, TCP_NODELAY, (char *)&on, sizeof(on)); -# endif - return (ret == 0); -} - -int BIO_socket_nbio(int s, int mode) -{ - int ret = -1; - int l; - - l = mode; -# ifdef FIONBIO - l = mode; - - ret = BIO_socket_ioctl(s, FIONBIO, &l); -# elif defined(F_GETFL) && defined(F_SETFL) && (defined(O_NONBLOCK) || defined(FNDELAY)) - /* make sure this call always pushes an error level; BIO_socket_ioctl() does so, so we do too. */ - - l = fcntl(s, F_GETFL, 0); - if (l == -1) { - SYSerr(SYS_F_FCNTL, get_last_sys_error()); - ret = -1; - } else { -# if defined(O_NONBLOCK) - l &= ~O_NONBLOCK; -# else - l &= ~FNDELAY; /* BSD4.x */ -# endif - if (mode) { -# if defined(O_NONBLOCK) - l |= O_NONBLOCK; -# else - l |= FNDELAY; /* BSD4.x */ -# endif - } - ret = fcntl(s, F_SETFL, l); - - if (ret < 0) { - SYSerr(SYS_F_FCNTL, get_last_sys_error()); - } - } -# else - /* make sure this call always pushes an error level; BIO_socket_ioctl() does so, so we do too. */ - BIOerr(BIO_F_BIO_SOCKET_NBIO, ERR_R_PASSED_INVALID_ARGUMENT); -# endif - - return (ret == 0); -} - -int BIO_sock_info(int sock, - enum BIO_sock_info_type type, union BIO_sock_info_u *info) -{ - switch (type) { - case BIO_SOCK_INFO_ADDRESS: - { - socklen_t addr_len; - int ret = 0; - addr_len = sizeof(*info->addr); - ret = getsockname(sock, BIO_ADDR_sockaddr_noconst(info->addr), - &addr_len); - if (ret == -1) { - SYSerr(SYS_F_GETSOCKNAME, get_last_socket_error()); - BIOerr(BIO_F_BIO_SOCK_INFO, BIO_R_GETSOCKNAME_ERROR); - return 0; - } - if ((size_t)addr_len > sizeof(*info->addr)) { - BIOerr(BIO_F_BIO_SOCK_INFO, BIO_R_GETSOCKNAME_TRUNCATED_ADDRESS); - return 0; - } - } - break; - default: - BIOerr(BIO_F_BIO_SOCK_INFO, BIO_R_UNKNOWN_INFO_TYPE); - return 0; - } - return 1; -} - -#endif +#ifndef OPENSSL_NO_SOCK +# define SOCKET_PROTOCOL IPPROTO_TCP +# ifdef SO_MAXCONN +# define MAX_LISTEN SO_MAXCONN +# elif defined(SOMAXCONN) +# define MAX_LISTEN SOMAXCONN +# else +# define MAX_LISTEN 32 +# endif +# if defined(OPENSSL_SYS_WINDOWS) +static int wsa_init_done = 0; +# endif + +# if OPENSSL_API_COMPAT < 0x10100000L +int BIO_get_host_ip(const char *str, unsigned char *ip) +{ + BIO_ADDRINFO *res = NULL; + int ret = 0; + + if (BIO_sock_init() != 1) + return 0; /* don't generate another error code here */ + + if (BIO_lookup(str, NULL, BIO_LOOKUP_CLIENT, AF_INET, SOCK_STREAM, &res)) { + size_t l; + + if (BIO_ADDRINFO_family(res) != AF_INET) { + BIOerr(BIO_F_BIO_GET_HOST_IP, + BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET); + } else if (BIO_ADDR_rawaddress(BIO_ADDRINFO_address(res), NULL, &l)) { + /* + * Because only AF_INET addresses will reach this far, we can assert + * that l should be 4 + */ + if (ossl_assert(l == 4)) + ret = BIO_ADDR_rawaddress(BIO_ADDRINFO_address(res), ip, &l); + } + BIO_ADDRINFO_free(res); + } else { + ERR_add_error_data(2, "host=", str); + } + + return ret; +} + +int BIO_get_port(const char *str, unsigned short *port_ptr) +{ + BIO_ADDRINFO *res = NULL; + int ret = 0; + + if (str == NULL) { + BIOerr(BIO_F_BIO_GET_PORT, BIO_R_NO_PORT_DEFINED); + return 0; + } + + if (BIO_sock_init() != 1) + return 0; /* don't generate another error code here */ + + if (BIO_lookup(NULL, str, BIO_LOOKUP_CLIENT, AF_INET, SOCK_STREAM, &res)) { + if (BIO_ADDRINFO_family(res) != AF_INET) { + BIOerr(BIO_F_BIO_GET_PORT, + BIO_R_ADDRINFO_ADDR_IS_NOT_AF_INET); + } else { + *port_ptr = ntohs(BIO_ADDR_rawport(BIO_ADDRINFO_address(res))); + ret = 1; + } + BIO_ADDRINFO_free(res); + } else { + ERR_add_error_data(2, "host=", str); + } + + return ret; +} +# endif + +int BIO_sock_error(int sock) +{ + int j = 0, i; + socklen_t size = sizeof(j); + + /* + * Note: under Windows the third parameter is of type (char *) whereas + * under other systems it is (void *) if you don't have a cast it will + * choke the compiler: if you do have a cast then you can either go for + * (char *) or (void *). + */ + i = getsockopt(sock, SOL_SOCKET, SO_ERROR, (void *)&j, &size); + if (i < 0) + return get_last_socket_error(); + else + return j; +} + +# if OPENSSL_API_COMPAT < 0x10100000L +struct hostent *BIO_gethostbyname(const char *name) +{ + /* + * Caching gethostbyname() results forever is wrong, so we have to let + * the true gethostbyname() worry about this + */ + return gethostbyname(name); +} +# endif + +int BIO_sock_init(void) +{ +# ifdef OPENSSL_SYS_WINDOWS + static struct WSAData wsa_state; + + if (!wsa_init_done) { + int err; + + wsa_init_done = 1; + memset(&wsa_state, 0, sizeof(wsa_state)); + /* + * Not making wsa_state available to the rest of the code is formally + * wrong. But the structures we use are [believed to be] invariable + * among Winsock DLLs, while API availability is [expected to be] + * probed at run-time with DSO_global_lookup. + */ + if (WSAStartup(0x0202, &wsa_state) != 0) { + err = WSAGetLastError(); + SYSerr(SYS_F_WSASTARTUP, err); + BIOerr(BIO_F_BIO_SOCK_INIT, BIO_R_WSASTARTUP); + return -1; + } + } +# endif /* OPENSSL_SYS_WINDOWS */ +# ifdef WATT32 + extern int _watt_do_exit; + _watt_do_exit = 0; /* don't make sock_init() call exit() */ + if (sock_init()) + return -1; +# endif + + return 1; +} + +void bio_sock_cleanup_int(void) +{ +# ifdef OPENSSL_SYS_WINDOWS + if (wsa_init_done) { + wsa_init_done = 0; + WSACleanup(); + } +# endif +} + +int BIO_socket_ioctl(int fd, long type, void *arg) +{ + int i; + +# ifdef __DJGPP__ + i = ioctlsocket(fd, type, (char *)arg); +# else +# if defined(OPENSSL_SYS_VMS) + /*- + * 2011-02-18 SMS. + * VMS ioctl() can't tolerate a 64-bit "void *arg", but we + * observe that all the consumers pass in an "unsigned long *", + * so we arrange a local copy with a short pointer, and use + * that, instead. + */ +# if __INITIAL_POINTER_SIZE == 64 +# define ARG arg_32p +# pragma pointer_size save +# pragma pointer_size 32 + unsigned long arg_32; + unsigned long *arg_32p; +# pragma pointer_size restore + arg_32p = &arg_32; + arg_32 = *((unsigned long *)arg); +# else /* __INITIAL_POINTER_SIZE == 64 */ +# define ARG arg +# endif /* __INITIAL_POINTER_SIZE == 64 [else] */ +# else /* defined(OPENSSL_SYS_VMS) */ +# define ARG arg +# endif /* defined(OPENSSL_SYS_VMS) [else] */ + + i = ioctlsocket(fd, type, ARG); +# endif /* __DJGPP__ */ + if (i < 0) + SYSerr(SYS_F_IOCTLSOCKET, get_last_socket_error()); + return i; +} + +# if OPENSSL_API_COMPAT < 0x10100000L +int BIO_get_accept_socket(char *host, int bind_mode) +{ + int s = INVALID_SOCKET; + char *h = NULL, *p = NULL; + BIO_ADDRINFO *res = NULL; + + if (!BIO_parse_hostserv(host, &h, &p, BIO_PARSE_PRIO_SERV)) + return INVALID_SOCKET; + + if (BIO_sock_init() != 1) + return INVALID_SOCKET; + + if (BIO_lookup(h, p, BIO_LOOKUP_SERVER, AF_UNSPEC, SOCK_STREAM, &res) != 0) + goto err; + + if ((s = BIO_socket(BIO_ADDRINFO_family(res), BIO_ADDRINFO_socktype(res), + BIO_ADDRINFO_protocol(res), 0)) == INVALID_SOCKET) { + s = INVALID_SOCKET; + goto err; + } + + if (!BIO_listen(s, BIO_ADDRINFO_address(res), + bind_mode ? BIO_SOCK_REUSEADDR : 0)) { + BIO_closesocket(s); + s = INVALID_SOCKET; + } + + err: + BIO_ADDRINFO_free(res); + OPENSSL_free(h); + OPENSSL_free(p); + + return s; +} + +int BIO_accept(int sock, char **ip_port) +{ + BIO_ADDR res; + int ret = -1; + + ret = BIO_accept_ex(sock, &res, 0); + if (ret == (int)INVALID_SOCKET) { + if (BIO_sock_should_retry(ret)) { + ret = -2; + goto end; + } + SYSerr(SYS_F_ACCEPT, get_last_socket_error()); + BIOerr(BIO_F_BIO_ACCEPT, BIO_R_ACCEPT_ERROR); + goto end; + } + + if (ip_port != NULL) { + char *host = BIO_ADDR_hostname_string(&res, 1); + char *port = BIO_ADDR_service_string(&res, 1); + if (host != NULL && port != NULL) + *ip_port = OPENSSL_zalloc(strlen(host) + strlen(port) + 2); + else + *ip_port = NULL; + + if (*ip_port == NULL) { + BIOerr(BIO_F_BIO_ACCEPT, ERR_R_MALLOC_FAILURE); + BIO_closesocket(ret); + ret = (int)INVALID_SOCKET; + } else { + strcpy(*ip_port, host); + strcat(*ip_port, ":"); + strcat(*ip_port, port); + } + OPENSSL_free(host); + OPENSSL_free(port); + } + + end: + return ret; +} +# endif + +int BIO_set_tcp_ndelay(int s, int on) +{ + int ret = 0; +# if defined(TCP_NODELAY) && (defined(IPPROTO_TCP) || defined(SOL_TCP)) + int opt; + +# ifdef SOL_TCP + opt = SOL_TCP; +# else +# ifdef IPPROTO_TCP + opt = IPPROTO_TCP; +# endif +# endif + + ret = setsockopt(s, opt, TCP_NODELAY, (char *)&on, sizeof(on)); +# endif + return (ret == 0); +} + +int BIO_socket_nbio(int s, int mode) +{ + int ret = -1; + int l; + + l = mode; +# ifdef FIONBIO + l = mode; + + ret = BIO_socket_ioctl(s, FIONBIO, &l); +# elif defined(F_GETFL) && defined(F_SETFL) && (defined(O_NONBLOCK) || defined(FNDELAY)) + /* make sure this call always pushes an error level; BIO_socket_ioctl() does so, so we do too. */ + + l = fcntl(s, F_GETFL, 0); + if (l == -1) { + SYSerr(SYS_F_FCNTL, get_last_sys_error()); + ret = -1; + } else { +# if defined(O_NONBLOCK) + l &= ~O_NONBLOCK; +# else + l &= ~FNDELAY; /* BSD4.x */ +# endif + if (mode) { +# if defined(O_NONBLOCK) + l |= O_NONBLOCK; +# else + l |= FNDELAY; /* BSD4.x */ +# endif + } + ret = fcntl(s, F_SETFL, l); + + if (ret < 0) { + SYSerr(SYS_F_FCNTL, get_last_sys_error()); + } + } +# else + /* make sure this call always pushes an error level; BIO_socket_ioctl() does so, so we do too. */ + BIOerr(BIO_F_BIO_SOCKET_NBIO, ERR_R_PASSED_INVALID_ARGUMENT); +# endif + + return (ret == 0); +} + +int BIO_sock_info(int sock, + enum BIO_sock_info_type type, union BIO_sock_info_u *info) +{ + switch (type) { + case BIO_SOCK_INFO_ADDRESS: + { + socklen_t addr_len; + int ret = 0; + addr_len = sizeof(*info->addr); + ret = getsockname(sock, BIO_ADDR_sockaddr_noconst(info->addr), + &addr_len); + if (ret == -1) { + SYSerr(SYS_F_GETSOCKNAME, get_last_socket_error()); + BIOerr(BIO_F_BIO_SOCK_INFO, BIO_R_GETSOCKNAME_ERROR); + return 0; + } + if ((size_t)addr_len > sizeof(*info->addr)) { + BIOerr(BIO_F_BIO_SOCK_INFO, BIO_R_GETSOCKNAME_TRUNCATED_ADDRESS); + return 0; + } + } + break; + default: + BIOerr(BIO_F_BIO_SOCK_INFO, BIO_R_UNKNOWN_INFO_TYPE); + return 0; + } + return 1; +} + +#endif diff --git a/contrib/libs/openssl/crypto/bio/b_sock2.c b/contrib/libs/openssl/crypto/bio/b_sock2.c index f5f9620809..104ff31b0d 100644 --- a/contrib/libs/openssl/crypto/bio/b_sock2.c +++ b/contrib/libs/openssl/crypto/bio/b_sock2.c @@ -1,318 +1,318 @@ -/* +/* * Copyright 2016-2021 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 - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -#include <stdio.h> -#include <stdlib.h> -#include <errno.h> - + * + * Licensed under the OpenSSL license (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 <stdio.h> +#include <stdlib.h> +#include <errno.h> + #include "bio_local.h" - -#include <openssl/err.h> - -#ifndef OPENSSL_NO_SOCK -# ifdef SO_MAXCONN -# define MAX_LISTEN SO_MAXCONN -# elif defined(SOMAXCONN) -# define MAX_LISTEN SOMAXCONN -# else -# define MAX_LISTEN 32 -# endif - -/*- - * BIO_socket - create a socket - * @domain: the socket domain (AF_INET, AF_INET6, AF_UNIX, ...) - * @socktype: the socket type (SOCK_STEAM, SOCK_DGRAM) - * @protocol: the protocol to use (IPPROTO_TCP, IPPROTO_UDP) - * @options: BIO socket options (currently unused) - * - * Creates a socket. This should be called before calling any - * of BIO_connect and BIO_listen. - * - * Returns the file descriptor on success or INVALID_SOCKET on failure. On - * failure errno is set, and a status is added to the OpenSSL error stack. - */ -int BIO_socket(int domain, int socktype, int protocol, int options) -{ - int sock = -1; - - if (BIO_sock_init() != 1) - return INVALID_SOCKET; - - sock = socket(domain, socktype, protocol); - if (sock == -1) { - SYSerr(SYS_F_SOCKET, get_last_socket_error()); - BIOerr(BIO_F_BIO_SOCKET, BIO_R_UNABLE_TO_CREATE_SOCKET); - return INVALID_SOCKET; - } - - return sock; -} - -/*- - * BIO_connect - connect to an address - * @sock: the socket to connect with - * @addr: the address to connect to - * @options: BIO socket options - * - * Connects to the address using the given socket and options. - * - * Options can be a combination of the following: - * - BIO_SOCK_KEEPALIVE: enable regularly sending keep-alive messages. - * - BIO_SOCK_NONBLOCK: Make the socket non-blocking. - * - BIO_SOCK_NODELAY: don't delay small messages. - * - * options holds BIO socket options that can be used - * You should call this for every address returned by BIO_lookup - * until the connection is successful. - * - * Returns 1 on success or 0 on failure. On failure errno is set - * and an error status is added to the OpenSSL error stack. - */ -int BIO_connect(int sock, const BIO_ADDR *addr, int options) -{ - const int on = 1; - - if (sock == -1) { - BIOerr(BIO_F_BIO_CONNECT, BIO_R_INVALID_SOCKET); - return 0; - } - - if (!BIO_socket_nbio(sock, (options & BIO_SOCK_NONBLOCK) != 0)) - return 0; - - if (options & BIO_SOCK_KEEPALIVE) { - if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, - (const void *)&on, sizeof(on)) != 0) { - SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error()); - BIOerr(BIO_F_BIO_CONNECT, BIO_R_UNABLE_TO_KEEPALIVE); - return 0; - } - } - - if (options & BIO_SOCK_NODELAY) { - if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, - (const void *)&on, sizeof(on)) != 0) { - SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error()); - BIOerr(BIO_F_BIO_CONNECT, BIO_R_UNABLE_TO_NODELAY); - return 0; - } - } - - if (connect(sock, BIO_ADDR_sockaddr(addr), - BIO_ADDR_sockaddr_size(addr)) == -1) { - if (!BIO_sock_should_retry(-1)) { - SYSerr(SYS_F_CONNECT, get_last_socket_error()); - BIOerr(BIO_F_BIO_CONNECT, BIO_R_CONNECT_ERROR); - } - return 0; - } - return 1; -} - -/*- - * BIO_bind - bind socket to address - * @sock: the socket to set - * @addr: local address to bind to - * @options: BIO socket options - * - * Binds to the address using the given socket and options. - * - * Options can be a combination of the following: - * - BIO_SOCK_REUSEADDR: Try to reuse the address and port combination - * for a recently closed port. - * - * When restarting the program it could be that the port is still in use. If - * you set to BIO_SOCK_REUSEADDR option it will try to reuse the port anyway. - * It's recommended that you use this. - */ -int BIO_bind(int sock, const BIO_ADDR *addr, int options) -{ -# ifndef OPENSSL_SYS_WINDOWS - int on = 1; -# endif - - if (sock == -1) { - BIOerr(BIO_F_BIO_BIND, BIO_R_INVALID_SOCKET); - return 0; - } - -# ifndef OPENSSL_SYS_WINDOWS - /* - * SO_REUSEADDR has different behavior on Windows than on - * other operating systems, don't set it there. - */ - if (options & BIO_SOCK_REUSEADDR) { - if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, - (const void *)&on, sizeof(on)) != 0) { - SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error()); - BIOerr(BIO_F_BIO_BIND, BIO_R_UNABLE_TO_REUSEADDR); - return 0; - } - } -# endif - - if (bind(sock, BIO_ADDR_sockaddr(addr), BIO_ADDR_sockaddr_size(addr)) != 0) { - SYSerr(SYS_F_BIND, get_last_socket_error()); - BIOerr(BIO_F_BIO_BIND, BIO_R_UNABLE_TO_BIND_SOCKET); - return 0; - } - - return 1; -} - -/*- - * BIO_listen - Creates a listen socket - * @sock: the socket to listen with - * @addr: local address to bind to - * @options: BIO socket options - * - * Binds to the address using the given socket and options, then - * starts listening for incoming connections. - * - * Options can be a combination of the following: - * - BIO_SOCK_KEEPALIVE: enable regularly sending keep-alive messages. - * - BIO_SOCK_NONBLOCK: Make the socket non-blocking. - * - BIO_SOCK_NODELAY: don't delay small messages. - * - BIO_SOCK_REUSEADDR: Try to reuse the address and port combination - * for a recently closed port. - * - BIO_SOCK_V6_ONLY: When creating an IPv6 socket, make it listen only - * for IPv6 addresses and not IPv4 addresses mapped to IPv6. - * - * It's recommended that you set up both an IPv6 and IPv4 listen socket, and - * then check both for new clients that connect to it. You want to set up - * the socket as non-blocking in that case since else it could hang. - * - * Not all operating systems support IPv4 addresses on an IPv6 socket, and for - * others it's an option. If you pass the BIO_LISTEN_V6_ONLY it will try to - * create the IPv6 sockets to only listen for IPv6 connection. - * - * It could be that the first BIO_listen() call will listen to all the IPv6 - * and IPv4 addresses and that then trying to bind to the IPv4 address will - * fail. We can't tell the difference between already listening ourself to - * it and someone else listening to it when failing and errno is EADDRINUSE, so - * it's recommended to not give an error in that case if the first call was - * successful. - * - * When restarting the program it could be that the port is still in use. If - * you set to BIO_SOCK_REUSEADDR option it will try to reuse the port anyway. - * It's recommended that you use this. - */ -int BIO_listen(int sock, const BIO_ADDR *addr, int options) -{ - int on = 1; - int socktype; - socklen_t socktype_len = sizeof(socktype); - - if (sock == -1) { - BIOerr(BIO_F_BIO_LISTEN, BIO_R_INVALID_SOCKET); - return 0; - } - - if (getsockopt(sock, SOL_SOCKET, SO_TYPE, - (void *)&socktype, &socktype_len) != 0 - || socktype_len != sizeof(socktype)) { - SYSerr(SYS_F_GETSOCKOPT, get_last_socket_error()); - BIOerr(BIO_F_BIO_LISTEN, BIO_R_GETTING_SOCKTYPE); - return 0; - } - - if (!BIO_socket_nbio(sock, (options & BIO_SOCK_NONBLOCK) != 0)) - return 0; - - if (options & BIO_SOCK_KEEPALIVE) { - if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, - (const void *)&on, sizeof(on)) != 0) { - SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error()); - BIOerr(BIO_F_BIO_LISTEN, BIO_R_UNABLE_TO_KEEPALIVE); - return 0; - } - } - - if (options & BIO_SOCK_NODELAY) { - if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, - (const void *)&on, sizeof(on)) != 0) { - SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error()); - BIOerr(BIO_F_BIO_LISTEN, BIO_R_UNABLE_TO_NODELAY); - return 0; - } - } - + +#include <openssl/err.h> + +#ifndef OPENSSL_NO_SOCK +# ifdef SO_MAXCONN +# define MAX_LISTEN SO_MAXCONN +# elif defined(SOMAXCONN) +# define MAX_LISTEN SOMAXCONN +# else +# define MAX_LISTEN 32 +# endif + +/*- + * BIO_socket - create a socket + * @domain: the socket domain (AF_INET, AF_INET6, AF_UNIX, ...) + * @socktype: the socket type (SOCK_STEAM, SOCK_DGRAM) + * @protocol: the protocol to use (IPPROTO_TCP, IPPROTO_UDP) + * @options: BIO socket options (currently unused) + * + * Creates a socket. This should be called before calling any + * of BIO_connect and BIO_listen. + * + * Returns the file descriptor on success or INVALID_SOCKET on failure. On + * failure errno is set, and a status is added to the OpenSSL error stack. + */ +int BIO_socket(int domain, int socktype, int protocol, int options) +{ + int sock = -1; + + if (BIO_sock_init() != 1) + return INVALID_SOCKET; + + sock = socket(domain, socktype, protocol); + if (sock == -1) { + SYSerr(SYS_F_SOCKET, get_last_socket_error()); + BIOerr(BIO_F_BIO_SOCKET, BIO_R_UNABLE_TO_CREATE_SOCKET); + return INVALID_SOCKET; + } + + return sock; +} + +/*- + * BIO_connect - connect to an address + * @sock: the socket to connect with + * @addr: the address to connect to + * @options: BIO socket options + * + * Connects to the address using the given socket and options. + * + * Options can be a combination of the following: + * - BIO_SOCK_KEEPALIVE: enable regularly sending keep-alive messages. + * - BIO_SOCK_NONBLOCK: Make the socket non-blocking. + * - BIO_SOCK_NODELAY: don't delay small messages. + * + * options holds BIO socket options that can be used + * You should call this for every address returned by BIO_lookup + * until the connection is successful. + * + * Returns 1 on success or 0 on failure. On failure errno is set + * and an error status is added to the OpenSSL error stack. + */ +int BIO_connect(int sock, const BIO_ADDR *addr, int options) +{ + const int on = 1; + + if (sock == -1) { + BIOerr(BIO_F_BIO_CONNECT, BIO_R_INVALID_SOCKET); + return 0; + } + + if (!BIO_socket_nbio(sock, (options & BIO_SOCK_NONBLOCK) != 0)) + return 0; + + if (options & BIO_SOCK_KEEPALIVE) { + if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, + (const void *)&on, sizeof(on)) != 0) { + SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error()); + BIOerr(BIO_F_BIO_CONNECT, BIO_R_UNABLE_TO_KEEPALIVE); + return 0; + } + } + + if (options & BIO_SOCK_NODELAY) { + if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, + (const void *)&on, sizeof(on)) != 0) { + SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error()); + BIOerr(BIO_F_BIO_CONNECT, BIO_R_UNABLE_TO_NODELAY); + return 0; + } + } + + if (connect(sock, BIO_ADDR_sockaddr(addr), + BIO_ADDR_sockaddr_size(addr)) == -1) { + if (!BIO_sock_should_retry(-1)) { + SYSerr(SYS_F_CONNECT, get_last_socket_error()); + BIOerr(BIO_F_BIO_CONNECT, BIO_R_CONNECT_ERROR); + } + return 0; + } + return 1; +} + +/*- + * BIO_bind - bind socket to address + * @sock: the socket to set + * @addr: local address to bind to + * @options: BIO socket options + * + * Binds to the address using the given socket and options. + * + * Options can be a combination of the following: + * - BIO_SOCK_REUSEADDR: Try to reuse the address and port combination + * for a recently closed port. + * + * When restarting the program it could be that the port is still in use. If + * you set to BIO_SOCK_REUSEADDR option it will try to reuse the port anyway. + * It's recommended that you use this. + */ +int BIO_bind(int sock, const BIO_ADDR *addr, int options) +{ +# ifndef OPENSSL_SYS_WINDOWS + int on = 1; +# endif + + if (sock == -1) { + BIOerr(BIO_F_BIO_BIND, BIO_R_INVALID_SOCKET); + return 0; + } + +# ifndef OPENSSL_SYS_WINDOWS + /* + * SO_REUSEADDR has different behavior on Windows than on + * other operating systems, don't set it there. + */ + if (options & BIO_SOCK_REUSEADDR) { + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, + (const void *)&on, sizeof(on)) != 0) { + SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error()); + BIOerr(BIO_F_BIO_BIND, BIO_R_UNABLE_TO_REUSEADDR); + return 0; + } + } +# endif + + if (bind(sock, BIO_ADDR_sockaddr(addr), BIO_ADDR_sockaddr_size(addr)) != 0) { + SYSerr(SYS_F_BIND, get_last_socket_error()); + BIOerr(BIO_F_BIO_BIND, BIO_R_UNABLE_TO_BIND_SOCKET); + return 0; + } + + return 1; +} + +/*- + * BIO_listen - Creates a listen socket + * @sock: the socket to listen with + * @addr: local address to bind to + * @options: BIO socket options + * + * Binds to the address using the given socket and options, then + * starts listening for incoming connections. + * + * Options can be a combination of the following: + * - BIO_SOCK_KEEPALIVE: enable regularly sending keep-alive messages. + * - BIO_SOCK_NONBLOCK: Make the socket non-blocking. + * - BIO_SOCK_NODELAY: don't delay small messages. + * - BIO_SOCK_REUSEADDR: Try to reuse the address and port combination + * for a recently closed port. + * - BIO_SOCK_V6_ONLY: When creating an IPv6 socket, make it listen only + * for IPv6 addresses and not IPv4 addresses mapped to IPv6. + * + * It's recommended that you set up both an IPv6 and IPv4 listen socket, and + * then check both for new clients that connect to it. You want to set up + * the socket as non-blocking in that case since else it could hang. + * + * Not all operating systems support IPv4 addresses on an IPv6 socket, and for + * others it's an option. If you pass the BIO_LISTEN_V6_ONLY it will try to + * create the IPv6 sockets to only listen for IPv6 connection. + * + * It could be that the first BIO_listen() call will listen to all the IPv6 + * and IPv4 addresses and that then trying to bind to the IPv4 address will + * fail. We can't tell the difference between already listening ourself to + * it and someone else listening to it when failing and errno is EADDRINUSE, so + * it's recommended to not give an error in that case if the first call was + * successful. + * + * When restarting the program it could be that the port is still in use. If + * you set to BIO_SOCK_REUSEADDR option it will try to reuse the port anyway. + * It's recommended that you use this. + */ +int BIO_listen(int sock, const BIO_ADDR *addr, int options) +{ + int on = 1; + int socktype; + socklen_t socktype_len = sizeof(socktype); + + if (sock == -1) { + BIOerr(BIO_F_BIO_LISTEN, BIO_R_INVALID_SOCKET); + return 0; + } + + if (getsockopt(sock, SOL_SOCKET, SO_TYPE, + (void *)&socktype, &socktype_len) != 0 + || socktype_len != sizeof(socktype)) { + SYSerr(SYS_F_GETSOCKOPT, get_last_socket_error()); + BIOerr(BIO_F_BIO_LISTEN, BIO_R_GETTING_SOCKTYPE); + return 0; + } + + if (!BIO_socket_nbio(sock, (options & BIO_SOCK_NONBLOCK) != 0)) + return 0; + + if (options & BIO_SOCK_KEEPALIVE) { + if (setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE, + (const void *)&on, sizeof(on)) != 0) { + SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error()); + BIOerr(BIO_F_BIO_LISTEN, BIO_R_UNABLE_TO_KEEPALIVE); + return 0; + } + } + + if (options & BIO_SOCK_NODELAY) { + if (setsockopt(sock, IPPROTO_TCP, TCP_NODELAY, + (const void *)&on, sizeof(on)) != 0) { + SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error()); + BIOerr(BIO_F_BIO_LISTEN, BIO_R_UNABLE_TO_NODELAY); + return 0; + } + } + /* On OpenBSD it is always ipv6 only with ipv6 sockets thus read-only */ # if defined(IPV6_V6ONLY) && !defined(__OpenBSD__) - if (BIO_ADDR_family(addr) == AF_INET6) { - /* - * Note: Windows default of IPV6_V6ONLY is ON, and Linux is OFF. - * Therefore we always have to use setsockopt here. - */ - on = options & BIO_SOCK_V6_ONLY ? 1 : 0; - if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, - (const void *)&on, sizeof(on)) != 0) { - SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error()); - BIOerr(BIO_F_BIO_LISTEN, BIO_R_LISTEN_V6_ONLY); - return 0; - } - } -# endif - - if (!BIO_bind(sock, addr, options)) - return 0; - - if (socktype != SOCK_DGRAM && listen(sock, MAX_LISTEN) == -1) { - SYSerr(SYS_F_LISTEN, get_last_socket_error()); - BIOerr(BIO_F_BIO_LISTEN, BIO_R_UNABLE_TO_LISTEN_SOCKET); - return 0; - } - - return 1; -} - -/*- - * BIO_accept_ex - Accept new incoming connections - * @sock: the listening socket - * @addr: the BIO_ADDR to store the peer address in - * @options: BIO socket options, applied on the accepted socket. - * - */ -int BIO_accept_ex(int accept_sock, BIO_ADDR *addr_, int options) -{ - socklen_t len; - int accepted_sock; - BIO_ADDR locaddr; - BIO_ADDR *addr = addr_ == NULL ? &locaddr : addr_; - - len = sizeof(*addr); - accepted_sock = accept(accept_sock, - BIO_ADDR_sockaddr_noconst(addr), &len); - if (accepted_sock == -1) { - if (!BIO_sock_should_retry(accepted_sock)) { - SYSerr(SYS_F_ACCEPT, get_last_socket_error()); - BIOerr(BIO_F_BIO_ACCEPT_EX, BIO_R_ACCEPT_ERROR); - } - return INVALID_SOCKET; - } - - if (!BIO_socket_nbio(accepted_sock, (options & BIO_SOCK_NONBLOCK) != 0)) { - closesocket(accepted_sock); - return INVALID_SOCKET; - } - - return accepted_sock; -} - -/*- - * BIO_closesocket - Close a socket - * @sock: the socket to close - */ -int BIO_closesocket(int sock) -{ - if (closesocket(sock) < 0) - return 0; - return 1; -} -#endif + if (BIO_ADDR_family(addr) == AF_INET6) { + /* + * Note: Windows default of IPV6_V6ONLY is ON, and Linux is OFF. + * Therefore we always have to use setsockopt here. + */ + on = options & BIO_SOCK_V6_ONLY ? 1 : 0; + if (setsockopt(sock, IPPROTO_IPV6, IPV6_V6ONLY, + (const void *)&on, sizeof(on)) != 0) { + SYSerr(SYS_F_SETSOCKOPT, get_last_socket_error()); + BIOerr(BIO_F_BIO_LISTEN, BIO_R_LISTEN_V6_ONLY); + return 0; + } + } +# endif + + if (!BIO_bind(sock, addr, options)) + return 0; + + if (socktype != SOCK_DGRAM && listen(sock, MAX_LISTEN) == -1) { + SYSerr(SYS_F_LISTEN, get_last_socket_error()); + BIOerr(BIO_F_BIO_LISTEN, BIO_R_UNABLE_TO_LISTEN_SOCKET); + return 0; + } + + return 1; +} + +/*- + * BIO_accept_ex - Accept new incoming connections + * @sock: the listening socket + * @addr: the BIO_ADDR to store the peer address in + * @options: BIO socket options, applied on the accepted socket. + * + */ +int BIO_accept_ex(int accept_sock, BIO_ADDR *addr_, int options) +{ + socklen_t len; + int accepted_sock; + BIO_ADDR locaddr; + BIO_ADDR *addr = addr_ == NULL ? &locaddr : addr_; + + len = sizeof(*addr); + accepted_sock = accept(accept_sock, + BIO_ADDR_sockaddr_noconst(addr), &len); + if (accepted_sock == -1) { + if (!BIO_sock_should_retry(accepted_sock)) { + SYSerr(SYS_F_ACCEPT, get_last_socket_error()); + BIOerr(BIO_F_BIO_ACCEPT_EX, BIO_R_ACCEPT_ERROR); + } + return INVALID_SOCKET; + } + + if (!BIO_socket_nbio(accepted_sock, (options & BIO_SOCK_NONBLOCK) != 0)) { + closesocket(accepted_sock); + return INVALID_SOCKET; + } + + return accepted_sock; +} + +/*- + * BIO_closesocket - Close a socket + * @sock: the socket to close + */ +int BIO_closesocket(int sock) +{ + if (closesocket(sock) < 0) + return 0; + return 1; +} +#endif diff --git a/contrib/libs/openssl/crypto/bio/bf_buff.c b/contrib/libs/openssl/crypto/bio/bf_buff.c index bdc3fddecc..51ae1f918d 100644 --- a/contrib/libs/openssl/crypto/bio/bf_buff.c +++ b/contrib/libs/openssl/crypto/bio/bf_buff.c @@ -1,475 +1,475 @@ -/* - * Copyright 1995-2016 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 - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -#include <stdio.h> -#include <errno.h> +/* + * Copyright 1995-2016 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 + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include <errno.h> #include "bio_local.h" -#include "internal/cryptlib.h" - -static int buffer_write(BIO *h, const char *buf, int num); -static int buffer_read(BIO *h, char *buf, int size); -static int buffer_puts(BIO *h, const char *str); -static int buffer_gets(BIO *h, char *str, int size); -static long buffer_ctrl(BIO *h, int cmd, long arg1, void *arg2); -static int buffer_new(BIO *h); -static int buffer_free(BIO *data); -static long buffer_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp); -#define DEFAULT_BUFFER_SIZE 4096 - -static const BIO_METHOD methods_buffer = { - BIO_TYPE_BUFFER, - "buffer", - /* TODO: Convert to new style write function */ - bwrite_conv, - buffer_write, - /* TODO: Convert to new style read function */ - bread_conv, - buffer_read, - buffer_puts, - buffer_gets, - buffer_ctrl, - buffer_new, - buffer_free, - buffer_callback_ctrl, -}; - -const BIO_METHOD *BIO_f_buffer(void) -{ - return &methods_buffer; -} - -static int buffer_new(BIO *bi) -{ - BIO_F_BUFFER_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); - - if (ctx == NULL) - return 0; - ctx->ibuf_size = DEFAULT_BUFFER_SIZE; - ctx->ibuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE); - if (ctx->ibuf == NULL) { - OPENSSL_free(ctx); - return 0; - } - ctx->obuf_size = DEFAULT_BUFFER_SIZE; - ctx->obuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE); - if (ctx->obuf == NULL) { - OPENSSL_free(ctx->ibuf); - OPENSSL_free(ctx); - return 0; - } - - bi->init = 1; - bi->ptr = (char *)ctx; - bi->flags = 0; - return 1; -} - -static int buffer_free(BIO *a) -{ - BIO_F_BUFFER_CTX *b; - - if (a == NULL) - return 0; - b = (BIO_F_BUFFER_CTX *)a->ptr; - OPENSSL_free(b->ibuf); - OPENSSL_free(b->obuf); - OPENSSL_free(a->ptr); - a->ptr = NULL; - a->init = 0; - a->flags = 0; - return 1; -} - -static int buffer_read(BIO *b, char *out, int outl) -{ - int i, num = 0; - BIO_F_BUFFER_CTX *ctx; - - if (out == NULL) - return 0; - ctx = (BIO_F_BUFFER_CTX *)b->ptr; - - if ((ctx == NULL) || (b->next_bio == NULL)) - return 0; - num = 0; - BIO_clear_retry_flags(b); - - start: - i = ctx->ibuf_len; - /* If there is stuff left over, grab it */ - if (i != 0) { - if (i > outl) - i = outl; - memcpy(out, &(ctx->ibuf[ctx->ibuf_off]), i); - ctx->ibuf_off += i; - ctx->ibuf_len -= i; - num += i; - if (outl == i) - return num; - outl -= i; - out += i; - } - - /* - * We may have done a partial read. try to do more. We have nothing in - * the buffer. If we get an error and have read some data, just return it - * and let them retry to get the error again. copy direct to parent - * address space - */ - if (outl > ctx->ibuf_size) { - for (;;) { - i = BIO_read(b->next_bio, out, outl); - if (i <= 0) { - BIO_copy_next_retry(b); - if (i < 0) - return ((num > 0) ? num : i); - if (i == 0) - return num; - } - num += i; - if (outl == i) - return num; - out += i; - outl -= i; - } - } - /* else */ - - /* we are going to be doing some buffering */ - i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size); - if (i <= 0) { - BIO_copy_next_retry(b); - if (i < 0) - return ((num > 0) ? num : i); - if (i == 0) - return num; - } - ctx->ibuf_off = 0; - ctx->ibuf_len = i; - - /* Lets re-read using ourselves :-) */ - goto start; -} - -static int buffer_write(BIO *b, const char *in, int inl) -{ - int i, num = 0; - BIO_F_BUFFER_CTX *ctx; - - if ((in == NULL) || (inl <= 0)) - return 0; - ctx = (BIO_F_BUFFER_CTX *)b->ptr; - if ((ctx == NULL) || (b->next_bio == NULL)) - return 0; - - BIO_clear_retry_flags(b); - start: - i = ctx->obuf_size - (ctx->obuf_len + ctx->obuf_off); - /* add to buffer and return */ - if (i >= inl) { - memcpy(&(ctx->obuf[ctx->obuf_off + ctx->obuf_len]), in, inl); - ctx->obuf_len += inl; - return (num + inl); - } - /* else */ - /* stuff already in buffer, so add to it first, then flush */ - if (ctx->obuf_len != 0) { - if (i > 0) { /* lets fill it up if we can */ - memcpy(&(ctx->obuf[ctx->obuf_off + ctx->obuf_len]), in, i); - in += i; - inl -= i; - num += i; - ctx->obuf_len += i; - } - /* we now have a full buffer needing flushing */ - for (;;) { - i = BIO_write(b->next_bio, &(ctx->obuf[ctx->obuf_off]), - ctx->obuf_len); - if (i <= 0) { - BIO_copy_next_retry(b); - - if (i < 0) - return ((num > 0) ? num : i); - if (i == 0) - return num; - } - ctx->obuf_off += i; - ctx->obuf_len -= i; - if (ctx->obuf_len == 0) - break; - } - } - /* - * we only get here if the buffer has been flushed and we still have - * stuff to write - */ - ctx->obuf_off = 0; - - /* we now have inl bytes to write */ - while (inl >= ctx->obuf_size) { - i = BIO_write(b->next_bio, in, inl); - if (i <= 0) { - BIO_copy_next_retry(b); - if (i < 0) - return ((num > 0) ? num : i); - if (i == 0) - return num; - } - num += i; - in += i; - inl -= i; - if (inl == 0) - return num; - } - - /* - * copy the rest into the buffer since we have only a small amount left - */ - goto start; -} - -static long buffer_ctrl(BIO *b, int cmd, long num, void *ptr) -{ - BIO *dbio; - BIO_F_BUFFER_CTX *ctx; - long ret = 1; - char *p1, *p2; - int r, i, *ip; - int ibs, obs; - - ctx = (BIO_F_BUFFER_CTX *)b->ptr; - - switch (cmd) { - case BIO_CTRL_RESET: - ctx->ibuf_off = 0; - ctx->ibuf_len = 0; - ctx->obuf_off = 0; - ctx->obuf_len = 0; - if (b->next_bio == NULL) - return 0; - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); - break; - case BIO_CTRL_EOF: - if (ctx->ibuf_len > 0) - return 0; - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); - break; - case BIO_CTRL_INFO: - ret = (long)ctx->obuf_len; - break; - case BIO_C_GET_BUFF_NUM_LINES: - ret = 0; - p1 = ctx->ibuf; - for (i = 0; i < ctx->ibuf_len; i++) { - if (p1[ctx->ibuf_off + i] == '\n') - ret++; - } - break; - case BIO_CTRL_WPENDING: - ret = (long)ctx->obuf_len; - if (ret == 0) { - if (b->next_bio == NULL) - return 0; - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); - } - break; - case BIO_CTRL_PENDING: - ret = (long)ctx->ibuf_len; - if (ret == 0) { - if (b->next_bio == NULL) - return 0; - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); - } - break; - case BIO_C_SET_BUFF_READ_DATA: - if (num > ctx->ibuf_size) { - p1 = OPENSSL_malloc((int)num); - if (p1 == NULL) - goto malloc_error; - OPENSSL_free(ctx->ibuf); - ctx->ibuf = p1; - } - ctx->ibuf_off = 0; - ctx->ibuf_len = (int)num; - memcpy(ctx->ibuf, ptr, (int)num); - ret = 1; - break; - case BIO_C_SET_BUFF_SIZE: - if (ptr != NULL) { - ip = (int *)ptr; - if (*ip == 0) { - ibs = (int)num; - obs = ctx->obuf_size; - } else { /* if (*ip == 1) */ - - ibs = ctx->ibuf_size; - obs = (int)num; - } - } else { - ibs = (int)num; - obs = (int)num; - } - p1 = ctx->ibuf; - p2 = ctx->obuf; - if ((ibs > DEFAULT_BUFFER_SIZE) && (ibs != ctx->ibuf_size)) { - p1 = OPENSSL_malloc((int)num); - if (p1 == NULL) - goto malloc_error; - } - if ((obs > DEFAULT_BUFFER_SIZE) && (obs != ctx->obuf_size)) { - p2 = OPENSSL_malloc((int)num); - if (p2 == NULL) { - if (p1 != ctx->ibuf) - OPENSSL_free(p1); - goto malloc_error; - } - } - if (ctx->ibuf != p1) { - OPENSSL_free(ctx->ibuf); - ctx->ibuf = p1; - ctx->ibuf_off = 0; - ctx->ibuf_len = 0; - ctx->ibuf_size = ibs; - } - if (ctx->obuf != p2) { - OPENSSL_free(ctx->obuf); - ctx->obuf = p2; - ctx->obuf_off = 0; - ctx->obuf_len = 0; - ctx->obuf_size = obs; - } - break; - case BIO_C_DO_STATE_MACHINE: - if (b->next_bio == NULL) - return 0; - BIO_clear_retry_flags(b); - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); - BIO_copy_next_retry(b); - break; - - case BIO_CTRL_FLUSH: - if (b->next_bio == NULL) - return 0; - if (ctx->obuf_len <= 0) { - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); - break; - } - - for (;;) { - BIO_clear_retry_flags(b); - if (ctx->obuf_len > 0) { - r = BIO_write(b->next_bio, - &(ctx->obuf[ctx->obuf_off]), ctx->obuf_len); - BIO_copy_next_retry(b); - if (r <= 0) - return (long)r; - ctx->obuf_off += r; - ctx->obuf_len -= r; - } else { - ctx->obuf_len = 0; - ctx->obuf_off = 0; - break; - } - } - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); - break; - case BIO_CTRL_DUP: - dbio = (BIO *)ptr; - if (!BIO_set_read_buffer_size(dbio, ctx->ibuf_size) || - !BIO_set_write_buffer_size(dbio, ctx->obuf_size)) - ret = 0; - break; - case BIO_CTRL_PEEK: - /* Ensure there's stuff in the input buffer */ - { - char fake_buf[1]; - (void)buffer_read(b, fake_buf, 0); - } - if (num > ctx->ibuf_len) - num = ctx->ibuf_len; - memcpy(ptr, &(ctx->ibuf[ctx->ibuf_off]), num); - ret = num; - break; - default: - if (b->next_bio == NULL) - return 0; - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); - break; - } - return ret; - malloc_error: - BIOerr(BIO_F_BUFFER_CTRL, ERR_R_MALLOC_FAILURE); - return 0; -} - -static long buffer_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) -{ - long ret = 1; - - if (b->next_bio == NULL) - return 0; - switch (cmd) { - default: - ret = BIO_callback_ctrl(b->next_bio, cmd, fp); - break; - } - return ret; -} - -static int buffer_gets(BIO *b, char *buf, int size) -{ - BIO_F_BUFFER_CTX *ctx; - int num = 0, i, flag; - char *p; - - ctx = (BIO_F_BUFFER_CTX *)b->ptr; - size--; /* reserve space for a '\0' */ - BIO_clear_retry_flags(b); - - for (;;) { - if (ctx->ibuf_len > 0) { - p = &(ctx->ibuf[ctx->ibuf_off]); - flag = 0; - for (i = 0; (i < ctx->ibuf_len) && (i < size); i++) { - *(buf++) = p[i]; - if (p[i] == '\n') { - flag = 1; - i++; - break; - } - } - num += i; - size -= i; - ctx->ibuf_len -= i; - ctx->ibuf_off += i; - if (flag || size == 0) { - *buf = '\0'; - return num; - } - } else { /* read another chunk */ - - i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size); - if (i <= 0) { - BIO_copy_next_retry(b); - *buf = '\0'; - if (i < 0) - return ((num > 0) ? num : i); - if (i == 0) - return num; - } - ctx->ibuf_len = i; - ctx->ibuf_off = 0; - } - } -} - -static int buffer_puts(BIO *b, const char *str) -{ - return buffer_write(b, str, strlen(str)); -} +#include "internal/cryptlib.h" + +static int buffer_write(BIO *h, const char *buf, int num); +static int buffer_read(BIO *h, char *buf, int size); +static int buffer_puts(BIO *h, const char *str); +static int buffer_gets(BIO *h, char *str, int size); +static long buffer_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int buffer_new(BIO *h); +static int buffer_free(BIO *data); +static long buffer_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp); +#define DEFAULT_BUFFER_SIZE 4096 + +static const BIO_METHOD methods_buffer = { + BIO_TYPE_BUFFER, + "buffer", + /* TODO: Convert to new style write function */ + bwrite_conv, + buffer_write, + /* TODO: Convert to new style read function */ + bread_conv, + buffer_read, + buffer_puts, + buffer_gets, + buffer_ctrl, + buffer_new, + buffer_free, + buffer_callback_ctrl, +}; + +const BIO_METHOD *BIO_f_buffer(void) +{ + return &methods_buffer; +} + +static int buffer_new(BIO *bi) +{ + BIO_F_BUFFER_CTX *ctx = OPENSSL_zalloc(sizeof(*ctx)); + + if (ctx == NULL) + return 0; + ctx->ibuf_size = DEFAULT_BUFFER_SIZE; + ctx->ibuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE); + if (ctx->ibuf == NULL) { + OPENSSL_free(ctx); + return 0; + } + ctx->obuf_size = DEFAULT_BUFFER_SIZE; + ctx->obuf = OPENSSL_malloc(DEFAULT_BUFFER_SIZE); + if (ctx->obuf == NULL) { + OPENSSL_free(ctx->ibuf); + OPENSSL_free(ctx); + return 0; + } + + bi->init = 1; + bi->ptr = (char *)ctx; + bi->flags = 0; + return 1; +} + +static int buffer_free(BIO *a) +{ + BIO_F_BUFFER_CTX *b; + + if (a == NULL) + return 0; + b = (BIO_F_BUFFER_CTX *)a->ptr; + OPENSSL_free(b->ibuf); + OPENSSL_free(b->obuf); + OPENSSL_free(a->ptr); + a->ptr = NULL; + a->init = 0; + a->flags = 0; + return 1; +} + +static int buffer_read(BIO *b, char *out, int outl) +{ + int i, num = 0; + BIO_F_BUFFER_CTX *ctx; + + if (out == NULL) + return 0; + ctx = (BIO_F_BUFFER_CTX *)b->ptr; + + if ((ctx == NULL) || (b->next_bio == NULL)) + return 0; + num = 0; + BIO_clear_retry_flags(b); + + start: + i = ctx->ibuf_len; + /* If there is stuff left over, grab it */ + if (i != 0) { + if (i > outl) + i = outl; + memcpy(out, &(ctx->ibuf[ctx->ibuf_off]), i); + ctx->ibuf_off += i; + ctx->ibuf_len -= i; + num += i; + if (outl == i) + return num; + outl -= i; + out += i; + } + + /* + * We may have done a partial read. try to do more. We have nothing in + * the buffer. If we get an error and have read some data, just return it + * and let them retry to get the error again. copy direct to parent + * address space + */ + if (outl > ctx->ibuf_size) { + for (;;) { + i = BIO_read(b->next_bio, out, outl); + if (i <= 0) { + BIO_copy_next_retry(b); + if (i < 0) + return ((num > 0) ? num : i); + if (i == 0) + return num; + } + num += i; + if (outl == i) + return num; + out += i; + outl -= i; + } + } + /* else */ + + /* we are going to be doing some buffering */ + i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size); + if (i <= 0) { + BIO_copy_next_retry(b); + if (i < 0) + return ((num > 0) ? num : i); + if (i == 0) + return num; + } + ctx->ibuf_off = 0; + ctx->ibuf_len = i; + + /* Lets re-read using ourselves :-) */ + goto start; +} + +static int buffer_write(BIO *b, const char *in, int inl) +{ + int i, num = 0; + BIO_F_BUFFER_CTX *ctx; + + if ((in == NULL) || (inl <= 0)) + return 0; + ctx = (BIO_F_BUFFER_CTX *)b->ptr; + if ((ctx == NULL) || (b->next_bio == NULL)) + return 0; + + BIO_clear_retry_flags(b); + start: + i = ctx->obuf_size - (ctx->obuf_len + ctx->obuf_off); + /* add to buffer and return */ + if (i >= inl) { + memcpy(&(ctx->obuf[ctx->obuf_off + ctx->obuf_len]), in, inl); + ctx->obuf_len += inl; + return (num + inl); + } + /* else */ + /* stuff already in buffer, so add to it first, then flush */ + if (ctx->obuf_len != 0) { + if (i > 0) { /* lets fill it up if we can */ + memcpy(&(ctx->obuf[ctx->obuf_off + ctx->obuf_len]), in, i); + in += i; + inl -= i; + num += i; + ctx->obuf_len += i; + } + /* we now have a full buffer needing flushing */ + for (;;) { + i = BIO_write(b->next_bio, &(ctx->obuf[ctx->obuf_off]), + ctx->obuf_len); + if (i <= 0) { + BIO_copy_next_retry(b); + + if (i < 0) + return ((num > 0) ? num : i); + if (i == 0) + return num; + } + ctx->obuf_off += i; + ctx->obuf_len -= i; + if (ctx->obuf_len == 0) + break; + } + } + /* + * we only get here if the buffer has been flushed and we still have + * stuff to write + */ + ctx->obuf_off = 0; + + /* we now have inl bytes to write */ + while (inl >= ctx->obuf_size) { + i = BIO_write(b->next_bio, in, inl); + if (i <= 0) { + BIO_copy_next_retry(b); + if (i < 0) + return ((num > 0) ? num : i); + if (i == 0) + return num; + } + num += i; + in += i; + inl -= i; + if (inl == 0) + return num; + } + + /* + * copy the rest into the buffer since we have only a small amount left + */ + goto start; +} + +static long buffer_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + BIO *dbio; + BIO_F_BUFFER_CTX *ctx; + long ret = 1; + char *p1, *p2; + int r, i, *ip; + int ibs, obs; + + ctx = (BIO_F_BUFFER_CTX *)b->ptr; + + switch (cmd) { + case BIO_CTRL_RESET: + ctx->ibuf_off = 0; + ctx->ibuf_len = 0; + ctx->obuf_off = 0; + ctx->obuf_len = 0; + if (b->next_bio == NULL) + return 0; + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + break; + case BIO_CTRL_EOF: + if (ctx->ibuf_len > 0) + return 0; + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + break; + case BIO_CTRL_INFO: + ret = (long)ctx->obuf_len; + break; + case BIO_C_GET_BUFF_NUM_LINES: + ret = 0; + p1 = ctx->ibuf; + for (i = 0; i < ctx->ibuf_len; i++) { + if (p1[ctx->ibuf_off + i] == '\n') + ret++; + } + break; + case BIO_CTRL_WPENDING: + ret = (long)ctx->obuf_len; + if (ret == 0) { + if (b->next_bio == NULL) + return 0; + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + } + break; + case BIO_CTRL_PENDING: + ret = (long)ctx->ibuf_len; + if (ret == 0) { + if (b->next_bio == NULL) + return 0; + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + } + break; + case BIO_C_SET_BUFF_READ_DATA: + if (num > ctx->ibuf_size) { + p1 = OPENSSL_malloc((int)num); + if (p1 == NULL) + goto malloc_error; + OPENSSL_free(ctx->ibuf); + ctx->ibuf = p1; + } + ctx->ibuf_off = 0; + ctx->ibuf_len = (int)num; + memcpy(ctx->ibuf, ptr, (int)num); + ret = 1; + break; + case BIO_C_SET_BUFF_SIZE: + if (ptr != NULL) { + ip = (int *)ptr; + if (*ip == 0) { + ibs = (int)num; + obs = ctx->obuf_size; + } else { /* if (*ip == 1) */ + + ibs = ctx->ibuf_size; + obs = (int)num; + } + } else { + ibs = (int)num; + obs = (int)num; + } + p1 = ctx->ibuf; + p2 = ctx->obuf; + if ((ibs > DEFAULT_BUFFER_SIZE) && (ibs != ctx->ibuf_size)) { + p1 = OPENSSL_malloc((int)num); + if (p1 == NULL) + goto malloc_error; + } + if ((obs > DEFAULT_BUFFER_SIZE) && (obs != ctx->obuf_size)) { + p2 = OPENSSL_malloc((int)num); + if (p2 == NULL) { + if (p1 != ctx->ibuf) + OPENSSL_free(p1); + goto malloc_error; + } + } + if (ctx->ibuf != p1) { + OPENSSL_free(ctx->ibuf); + ctx->ibuf = p1; + ctx->ibuf_off = 0; + ctx->ibuf_len = 0; + ctx->ibuf_size = ibs; + } + if (ctx->obuf != p2) { + OPENSSL_free(ctx->obuf); + ctx->obuf = p2; + ctx->obuf_off = 0; + ctx->obuf_len = 0; + ctx->obuf_size = obs; + } + break; + case BIO_C_DO_STATE_MACHINE: + if (b->next_bio == NULL) + return 0; + BIO_clear_retry_flags(b); + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + BIO_copy_next_retry(b); + break; + + case BIO_CTRL_FLUSH: + if (b->next_bio == NULL) + return 0; + if (ctx->obuf_len <= 0) { + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + break; + } + + for (;;) { + BIO_clear_retry_flags(b); + if (ctx->obuf_len > 0) { + r = BIO_write(b->next_bio, + &(ctx->obuf[ctx->obuf_off]), ctx->obuf_len); + BIO_copy_next_retry(b); + if (r <= 0) + return (long)r; + ctx->obuf_off += r; + ctx->obuf_len -= r; + } else { + ctx->obuf_len = 0; + ctx->obuf_off = 0; + break; + } + } + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + break; + case BIO_CTRL_DUP: + dbio = (BIO *)ptr; + if (!BIO_set_read_buffer_size(dbio, ctx->ibuf_size) || + !BIO_set_write_buffer_size(dbio, ctx->obuf_size)) + ret = 0; + break; + case BIO_CTRL_PEEK: + /* Ensure there's stuff in the input buffer */ + { + char fake_buf[1]; + (void)buffer_read(b, fake_buf, 0); + } + if (num > ctx->ibuf_len) + num = ctx->ibuf_len; + memcpy(ptr, &(ctx->ibuf[ctx->ibuf_off]), num); + ret = num; + break; + default: + if (b->next_bio == NULL) + return 0; + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + break; + } + return ret; + malloc_error: + BIOerr(BIO_F_BUFFER_CTRL, ERR_R_MALLOC_FAILURE); + return 0; +} + +static long buffer_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) +{ + long ret = 1; + + if (b->next_bio == NULL) + return 0; + switch (cmd) { + default: + ret = BIO_callback_ctrl(b->next_bio, cmd, fp); + break; + } + return ret; +} + +static int buffer_gets(BIO *b, char *buf, int size) +{ + BIO_F_BUFFER_CTX *ctx; + int num = 0, i, flag; + char *p; + + ctx = (BIO_F_BUFFER_CTX *)b->ptr; + size--; /* reserve space for a '\0' */ + BIO_clear_retry_flags(b); + + for (;;) { + if (ctx->ibuf_len > 0) { + p = &(ctx->ibuf[ctx->ibuf_off]); + flag = 0; + for (i = 0; (i < ctx->ibuf_len) && (i < size); i++) { + *(buf++) = p[i]; + if (p[i] == '\n') { + flag = 1; + i++; + break; + } + } + num += i; + size -= i; + ctx->ibuf_len -= i; + ctx->ibuf_off += i; + if (flag || size == 0) { + *buf = '\0'; + return num; + } + } else { /* read another chunk */ + + i = BIO_read(b->next_bio, ctx->ibuf, ctx->ibuf_size); + if (i <= 0) { + BIO_copy_next_retry(b); + *buf = '\0'; + if (i < 0) + return ((num > 0) ? num : i); + if (i == 0) + return num; + } + ctx->ibuf_len = i; + ctx->ibuf_off = 0; + } + } +} + +static int buffer_puts(BIO *b, const char *str) +{ + return buffer_write(b, str, strlen(str)); +} diff --git a/contrib/libs/openssl/crypto/bio/bf_lbuf.c b/contrib/libs/openssl/crypto/bio/bf_lbuf.c index 260df96cf8..72f9901813 100644 --- a/contrib/libs/openssl/crypto/bio/bf_lbuf.c +++ b/contrib/libs/openssl/crypto/bio/bf_lbuf.c @@ -1,326 +1,326 @@ -/* - * Copyright 1995-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 - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -#include <stdio.h> -#include <errno.h> +/* + * Copyright 1995-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 + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include <errno.h> #include "bio_local.h" -#include "internal/cryptlib.h" -#include <openssl/evp.h> - -static int linebuffer_write(BIO *h, const char *buf, int num); -static int linebuffer_read(BIO *h, char *buf, int size); -static int linebuffer_puts(BIO *h, const char *str); -static int linebuffer_gets(BIO *h, char *str, int size); -static long linebuffer_ctrl(BIO *h, int cmd, long arg1, void *arg2); -static int linebuffer_new(BIO *h); -static int linebuffer_free(BIO *data); -static long linebuffer_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp); - -/* A 10k maximum should be enough for most purposes */ -#define DEFAULT_LINEBUFFER_SIZE 1024*10 - -/* #define DEBUG */ - -static const BIO_METHOD methods_linebuffer = { - BIO_TYPE_LINEBUFFER, - "linebuffer", - /* TODO: Convert to new style write function */ - bwrite_conv, - linebuffer_write, - /* TODO: Convert to new style read function */ - bread_conv, - linebuffer_read, - linebuffer_puts, - linebuffer_gets, - linebuffer_ctrl, - linebuffer_new, - linebuffer_free, - linebuffer_callback_ctrl, -}; - -const BIO_METHOD *BIO_f_linebuffer(void) -{ - return &methods_linebuffer; -} - -typedef struct bio_linebuffer_ctx_struct { - char *obuf; /* the output char array */ - int obuf_size; /* how big is the output buffer */ - int obuf_len; /* how many bytes are in it */ -} BIO_LINEBUFFER_CTX; - -static int linebuffer_new(BIO *bi) -{ - BIO_LINEBUFFER_CTX *ctx; - - if ((ctx = OPENSSL_malloc(sizeof(*ctx))) == NULL) { - BIOerr(BIO_F_LINEBUFFER_NEW, ERR_R_MALLOC_FAILURE); - return 0; - } - ctx->obuf = OPENSSL_malloc(DEFAULT_LINEBUFFER_SIZE); - if (ctx->obuf == NULL) { - BIOerr(BIO_F_LINEBUFFER_NEW, ERR_R_MALLOC_FAILURE); - OPENSSL_free(ctx); - return 0; - } - ctx->obuf_size = DEFAULT_LINEBUFFER_SIZE; - ctx->obuf_len = 0; - - bi->init = 1; - bi->ptr = (char *)ctx; - bi->flags = 0; - return 1; -} - -static int linebuffer_free(BIO *a) -{ - BIO_LINEBUFFER_CTX *b; - - if (a == NULL) - return 0; - b = (BIO_LINEBUFFER_CTX *)a->ptr; - OPENSSL_free(b->obuf); - OPENSSL_free(a->ptr); - a->ptr = NULL; - a->init = 0; - a->flags = 0; - return 1; -} - -static int linebuffer_read(BIO *b, char *out, int outl) -{ - int ret = 0; - - if (out == NULL) - return 0; - if (b->next_bio == NULL) - return 0; - ret = BIO_read(b->next_bio, out, outl); - BIO_clear_retry_flags(b); - BIO_copy_next_retry(b); - return ret; -} - -static int linebuffer_write(BIO *b, const char *in, int inl) -{ - int i, num = 0, foundnl; - BIO_LINEBUFFER_CTX *ctx; - - if ((in == NULL) || (inl <= 0)) - return 0; - ctx = (BIO_LINEBUFFER_CTX *)b->ptr; - if ((ctx == NULL) || (b->next_bio == NULL)) - return 0; - - BIO_clear_retry_flags(b); - - do { - const char *p; - char c; - - for (p = in, c = '\0'; p < in + inl && (c = *p) != '\n'; p++) ; - if (c == '\n') { - p++; - foundnl = 1; - } else - foundnl = 0; - - /* - * If a NL was found and we already have text in the save buffer, - * concatenate them and write - */ - while ((foundnl || p - in > ctx->obuf_size - ctx->obuf_len) - && ctx->obuf_len > 0) { - int orig_olen = ctx->obuf_len; - - i = ctx->obuf_size - ctx->obuf_len; - if (p - in > 0) { - if (i >= p - in) { - memcpy(&(ctx->obuf[ctx->obuf_len]), in, p - in); - ctx->obuf_len += p - in; - inl -= p - in; - num += p - in; - in = p; - } else { - memcpy(&(ctx->obuf[ctx->obuf_len]), in, i); - ctx->obuf_len += i; - inl -= i; - in += i; - num += i; - } - } - i = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); - if (i <= 0) { - ctx->obuf_len = orig_olen; - BIO_copy_next_retry(b); - - if (i < 0) - return ((num > 0) ? num : i); - if (i == 0) - return num; - } - if (i < ctx->obuf_len) - memmove(ctx->obuf, ctx->obuf + i, ctx->obuf_len - i); - ctx->obuf_len -= i; - } - - /* - * Now that the save buffer is emptied, let's write the input buffer - * if a NL was found and there is anything to write. - */ - if ((foundnl || p - in > ctx->obuf_size) && p - in > 0) { - i = BIO_write(b->next_bio, in, p - in); - if (i <= 0) { - BIO_copy_next_retry(b); - if (i < 0) - return ((num > 0) ? num : i); - if (i == 0) - return num; - } - num += i; - in += i; - inl -= i; - } - } - while (foundnl && inl > 0); - /* - * We've written as much as we can. The rest of the input buffer, if - * any, is text that doesn't and with a NL and therefore needs to be - * saved for the next trip. - */ - if (inl > 0) { - memcpy(&(ctx->obuf[ctx->obuf_len]), in, inl); - ctx->obuf_len += inl; - num += inl; - } - return num; -} - -static long linebuffer_ctrl(BIO *b, int cmd, long num, void *ptr) -{ - BIO *dbio; - BIO_LINEBUFFER_CTX *ctx; - long ret = 1; - char *p; - int r; - int obs; - - ctx = (BIO_LINEBUFFER_CTX *)b->ptr; - - switch (cmd) { - case BIO_CTRL_RESET: - ctx->obuf_len = 0; - if (b->next_bio == NULL) - return 0; - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); - break; - case BIO_CTRL_INFO: - ret = (long)ctx->obuf_len; - break; - case BIO_CTRL_WPENDING: - ret = (long)ctx->obuf_len; - if (ret == 0) { - if (b->next_bio == NULL) - return 0; - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); - } - break; - case BIO_C_SET_BUFF_SIZE: - obs = (int)num; - p = ctx->obuf; - if ((obs > DEFAULT_LINEBUFFER_SIZE) && (obs != ctx->obuf_size)) { - p = OPENSSL_malloc((int)num); - if (p == NULL) - goto malloc_error; - } - if (ctx->obuf != p) { - if (ctx->obuf_len > obs) { - ctx->obuf_len = obs; - } - memcpy(p, ctx->obuf, ctx->obuf_len); - OPENSSL_free(ctx->obuf); - ctx->obuf = p; - ctx->obuf_size = obs; - } - break; - case BIO_C_DO_STATE_MACHINE: - if (b->next_bio == NULL) - return 0; - BIO_clear_retry_flags(b); - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); - BIO_copy_next_retry(b); - break; - - case BIO_CTRL_FLUSH: - if (b->next_bio == NULL) - return 0; - if (ctx->obuf_len <= 0) { - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); - break; - } - - for (;;) { - BIO_clear_retry_flags(b); - if (ctx->obuf_len > 0) { - r = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); - BIO_copy_next_retry(b); - if (r <= 0) - return (long)r; - if (r < ctx->obuf_len) - memmove(ctx->obuf, ctx->obuf + r, ctx->obuf_len - r); - ctx->obuf_len -= r; - } else { - ctx->obuf_len = 0; - break; - } - } - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); - break; - case BIO_CTRL_DUP: - dbio = (BIO *)ptr; - if (!BIO_set_write_buffer_size(dbio, ctx->obuf_size)) - ret = 0; - break; - default: - if (b->next_bio == NULL) - return 0; - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); - break; - } - return ret; - malloc_error: - BIOerr(BIO_F_LINEBUFFER_CTRL, ERR_R_MALLOC_FAILURE); - return 0; -} - -static long linebuffer_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) -{ - long ret = 1; - - if (b->next_bio == NULL) - return 0; - switch (cmd) { - default: - ret = BIO_callback_ctrl(b->next_bio, cmd, fp); - break; - } - return ret; -} - -static int linebuffer_gets(BIO *b, char *buf, int size) -{ - if (b->next_bio == NULL) - return 0; - return BIO_gets(b->next_bio, buf, size); -} - -static int linebuffer_puts(BIO *b, const char *str) -{ - return linebuffer_write(b, str, strlen(str)); -} +#include "internal/cryptlib.h" +#include <openssl/evp.h> + +static int linebuffer_write(BIO *h, const char *buf, int num); +static int linebuffer_read(BIO *h, char *buf, int size); +static int linebuffer_puts(BIO *h, const char *str); +static int linebuffer_gets(BIO *h, char *str, int size); +static long linebuffer_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int linebuffer_new(BIO *h); +static int linebuffer_free(BIO *data); +static long linebuffer_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp); + +/* A 10k maximum should be enough for most purposes */ +#define DEFAULT_LINEBUFFER_SIZE 1024*10 + +/* #define DEBUG */ + +static const BIO_METHOD methods_linebuffer = { + BIO_TYPE_LINEBUFFER, + "linebuffer", + /* TODO: Convert to new style write function */ + bwrite_conv, + linebuffer_write, + /* TODO: Convert to new style read function */ + bread_conv, + linebuffer_read, + linebuffer_puts, + linebuffer_gets, + linebuffer_ctrl, + linebuffer_new, + linebuffer_free, + linebuffer_callback_ctrl, +}; + +const BIO_METHOD *BIO_f_linebuffer(void) +{ + return &methods_linebuffer; +} + +typedef struct bio_linebuffer_ctx_struct { + char *obuf; /* the output char array */ + int obuf_size; /* how big is the output buffer */ + int obuf_len; /* how many bytes are in it */ +} BIO_LINEBUFFER_CTX; + +static int linebuffer_new(BIO *bi) +{ + BIO_LINEBUFFER_CTX *ctx; + + if ((ctx = OPENSSL_malloc(sizeof(*ctx))) == NULL) { + BIOerr(BIO_F_LINEBUFFER_NEW, ERR_R_MALLOC_FAILURE); + return 0; + } + ctx->obuf = OPENSSL_malloc(DEFAULT_LINEBUFFER_SIZE); + if (ctx->obuf == NULL) { + BIOerr(BIO_F_LINEBUFFER_NEW, ERR_R_MALLOC_FAILURE); + OPENSSL_free(ctx); + return 0; + } + ctx->obuf_size = DEFAULT_LINEBUFFER_SIZE; + ctx->obuf_len = 0; + + bi->init = 1; + bi->ptr = (char *)ctx; + bi->flags = 0; + return 1; +} + +static int linebuffer_free(BIO *a) +{ + BIO_LINEBUFFER_CTX *b; + + if (a == NULL) + return 0; + b = (BIO_LINEBUFFER_CTX *)a->ptr; + OPENSSL_free(b->obuf); + OPENSSL_free(a->ptr); + a->ptr = NULL; + a->init = 0; + a->flags = 0; + return 1; +} + +static int linebuffer_read(BIO *b, char *out, int outl) +{ + int ret = 0; + + if (out == NULL) + return 0; + if (b->next_bio == NULL) + return 0; + ret = BIO_read(b->next_bio, out, outl); + BIO_clear_retry_flags(b); + BIO_copy_next_retry(b); + return ret; +} + +static int linebuffer_write(BIO *b, const char *in, int inl) +{ + int i, num = 0, foundnl; + BIO_LINEBUFFER_CTX *ctx; + + if ((in == NULL) || (inl <= 0)) + return 0; + ctx = (BIO_LINEBUFFER_CTX *)b->ptr; + if ((ctx == NULL) || (b->next_bio == NULL)) + return 0; + + BIO_clear_retry_flags(b); + + do { + const char *p; + char c; + + for (p = in, c = '\0'; p < in + inl && (c = *p) != '\n'; p++) ; + if (c == '\n') { + p++; + foundnl = 1; + } else + foundnl = 0; + + /* + * If a NL was found and we already have text in the save buffer, + * concatenate them and write + */ + while ((foundnl || p - in > ctx->obuf_size - ctx->obuf_len) + && ctx->obuf_len > 0) { + int orig_olen = ctx->obuf_len; + + i = ctx->obuf_size - ctx->obuf_len; + if (p - in > 0) { + if (i >= p - in) { + memcpy(&(ctx->obuf[ctx->obuf_len]), in, p - in); + ctx->obuf_len += p - in; + inl -= p - in; + num += p - in; + in = p; + } else { + memcpy(&(ctx->obuf[ctx->obuf_len]), in, i); + ctx->obuf_len += i; + inl -= i; + in += i; + num += i; + } + } + i = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); + if (i <= 0) { + ctx->obuf_len = orig_olen; + BIO_copy_next_retry(b); + + if (i < 0) + return ((num > 0) ? num : i); + if (i == 0) + return num; + } + if (i < ctx->obuf_len) + memmove(ctx->obuf, ctx->obuf + i, ctx->obuf_len - i); + ctx->obuf_len -= i; + } + + /* + * Now that the save buffer is emptied, let's write the input buffer + * if a NL was found and there is anything to write. + */ + if ((foundnl || p - in > ctx->obuf_size) && p - in > 0) { + i = BIO_write(b->next_bio, in, p - in); + if (i <= 0) { + BIO_copy_next_retry(b); + if (i < 0) + return ((num > 0) ? num : i); + if (i == 0) + return num; + } + num += i; + in += i; + inl -= i; + } + } + while (foundnl && inl > 0); + /* + * We've written as much as we can. The rest of the input buffer, if + * any, is text that doesn't and with a NL and therefore needs to be + * saved for the next trip. + */ + if (inl > 0) { + memcpy(&(ctx->obuf[ctx->obuf_len]), in, inl); + ctx->obuf_len += inl; + num += inl; + } + return num; +} + +static long linebuffer_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + BIO *dbio; + BIO_LINEBUFFER_CTX *ctx; + long ret = 1; + char *p; + int r; + int obs; + + ctx = (BIO_LINEBUFFER_CTX *)b->ptr; + + switch (cmd) { + case BIO_CTRL_RESET: + ctx->obuf_len = 0; + if (b->next_bio == NULL) + return 0; + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + break; + case BIO_CTRL_INFO: + ret = (long)ctx->obuf_len; + break; + case BIO_CTRL_WPENDING: + ret = (long)ctx->obuf_len; + if (ret == 0) { + if (b->next_bio == NULL) + return 0; + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + } + break; + case BIO_C_SET_BUFF_SIZE: + obs = (int)num; + p = ctx->obuf; + if ((obs > DEFAULT_LINEBUFFER_SIZE) && (obs != ctx->obuf_size)) { + p = OPENSSL_malloc((int)num); + if (p == NULL) + goto malloc_error; + } + if (ctx->obuf != p) { + if (ctx->obuf_len > obs) { + ctx->obuf_len = obs; + } + memcpy(p, ctx->obuf, ctx->obuf_len); + OPENSSL_free(ctx->obuf); + ctx->obuf = p; + ctx->obuf_size = obs; + } + break; + case BIO_C_DO_STATE_MACHINE: + if (b->next_bio == NULL) + return 0; + BIO_clear_retry_flags(b); + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + BIO_copy_next_retry(b); + break; + + case BIO_CTRL_FLUSH: + if (b->next_bio == NULL) + return 0; + if (ctx->obuf_len <= 0) { + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + break; + } + + for (;;) { + BIO_clear_retry_flags(b); + if (ctx->obuf_len > 0) { + r = BIO_write(b->next_bio, ctx->obuf, ctx->obuf_len); + BIO_copy_next_retry(b); + if (r <= 0) + return (long)r; + if (r < ctx->obuf_len) + memmove(ctx->obuf, ctx->obuf + r, ctx->obuf_len - r); + ctx->obuf_len -= r; + } else { + ctx->obuf_len = 0; + break; + } + } + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + break; + case BIO_CTRL_DUP: + dbio = (BIO *)ptr; + if (!BIO_set_write_buffer_size(dbio, ctx->obuf_size)) + ret = 0; + break; + default: + if (b->next_bio == NULL) + return 0; + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + break; + } + return ret; + malloc_error: + BIOerr(BIO_F_LINEBUFFER_CTRL, ERR_R_MALLOC_FAILURE); + return 0; +} + +static long linebuffer_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) +{ + long ret = 1; + + if (b->next_bio == NULL) + return 0; + switch (cmd) { + default: + ret = BIO_callback_ctrl(b->next_bio, cmd, fp); + break; + } + return ret; +} + +static int linebuffer_gets(BIO *b, char *buf, int size) +{ + if (b->next_bio == NULL) + return 0; + return BIO_gets(b->next_bio, buf, size); +} + +static int linebuffer_puts(BIO *b, const char *str) +{ + return linebuffer_write(b, str, strlen(str)); +} diff --git a/contrib/libs/openssl/crypto/bio/bf_nbio.c b/contrib/libs/openssl/crypto/bio/bf_nbio.c index 123f77f5e9..dd7011ab66 100644 --- a/contrib/libs/openssl/crypto/bio/bf_nbio.c +++ b/contrib/libs/openssl/crypto/bio/bf_nbio.c @@ -1,200 +1,200 @@ -/* - * Copyright 1995-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 - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -#include <stdio.h> -#include <errno.h> +/* + * Copyright 1995-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 + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include <errno.h> #include "bio_local.h" -#include "internal/cryptlib.h" -#include <openssl/rand.h> - -/* - * BIO_put and BIO_get both add to the digest, BIO_gets returns the digest - */ - -static int nbiof_write(BIO *h, const char *buf, int num); -static int nbiof_read(BIO *h, char *buf, int size); -static int nbiof_puts(BIO *h, const char *str); -static int nbiof_gets(BIO *h, char *str, int size); -static long nbiof_ctrl(BIO *h, int cmd, long arg1, void *arg2); -static int nbiof_new(BIO *h); -static int nbiof_free(BIO *data); -static long nbiof_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp); -typedef struct nbio_test_st { - /* only set if we sent a 'should retry' error */ - int lrn; - int lwn; -} NBIO_TEST; - -static const BIO_METHOD methods_nbiof = { - BIO_TYPE_NBIO_TEST, - "non-blocking IO test filter", - /* TODO: Convert to new style write function */ - bwrite_conv, - nbiof_write, - /* TODO: Convert to new style read function */ - bread_conv, - nbiof_read, - nbiof_puts, - nbiof_gets, - nbiof_ctrl, - nbiof_new, - nbiof_free, - nbiof_callback_ctrl, -}; - -const BIO_METHOD *BIO_f_nbio_test(void) -{ - return &methods_nbiof; -} - -static int nbiof_new(BIO *bi) -{ - NBIO_TEST *nt; - - if ((nt = OPENSSL_zalloc(sizeof(*nt))) == NULL) { - BIOerr(BIO_F_NBIOF_NEW, ERR_R_MALLOC_FAILURE); - return 0; - } - nt->lrn = -1; - nt->lwn = -1; - bi->ptr = (char *)nt; - bi->init = 1; - return 1; -} - -static int nbiof_free(BIO *a) -{ - if (a == NULL) - return 0; - OPENSSL_free(a->ptr); - a->ptr = NULL; - a->init = 0; - a->flags = 0; - return 1; -} - -static int nbiof_read(BIO *b, char *out, int outl) -{ - int ret = 0; - int num; - unsigned char n; - - if (out == NULL) - return 0; - if (b->next_bio == NULL) - return 0; - - BIO_clear_retry_flags(b); - if (RAND_priv_bytes(&n, 1) <= 0) - return -1; - num = (n & 0x07); - - if (outl > num) - outl = num; - - if (num == 0) { - ret = -1; - BIO_set_retry_read(b); - } else { - ret = BIO_read(b->next_bio, out, outl); - if (ret < 0) - BIO_copy_next_retry(b); - } - return ret; -} - -static int nbiof_write(BIO *b, const char *in, int inl) -{ - NBIO_TEST *nt; - int ret = 0; - int num; - unsigned char n; - - if ((in == NULL) || (inl <= 0)) - return 0; - if (b->next_bio == NULL) - return 0; - nt = (NBIO_TEST *)b->ptr; - - BIO_clear_retry_flags(b); - - if (nt->lwn > 0) { - num = nt->lwn; - nt->lwn = 0; - } else { - if (RAND_priv_bytes(&n, 1) <= 0) - return -1; - num = (n & 7); - } - - if (inl > num) - inl = num; - - if (num == 0) { - ret = -1; - BIO_set_retry_write(b); - } else { - ret = BIO_write(b->next_bio, in, inl); - if (ret < 0) { - BIO_copy_next_retry(b); - nt->lwn = inl; - } - } - return ret; -} - -static long nbiof_ctrl(BIO *b, int cmd, long num, void *ptr) -{ - long ret; - - if (b->next_bio == NULL) - return 0; - switch (cmd) { - case BIO_C_DO_STATE_MACHINE: - BIO_clear_retry_flags(b); - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); - BIO_copy_next_retry(b); - break; - case BIO_CTRL_DUP: - ret = 0L; - break; - default: - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); - break; - } - return ret; -} - -static long nbiof_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) -{ - long ret = 1; - - if (b->next_bio == NULL) - return 0; - switch (cmd) { - default: - ret = BIO_callback_ctrl(b->next_bio, cmd, fp); - break; - } - return ret; -} - -static int nbiof_gets(BIO *bp, char *buf, int size) -{ - if (bp->next_bio == NULL) - return 0; - return BIO_gets(bp->next_bio, buf, size); -} - -static int nbiof_puts(BIO *bp, const char *str) -{ - if (bp->next_bio == NULL) - return 0; - return BIO_puts(bp->next_bio, str); -} +#include "internal/cryptlib.h" +#include <openssl/rand.h> + +/* + * BIO_put and BIO_get both add to the digest, BIO_gets returns the digest + */ + +static int nbiof_write(BIO *h, const char *buf, int num); +static int nbiof_read(BIO *h, char *buf, int size); +static int nbiof_puts(BIO *h, const char *str); +static int nbiof_gets(BIO *h, char *str, int size); +static long nbiof_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int nbiof_new(BIO *h); +static int nbiof_free(BIO *data); +static long nbiof_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp); +typedef struct nbio_test_st { + /* only set if we sent a 'should retry' error */ + int lrn; + int lwn; +} NBIO_TEST; + +static const BIO_METHOD methods_nbiof = { + BIO_TYPE_NBIO_TEST, + "non-blocking IO test filter", + /* TODO: Convert to new style write function */ + bwrite_conv, + nbiof_write, + /* TODO: Convert to new style read function */ + bread_conv, + nbiof_read, + nbiof_puts, + nbiof_gets, + nbiof_ctrl, + nbiof_new, + nbiof_free, + nbiof_callback_ctrl, +}; + +const BIO_METHOD *BIO_f_nbio_test(void) +{ + return &methods_nbiof; +} + +static int nbiof_new(BIO *bi) +{ + NBIO_TEST *nt; + + if ((nt = OPENSSL_zalloc(sizeof(*nt))) == NULL) { + BIOerr(BIO_F_NBIOF_NEW, ERR_R_MALLOC_FAILURE); + return 0; + } + nt->lrn = -1; + nt->lwn = -1; + bi->ptr = (char *)nt; + bi->init = 1; + return 1; +} + +static int nbiof_free(BIO *a) +{ + if (a == NULL) + return 0; + OPENSSL_free(a->ptr); + a->ptr = NULL; + a->init = 0; + a->flags = 0; + return 1; +} + +static int nbiof_read(BIO *b, char *out, int outl) +{ + int ret = 0; + int num; + unsigned char n; + + if (out == NULL) + return 0; + if (b->next_bio == NULL) + return 0; + + BIO_clear_retry_flags(b); + if (RAND_priv_bytes(&n, 1) <= 0) + return -1; + num = (n & 0x07); + + if (outl > num) + outl = num; + + if (num == 0) { + ret = -1; + BIO_set_retry_read(b); + } else { + ret = BIO_read(b->next_bio, out, outl); + if (ret < 0) + BIO_copy_next_retry(b); + } + return ret; +} + +static int nbiof_write(BIO *b, const char *in, int inl) +{ + NBIO_TEST *nt; + int ret = 0; + int num; + unsigned char n; + + if ((in == NULL) || (inl <= 0)) + return 0; + if (b->next_bio == NULL) + return 0; + nt = (NBIO_TEST *)b->ptr; + + BIO_clear_retry_flags(b); + + if (nt->lwn > 0) { + num = nt->lwn; + nt->lwn = 0; + } else { + if (RAND_priv_bytes(&n, 1) <= 0) + return -1; + num = (n & 7); + } + + if (inl > num) + inl = num; + + if (num == 0) { + ret = -1; + BIO_set_retry_write(b); + } else { + ret = BIO_write(b->next_bio, in, inl); + if (ret < 0) { + BIO_copy_next_retry(b); + nt->lwn = inl; + } + } + return ret; +} + +static long nbiof_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + long ret; + + if (b->next_bio == NULL) + return 0; + switch (cmd) { + case BIO_C_DO_STATE_MACHINE: + BIO_clear_retry_flags(b); + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + BIO_copy_next_retry(b); + break; + case BIO_CTRL_DUP: + ret = 0L; + break; + default: + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + break; + } + return ret; +} + +static long nbiof_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) +{ + long ret = 1; + + if (b->next_bio == NULL) + return 0; + switch (cmd) { + default: + ret = BIO_callback_ctrl(b->next_bio, cmd, fp); + break; + } + return ret; +} + +static int nbiof_gets(BIO *bp, char *buf, int size) +{ + if (bp->next_bio == NULL) + return 0; + return BIO_gets(bp->next_bio, buf, size); +} + +static int nbiof_puts(BIO *bp, const char *str) +{ + if (bp->next_bio == NULL) + return 0; + return BIO_puts(bp->next_bio, str); +} diff --git a/contrib/libs/openssl/crypto/bio/bf_null.c b/contrib/libs/openssl/crypto/bio/bf_null.c index 22f788bfb3..48c6be692a 100644 --- a/contrib/libs/openssl/crypto/bio/bf_null.c +++ b/contrib/libs/openssl/crypto/bio/bf_null.c @@ -1,122 +1,122 @@ -/* - * Copyright 1995-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 - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -#include <stdio.h> -#include <errno.h> +/* + * Copyright 1995-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 + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include <errno.h> #include "bio_local.h" -#include "internal/cryptlib.h" - -/* - * BIO_put and BIO_get both add to the digest, BIO_gets returns the digest - */ - -static int nullf_write(BIO *h, const char *buf, int num); -static int nullf_read(BIO *h, char *buf, int size); -static int nullf_puts(BIO *h, const char *str); -static int nullf_gets(BIO *h, char *str, int size); -static long nullf_ctrl(BIO *h, int cmd, long arg1, void *arg2); -static long nullf_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp); -static const BIO_METHOD methods_nullf = { - BIO_TYPE_NULL_FILTER, - "NULL filter", - /* TODO: Convert to new style write function */ - bwrite_conv, - nullf_write, - /* TODO: Convert to new style read function */ - bread_conv, - nullf_read, - nullf_puts, - nullf_gets, - nullf_ctrl, - NULL, - NULL, - nullf_callback_ctrl, -}; - -const BIO_METHOD *BIO_f_null(void) -{ - return &methods_nullf; -} - -static int nullf_read(BIO *b, char *out, int outl) -{ - int ret = 0; - - if (out == NULL) - return 0; - if (b->next_bio == NULL) - return 0; - ret = BIO_read(b->next_bio, out, outl); - BIO_clear_retry_flags(b); - BIO_copy_next_retry(b); - return ret; -} - -static int nullf_write(BIO *b, const char *in, int inl) -{ - int ret = 0; - - if ((in == NULL) || (inl <= 0)) - return 0; - if (b->next_bio == NULL) - return 0; - ret = BIO_write(b->next_bio, in, inl); - BIO_clear_retry_flags(b); - BIO_copy_next_retry(b); - return ret; -} - -static long nullf_ctrl(BIO *b, int cmd, long num, void *ptr) -{ - long ret; - - if (b->next_bio == NULL) - return 0; - switch (cmd) { - case BIO_C_DO_STATE_MACHINE: - BIO_clear_retry_flags(b); - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); - BIO_copy_next_retry(b); - break; - case BIO_CTRL_DUP: - ret = 0L; - break; - default: - ret = BIO_ctrl(b->next_bio, cmd, num, ptr); - } - return ret; -} - -static long nullf_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) -{ - long ret = 1; - - if (b->next_bio == NULL) - return 0; - switch (cmd) { - default: - ret = BIO_callback_ctrl(b->next_bio, cmd, fp); - break; - } - return ret; -} - -static int nullf_gets(BIO *bp, char *buf, int size) -{ - if (bp->next_bio == NULL) - return 0; - return BIO_gets(bp->next_bio, buf, size); -} - -static int nullf_puts(BIO *bp, const char *str) -{ - if (bp->next_bio == NULL) - return 0; - return BIO_puts(bp->next_bio, str); -} +#include "internal/cryptlib.h" + +/* + * BIO_put and BIO_get both add to the digest, BIO_gets returns the digest + */ + +static int nullf_write(BIO *h, const char *buf, int num); +static int nullf_read(BIO *h, char *buf, int size); +static int nullf_puts(BIO *h, const char *str); +static int nullf_gets(BIO *h, char *str, int size); +static long nullf_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static long nullf_callback_ctrl(BIO *h, int cmd, BIO_info_cb *fp); +static const BIO_METHOD methods_nullf = { + BIO_TYPE_NULL_FILTER, + "NULL filter", + /* TODO: Convert to new style write function */ + bwrite_conv, + nullf_write, + /* TODO: Convert to new style read function */ + bread_conv, + nullf_read, + nullf_puts, + nullf_gets, + nullf_ctrl, + NULL, + NULL, + nullf_callback_ctrl, +}; + +const BIO_METHOD *BIO_f_null(void) +{ + return &methods_nullf; +} + +static int nullf_read(BIO *b, char *out, int outl) +{ + int ret = 0; + + if (out == NULL) + return 0; + if (b->next_bio == NULL) + return 0; + ret = BIO_read(b->next_bio, out, outl); + BIO_clear_retry_flags(b); + BIO_copy_next_retry(b); + return ret; +} + +static int nullf_write(BIO *b, const char *in, int inl) +{ + int ret = 0; + + if ((in == NULL) || (inl <= 0)) + return 0; + if (b->next_bio == NULL) + return 0; + ret = BIO_write(b->next_bio, in, inl); + BIO_clear_retry_flags(b); + BIO_copy_next_retry(b); + return ret; +} + +static long nullf_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + long ret; + + if (b->next_bio == NULL) + return 0; + switch (cmd) { + case BIO_C_DO_STATE_MACHINE: + BIO_clear_retry_flags(b); + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + BIO_copy_next_retry(b); + break; + case BIO_CTRL_DUP: + ret = 0L; + break; + default: + ret = BIO_ctrl(b->next_bio, cmd, num, ptr); + } + return ret; +} + +static long nullf_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) +{ + long ret = 1; + + if (b->next_bio == NULL) + return 0; + switch (cmd) { + default: + ret = BIO_callback_ctrl(b->next_bio, cmd, fp); + break; + } + return ret; +} + +static int nullf_gets(BIO *bp, char *buf, int size) +{ + if (bp->next_bio == NULL) + return 0; + return BIO_gets(bp->next_bio, buf, size); +} + +static int nullf_puts(BIO *bp, const char *str) +{ + if (bp->next_bio == NULL) + return 0; + return BIO_puts(bp->next_bio, str); +} diff --git a/contrib/libs/openssl/crypto/bio/bio_cb.c b/contrib/libs/openssl/crypto/bio/bio_cb.c index 2ce733031e..a153100a88 100644 --- a/contrib/libs/openssl/crypto/bio/bio_cb.c +++ b/contrib/libs/openssl/crypto/bio/bio_cb.c @@ -1,98 +1,98 @@ -/* - * Copyright 1995-2017 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 - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -#include <stdio.h> -#include <string.h> -#include <stdlib.h> +/* + * Copyright 1995-2017 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 + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include <string.h> +#include <stdlib.h> #include "bio_local.h" -#include "internal/cryptlib.h" -#include <openssl/err.h> - -long BIO_debug_callback(BIO *bio, int cmd, const char *argp, - int argi, long argl, long ret) -{ - BIO *b; - char buf[256]; - char *p; - long r = 1; - int len, left; - - if (BIO_CB_RETURN & cmd) - r = ret; - - len = BIO_snprintf(buf, sizeof(buf), "BIO[%p]: ", (void *)bio); - - /* Ignore errors and continue printing the other information. */ - if (len < 0) - len = 0; - p = buf + len; - left = sizeof(buf) - len; - - switch (cmd) { - case BIO_CB_FREE: - BIO_snprintf(p, left, "Free - %s\n", bio->method->name); - break; - case BIO_CB_READ: - if (bio->method->type & BIO_TYPE_DESCRIPTOR) - BIO_snprintf(p, left, "read(%d,%lu) - %s fd=%d\n", - bio->num, (unsigned long)argi, - bio->method->name, bio->num); - else - BIO_snprintf(p, left, "read(%d,%lu) - %s\n", - bio->num, (unsigned long)argi, bio->method->name); - break; - case BIO_CB_WRITE: - if (bio->method->type & BIO_TYPE_DESCRIPTOR) - BIO_snprintf(p, left, "write(%d,%lu) - %s fd=%d\n", - bio->num, (unsigned long)argi, - bio->method->name, bio->num); - else - BIO_snprintf(p, left, "write(%d,%lu) - %s\n", - bio->num, (unsigned long)argi, bio->method->name); - break; - case BIO_CB_PUTS: - BIO_snprintf(p, left, "puts() - %s\n", bio->method->name); - break; - case BIO_CB_GETS: - BIO_snprintf(p, left, "gets(%lu) - %s\n", (unsigned long)argi, - bio->method->name); - break; - case BIO_CB_CTRL: - BIO_snprintf(p, left, "ctrl(%lu) - %s\n", (unsigned long)argi, - bio->method->name); - break; - case BIO_CB_RETURN | BIO_CB_READ: - BIO_snprintf(p, left, "read return %ld\n", ret); - break; - case BIO_CB_RETURN | BIO_CB_WRITE: - BIO_snprintf(p, left, "write return %ld\n", ret); - break; - case BIO_CB_RETURN | BIO_CB_GETS: - BIO_snprintf(p, left, "gets return %ld\n", ret); - break; - case BIO_CB_RETURN | BIO_CB_PUTS: - BIO_snprintf(p, left, "puts return %ld\n", ret); - break; - case BIO_CB_RETURN | BIO_CB_CTRL: - BIO_snprintf(p, left, "ctrl return %ld\n", ret); - break; - default: - BIO_snprintf(p, left, "bio callback - unknown type (%d)\n", cmd); - break; - } - - b = (BIO *)bio->cb_arg; - if (b != NULL) - BIO_write(b, buf, strlen(buf)); -#if !defined(OPENSSL_NO_STDIO) - else - fputs(buf, stderr); -#endif - return r; -} +#include "internal/cryptlib.h" +#include <openssl/err.h> + +long BIO_debug_callback(BIO *bio, int cmd, const char *argp, + int argi, long argl, long ret) +{ + BIO *b; + char buf[256]; + char *p; + long r = 1; + int len, left; + + if (BIO_CB_RETURN & cmd) + r = ret; + + len = BIO_snprintf(buf, sizeof(buf), "BIO[%p]: ", (void *)bio); + + /* Ignore errors and continue printing the other information. */ + if (len < 0) + len = 0; + p = buf + len; + left = sizeof(buf) - len; + + switch (cmd) { + case BIO_CB_FREE: + BIO_snprintf(p, left, "Free - %s\n", bio->method->name); + break; + case BIO_CB_READ: + if (bio->method->type & BIO_TYPE_DESCRIPTOR) + BIO_snprintf(p, left, "read(%d,%lu) - %s fd=%d\n", + bio->num, (unsigned long)argi, + bio->method->name, bio->num); + else + BIO_snprintf(p, left, "read(%d,%lu) - %s\n", + bio->num, (unsigned long)argi, bio->method->name); + break; + case BIO_CB_WRITE: + if (bio->method->type & BIO_TYPE_DESCRIPTOR) + BIO_snprintf(p, left, "write(%d,%lu) - %s fd=%d\n", + bio->num, (unsigned long)argi, + bio->method->name, bio->num); + else + BIO_snprintf(p, left, "write(%d,%lu) - %s\n", + bio->num, (unsigned long)argi, bio->method->name); + break; + case BIO_CB_PUTS: + BIO_snprintf(p, left, "puts() - %s\n", bio->method->name); + break; + case BIO_CB_GETS: + BIO_snprintf(p, left, "gets(%lu) - %s\n", (unsigned long)argi, + bio->method->name); + break; + case BIO_CB_CTRL: + BIO_snprintf(p, left, "ctrl(%lu) - %s\n", (unsigned long)argi, + bio->method->name); + break; + case BIO_CB_RETURN | BIO_CB_READ: + BIO_snprintf(p, left, "read return %ld\n", ret); + break; + case BIO_CB_RETURN | BIO_CB_WRITE: + BIO_snprintf(p, left, "write return %ld\n", ret); + break; + case BIO_CB_RETURN | BIO_CB_GETS: + BIO_snprintf(p, left, "gets return %ld\n", ret); + break; + case BIO_CB_RETURN | BIO_CB_PUTS: + BIO_snprintf(p, left, "puts return %ld\n", ret); + break; + case BIO_CB_RETURN | BIO_CB_CTRL: + BIO_snprintf(p, left, "ctrl return %ld\n", ret); + break; + default: + BIO_snprintf(p, left, "bio callback - unknown type (%d)\n", cmd); + break; + } + + b = (BIO *)bio->cb_arg; + if (b != NULL) + BIO_write(b, buf, strlen(buf)); +#if !defined(OPENSSL_NO_STDIO) + else + fputs(buf, stderr); +#endif + return r; +} diff --git a/contrib/libs/openssl/crypto/bio/bio_err.c b/contrib/libs/openssl/crypto/bio/bio_err.c index dce434f302..7aa9dabb29 100644 --- a/contrib/libs/openssl/crypto/bio/bio_err.c +++ b/contrib/libs/openssl/crypto/bio/bio_err.c @@ -1,145 +1,145 @@ -/* - * Generated by util/mkerr.pl DO NOT EDIT - * Copyright 1995-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 - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -#include <openssl/err.h> -#include <openssl/bioerr.h> - -#ifndef OPENSSL_NO_ERR - -static const ERR_STRING_DATA BIO_str_functs[] = { - {ERR_PACK(ERR_LIB_BIO, BIO_F_ACPT_STATE, 0), "acpt_state"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_ADDRINFO_WRAP, 0), "addrinfo_wrap"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_ADDR_STRINGS, 0), "addr_strings"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_ACCEPT, 0), "BIO_accept"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_ACCEPT_EX, 0), "BIO_accept_ex"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_ACCEPT_NEW, 0), "BIO_ACCEPT_new"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_ADDR_NEW, 0), "BIO_ADDR_new"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_BIND, 0), "BIO_bind"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_CALLBACK_CTRL, 0), "BIO_callback_ctrl"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_CONNECT, 0), "BIO_connect"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_CONNECT_NEW, 0), "BIO_CONNECT_new"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_CTRL, 0), "BIO_ctrl"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_GETS, 0), "BIO_gets"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_GET_HOST_IP, 0), "BIO_get_host_ip"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_GET_NEW_INDEX, 0), "BIO_get_new_index"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_GET_PORT, 0), "BIO_get_port"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_LISTEN, 0), "BIO_listen"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_LOOKUP, 0), "BIO_lookup"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_LOOKUP_EX, 0), "BIO_lookup_ex"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_MAKE_PAIR, 0), "bio_make_pair"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_METH_NEW, 0), "BIO_meth_new"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_NEW, 0), "BIO_new"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_NEW_DGRAM_SCTP, 0), "BIO_new_dgram_sctp"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_NEW_FILE, 0), "BIO_new_file"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_NEW_MEM_BUF, 0), "BIO_new_mem_buf"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_NREAD, 0), "BIO_nread"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_NREAD0, 0), "BIO_nread0"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_NWRITE, 0), "BIO_nwrite"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_NWRITE0, 0), "BIO_nwrite0"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_PARSE_HOSTSERV, 0), "BIO_parse_hostserv"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_PUTS, 0), "BIO_puts"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_READ, 0), "BIO_read"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_READ_EX, 0), "BIO_read_ex"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_READ_INTERN, 0), "bio_read_intern"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_SOCKET, 0), "BIO_socket"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_SOCKET_NBIO, 0), "BIO_socket_nbio"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_SOCK_INFO, 0), "BIO_sock_info"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_SOCK_INIT, 0), "BIO_sock_init"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_WRITE, 0), "BIO_write"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_WRITE_EX, 0), "BIO_write_ex"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_WRITE_INTERN, 0), "bio_write_intern"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_BUFFER_CTRL, 0), "buffer_ctrl"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_CONN_CTRL, 0), "conn_ctrl"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_CONN_STATE, 0), "conn_state"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_DGRAM_SCTP_NEW, 0), "dgram_sctp_new"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_DGRAM_SCTP_READ, 0), "dgram_sctp_read"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_DGRAM_SCTP_WRITE, 0), "dgram_sctp_write"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_DOAPR_OUTCH, 0), "doapr_outch"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_FILE_CTRL, 0), "file_ctrl"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_FILE_READ, 0), "file_read"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_LINEBUFFER_CTRL, 0), "linebuffer_ctrl"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_LINEBUFFER_NEW, 0), "linebuffer_new"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_MEM_WRITE, 0), "mem_write"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_NBIOF_NEW, 0), "nbiof_new"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_SLG_WRITE, 0), "slg_write"}, - {ERR_PACK(ERR_LIB_BIO, BIO_F_SSL_NEW, 0), "SSL_new"}, - {0, NULL} -}; - -static const ERR_STRING_DATA BIO_str_reasons[] = { - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_ACCEPT_ERROR), "accept error"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_ADDRINFO_ADDR_IS_NOT_AF_INET), - "addrinfo addr is not af inet"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_AMBIGUOUS_HOST_OR_SERVICE), - "ambiguous host or service"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_BAD_FOPEN_MODE), "bad fopen mode"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_BROKEN_PIPE), "broken pipe"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_CONNECT_ERROR), "connect error"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET), - "gethostbyname addr is not af inet"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_GETSOCKNAME_ERROR), "getsockname error"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_GETSOCKNAME_TRUNCATED_ADDRESS), - "getsockname truncated address"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_GETTING_SOCKTYPE), "getting socktype"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_INVALID_ARGUMENT), "invalid argument"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_INVALID_SOCKET), "invalid socket"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_IN_USE), "in use"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_LENGTH_TOO_LONG), "length too long"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_LISTEN_V6_ONLY), "listen v6 only"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_LOOKUP_RETURNED_NOTHING), - "lookup returned nothing"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_MALFORMED_HOST_OR_SERVICE), - "malformed host or service"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NBIO_CONNECT_ERROR), "nbio connect error"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED), - "no accept addr or service specified"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NO_HOSTNAME_OR_SERVICE_SPECIFIED), - "no hostname or service specified"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NO_PORT_DEFINED), "no port defined"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NO_SUCH_FILE), "no such file"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NULL_PARAMETER), "null parameter"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNABLE_TO_BIND_SOCKET), - "unable to bind socket"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNABLE_TO_CREATE_SOCKET), - "unable to create socket"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNABLE_TO_KEEPALIVE), - "unable to keepalive"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNABLE_TO_LISTEN_SOCKET), - "unable to listen socket"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNABLE_TO_NODELAY), "unable to nodelay"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNABLE_TO_REUSEADDR), - "unable to reuseaddr"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNAVAILABLE_IP_FAMILY), - "unavailable ip family"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNINITIALIZED), "uninitialized"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNKNOWN_INFO_TYPE), "unknown info type"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNSUPPORTED_IP_FAMILY), - "unsupported ip family"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNSUPPORTED_METHOD), "unsupported method"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNSUPPORTED_PROTOCOL_FAMILY), - "unsupported protocol family"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_WRITE_TO_READ_ONLY_BIO), - "write to read only BIO"}, - {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_WSASTARTUP), "WSAStartup"}, - {0, NULL} -}; - -#endif - -int ERR_load_BIO_strings(void) -{ -#ifndef OPENSSL_NO_ERR - if (ERR_func_error_string(BIO_str_functs[0].error) == NULL) { - ERR_load_strings_const(BIO_str_functs); - ERR_load_strings_const(BIO_str_reasons); - } -#endif - return 1; -} +/* + * Generated by util/mkerr.pl DO NOT EDIT + * Copyright 1995-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 + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <openssl/err.h> +#include <openssl/bioerr.h> + +#ifndef OPENSSL_NO_ERR + +static const ERR_STRING_DATA BIO_str_functs[] = { + {ERR_PACK(ERR_LIB_BIO, BIO_F_ACPT_STATE, 0), "acpt_state"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_ADDRINFO_WRAP, 0), "addrinfo_wrap"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_ADDR_STRINGS, 0), "addr_strings"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_ACCEPT, 0), "BIO_accept"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_ACCEPT_EX, 0), "BIO_accept_ex"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_ACCEPT_NEW, 0), "BIO_ACCEPT_new"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_ADDR_NEW, 0), "BIO_ADDR_new"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_BIND, 0), "BIO_bind"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_CALLBACK_CTRL, 0), "BIO_callback_ctrl"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_CONNECT, 0), "BIO_connect"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_CONNECT_NEW, 0), "BIO_CONNECT_new"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_CTRL, 0), "BIO_ctrl"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_GETS, 0), "BIO_gets"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_GET_HOST_IP, 0), "BIO_get_host_ip"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_GET_NEW_INDEX, 0), "BIO_get_new_index"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_GET_PORT, 0), "BIO_get_port"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_LISTEN, 0), "BIO_listen"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_LOOKUP, 0), "BIO_lookup"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_LOOKUP_EX, 0), "BIO_lookup_ex"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_MAKE_PAIR, 0), "bio_make_pair"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_METH_NEW, 0), "BIO_meth_new"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_NEW, 0), "BIO_new"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_NEW_DGRAM_SCTP, 0), "BIO_new_dgram_sctp"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_NEW_FILE, 0), "BIO_new_file"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_NEW_MEM_BUF, 0), "BIO_new_mem_buf"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_NREAD, 0), "BIO_nread"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_NREAD0, 0), "BIO_nread0"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_NWRITE, 0), "BIO_nwrite"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_NWRITE0, 0), "BIO_nwrite0"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_PARSE_HOSTSERV, 0), "BIO_parse_hostserv"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_PUTS, 0), "BIO_puts"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_READ, 0), "BIO_read"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_READ_EX, 0), "BIO_read_ex"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_READ_INTERN, 0), "bio_read_intern"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_SOCKET, 0), "BIO_socket"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_SOCKET_NBIO, 0), "BIO_socket_nbio"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_SOCK_INFO, 0), "BIO_sock_info"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_SOCK_INIT, 0), "BIO_sock_init"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_WRITE, 0), "BIO_write"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_WRITE_EX, 0), "BIO_write_ex"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BIO_WRITE_INTERN, 0), "bio_write_intern"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_BUFFER_CTRL, 0), "buffer_ctrl"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_CONN_CTRL, 0), "conn_ctrl"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_CONN_STATE, 0), "conn_state"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_DGRAM_SCTP_NEW, 0), "dgram_sctp_new"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_DGRAM_SCTP_READ, 0), "dgram_sctp_read"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_DGRAM_SCTP_WRITE, 0), "dgram_sctp_write"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_DOAPR_OUTCH, 0), "doapr_outch"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_FILE_CTRL, 0), "file_ctrl"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_FILE_READ, 0), "file_read"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_LINEBUFFER_CTRL, 0), "linebuffer_ctrl"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_LINEBUFFER_NEW, 0), "linebuffer_new"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_MEM_WRITE, 0), "mem_write"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_NBIOF_NEW, 0), "nbiof_new"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_SLG_WRITE, 0), "slg_write"}, + {ERR_PACK(ERR_LIB_BIO, BIO_F_SSL_NEW, 0), "SSL_new"}, + {0, NULL} +}; + +static const ERR_STRING_DATA BIO_str_reasons[] = { + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_ACCEPT_ERROR), "accept error"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_ADDRINFO_ADDR_IS_NOT_AF_INET), + "addrinfo addr is not af inet"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_AMBIGUOUS_HOST_OR_SERVICE), + "ambiguous host or service"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_BAD_FOPEN_MODE), "bad fopen mode"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_BROKEN_PIPE), "broken pipe"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_CONNECT_ERROR), "connect error"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_GETHOSTBYNAME_ADDR_IS_NOT_AF_INET), + "gethostbyname addr is not af inet"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_GETSOCKNAME_ERROR), "getsockname error"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_GETSOCKNAME_TRUNCATED_ADDRESS), + "getsockname truncated address"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_GETTING_SOCKTYPE), "getting socktype"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_INVALID_ARGUMENT), "invalid argument"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_INVALID_SOCKET), "invalid socket"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_IN_USE), "in use"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_LENGTH_TOO_LONG), "length too long"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_LISTEN_V6_ONLY), "listen v6 only"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_LOOKUP_RETURNED_NOTHING), + "lookup returned nothing"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_MALFORMED_HOST_OR_SERVICE), + "malformed host or service"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NBIO_CONNECT_ERROR), "nbio connect error"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NO_ACCEPT_ADDR_OR_SERVICE_SPECIFIED), + "no accept addr or service specified"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NO_HOSTNAME_OR_SERVICE_SPECIFIED), + "no hostname or service specified"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NO_PORT_DEFINED), "no port defined"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NO_SUCH_FILE), "no such file"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_NULL_PARAMETER), "null parameter"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNABLE_TO_BIND_SOCKET), + "unable to bind socket"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNABLE_TO_CREATE_SOCKET), + "unable to create socket"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNABLE_TO_KEEPALIVE), + "unable to keepalive"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNABLE_TO_LISTEN_SOCKET), + "unable to listen socket"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNABLE_TO_NODELAY), "unable to nodelay"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNABLE_TO_REUSEADDR), + "unable to reuseaddr"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNAVAILABLE_IP_FAMILY), + "unavailable ip family"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNINITIALIZED), "uninitialized"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNKNOWN_INFO_TYPE), "unknown info type"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNSUPPORTED_IP_FAMILY), + "unsupported ip family"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNSUPPORTED_METHOD), "unsupported method"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_UNSUPPORTED_PROTOCOL_FAMILY), + "unsupported protocol family"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_WRITE_TO_READ_ONLY_BIO), + "write to read only BIO"}, + {ERR_PACK(ERR_LIB_BIO, 0, BIO_R_WSASTARTUP), "WSAStartup"}, + {0, NULL} +}; + +#endif + +int ERR_load_BIO_strings(void) +{ +#ifndef OPENSSL_NO_ERR + if (ERR_func_error_string(BIO_str_functs[0].error) == NULL) { + ERR_load_strings_const(BIO_str_functs); + ERR_load_strings_const(BIO_str_reasons); + } +#endif + return 1; +} diff --git a/contrib/libs/openssl/crypto/bio/bio_lib.c b/contrib/libs/openssl/crypto/bio/bio_lib.c index a179377470..d2202e537b 100644 --- a/contrib/libs/openssl/crypto/bio/bio_lib.c +++ b/contrib/libs/openssl/crypto/bio/bio_lib.c @@ -1,786 +1,786 @@ -/* - * Copyright 1995-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 - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -#include <stdio.h> -#include <errno.h> -#include <openssl/crypto.h> +/* + * Copyright 1995-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 + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include <errno.h> +#include <openssl/crypto.h> #include "bio_local.h" -#include "internal/cryptlib.h" - - -/* - * Helper macro for the callback to determine whether an operator expects a - * len parameter or not - */ -#define HAS_LEN_OPER(o) ((o) == BIO_CB_READ || (o) == BIO_CB_WRITE || \ - (o) == BIO_CB_GETS) - -/* - * Helper function to work out whether to call the new style callback or the old - * one, and translate between the two. - * - * This has a long return type for consistency with the old callback. Similarly - * for the "long" used for "inret" - */ -static long bio_call_callback(BIO *b, int oper, const char *argp, size_t len, - int argi, long argl, long inret, size_t *processed) -{ - long ret; - int bareoper; - - if (b->callback_ex != NULL) - return b->callback_ex(b, oper, argp, len, argi, argl, inret, processed); - - /* Strip off any BIO_CB_RETURN flag */ - bareoper = oper & ~BIO_CB_RETURN; - - /* - * We have an old style callback, so we will have to do nasty casts and - * check for overflows. - */ - if (HAS_LEN_OPER(bareoper)) { - /* In this case |len| is set, and should be used instead of |argi| */ - if (len > INT_MAX) - return -1; - - argi = (int)len; - } - - if (inret > 0 && (oper & BIO_CB_RETURN) && bareoper != BIO_CB_CTRL) { - if (*processed > INT_MAX) - return -1; - inret = *processed; - } - - ret = b->callback(b, oper, argp, argi, argl, inret); - - if (ret > 0 && (oper & BIO_CB_RETURN) && bareoper != BIO_CB_CTRL) { - *processed = (size_t)ret; - ret = 1; - } - - return ret; -} - -BIO *BIO_new(const BIO_METHOD *method) -{ - BIO *bio = OPENSSL_zalloc(sizeof(*bio)); - - if (bio == NULL) { - BIOerr(BIO_F_BIO_NEW, ERR_R_MALLOC_FAILURE); - return NULL; - } - - bio->method = method; - bio->shutdown = 1; - bio->references = 1; - - if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data)) - goto err; - - bio->lock = CRYPTO_THREAD_lock_new(); - if (bio->lock == NULL) { - BIOerr(BIO_F_BIO_NEW, ERR_R_MALLOC_FAILURE); - CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data); - goto err; - } - - if (method->create != NULL && !method->create(bio)) { - BIOerr(BIO_F_BIO_NEW, ERR_R_INIT_FAIL); - CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data); - CRYPTO_THREAD_lock_free(bio->lock); - goto err; - } - if (method->create == NULL) - bio->init = 1; - - return bio; - -err: - OPENSSL_free(bio); - return NULL; -} - -int BIO_free(BIO *a) -{ - int ret; - - if (a == NULL) - return 0; - - if (CRYPTO_DOWN_REF(&a->references, &ret, a->lock) <= 0) - return 0; - - REF_PRINT_COUNT("BIO", a); - if (ret > 0) - return 1; - REF_ASSERT_ISNT(ret < 0); - - if (a->callback != NULL || a->callback_ex != NULL) { - ret = (int)bio_call_callback(a, BIO_CB_FREE, NULL, 0, 0, 0L, 1L, NULL); - if (ret <= 0) - return ret; - } - - if ((a->method != NULL) && (a->method->destroy != NULL)) - a->method->destroy(a); - - CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, a, &a->ex_data); - - CRYPTO_THREAD_lock_free(a->lock); - - OPENSSL_free(a); - - return 1; -} - -void BIO_set_data(BIO *a, void *ptr) -{ - a->ptr = ptr; -} - -void *BIO_get_data(BIO *a) -{ - return a->ptr; -} - -void BIO_set_init(BIO *a, int init) -{ - a->init = init; -} - -int BIO_get_init(BIO *a) -{ - return a->init; -} - -void BIO_set_shutdown(BIO *a, int shut) -{ - a->shutdown = shut; -} - -int BIO_get_shutdown(BIO *a) -{ - return a->shutdown; -} - -void BIO_vfree(BIO *a) -{ - BIO_free(a); -} - -int BIO_up_ref(BIO *a) -{ - int i; - - if (CRYPTO_UP_REF(&a->references, &i, a->lock) <= 0) - return 0; - - REF_PRINT_COUNT("BIO", a); - REF_ASSERT_ISNT(i < 2); - return ((i > 1) ? 1 : 0); -} - -void BIO_clear_flags(BIO *b, int flags) -{ - b->flags &= ~flags; -} - -int BIO_test_flags(const BIO *b, int flags) -{ - return (b->flags & flags); -} - -void BIO_set_flags(BIO *b, int flags) -{ - b->flags |= flags; -} - -BIO_callback_fn BIO_get_callback(const BIO *b) -{ - return b->callback; -} - -void BIO_set_callback(BIO *b, BIO_callback_fn cb) -{ - b->callback = cb; -} - -BIO_callback_fn_ex BIO_get_callback_ex(const BIO *b) -{ - return b->callback_ex; -} - -void BIO_set_callback_ex(BIO *b, BIO_callback_fn_ex cb) -{ - b->callback_ex = cb; -} - -void BIO_set_callback_arg(BIO *b, char *arg) -{ - b->cb_arg = arg; -} - -char *BIO_get_callback_arg(const BIO *b) -{ - return b->cb_arg; -} - -const char *BIO_method_name(const BIO *b) -{ - return b->method->name; -} - -int BIO_method_type(const BIO *b) -{ - return b->method->type; -} - -/* - * This is essentially the same as BIO_read_ex() except that it allows - * 0 or a negative value to indicate failure (retryable or not) in the return. - * This is for compatibility with the old style BIO_read(), where existing code - * may make assumptions about the return value that it might get. - */ -static int bio_read_intern(BIO *b, void *data, size_t dlen, size_t *readbytes) -{ - int ret; - - if ((b == NULL) || (b->method == NULL) || (b->method->bread == NULL)) { - BIOerr(BIO_F_BIO_READ_INTERN, BIO_R_UNSUPPORTED_METHOD); - return -2; - } - - if ((b->callback != NULL || b->callback_ex != NULL) && - ((ret = (int)bio_call_callback(b, BIO_CB_READ, data, dlen, 0, 0L, 1L, - NULL)) <= 0)) - return ret; - - if (!b->init) { - BIOerr(BIO_F_BIO_READ_INTERN, BIO_R_UNINITIALIZED); - return -2; - } - - ret = b->method->bread(b, data, dlen, readbytes); - - if (ret > 0) - b->num_read += (uint64_t)*readbytes; - - if (b->callback != NULL || b->callback_ex != NULL) - ret = (int)bio_call_callback(b, BIO_CB_READ | BIO_CB_RETURN, data, - dlen, 0, 0L, ret, readbytes); - - /* Shouldn't happen */ - if (ret > 0 && *readbytes > dlen) { - BIOerr(BIO_F_BIO_READ_INTERN, ERR_R_INTERNAL_ERROR); - return -1; - } - - return ret; -} - -int BIO_read(BIO *b, void *data, int dlen) -{ - size_t readbytes; - int ret; - - if (dlen < 0) - return 0; - - ret = bio_read_intern(b, data, (size_t)dlen, &readbytes); - - if (ret > 0) { - /* *readbytes should always be <= dlen */ - ret = (int)readbytes; - } - - return ret; -} - -int BIO_read_ex(BIO *b, void *data, size_t dlen, size_t *readbytes) -{ - int ret; - - ret = bio_read_intern(b, data, dlen, readbytes); - - if (ret > 0) - ret = 1; - else - ret = 0; - - return ret; -} - -static int bio_write_intern(BIO *b, const void *data, size_t dlen, - size_t *written) -{ - int ret; - - if (b == NULL) - return 0; - - if ((b->method == NULL) || (b->method->bwrite == NULL)) { - BIOerr(BIO_F_BIO_WRITE_INTERN, BIO_R_UNSUPPORTED_METHOD); - return -2; - } - - if ((b->callback != NULL || b->callback_ex != NULL) && - ((ret = (int)bio_call_callback(b, BIO_CB_WRITE, data, dlen, 0, 0L, 1L, - NULL)) <= 0)) - return ret; - - if (!b->init) { - BIOerr(BIO_F_BIO_WRITE_INTERN, BIO_R_UNINITIALIZED); - return -2; - } - - ret = b->method->bwrite(b, data, dlen, written); - - if (ret > 0) - b->num_write += (uint64_t)*written; - - if (b->callback != NULL || b->callback_ex != NULL) - ret = (int)bio_call_callback(b, BIO_CB_WRITE | BIO_CB_RETURN, data, - dlen, 0, 0L, ret, written); - - return ret; -} - -int BIO_write(BIO *b, const void *data, int dlen) -{ - size_t written; - int ret; - - if (dlen < 0) - return 0; - - ret = bio_write_intern(b, data, (size_t)dlen, &written); - - if (ret > 0) { - /* *written should always be <= dlen */ - ret = (int)written; - } - - return ret; -} - -int BIO_write_ex(BIO *b, const void *data, size_t dlen, size_t *written) -{ - int ret; - - ret = bio_write_intern(b, data, dlen, written); - - if (ret > 0) - ret = 1; - else - ret = 0; - - return ret; -} - -int BIO_puts(BIO *b, const char *buf) -{ - int ret; - size_t written = 0; - - if ((b == NULL) || (b->method == NULL) || (b->method->bputs == NULL)) { - BIOerr(BIO_F_BIO_PUTS, BIO_R_UNSUPPORTED_METHOD); - return -2; - } - - if (b->callback != NULL || b->callback_ex != NULL) { - ret = (int)bio_call_callback(b, BIO_CB_PUTS, buf, 0, 0, 0L, 1L, NULL); - if (ret <= 0) - return ret; - } - - if (!b->init) { - BIOerr(BIO_F_BIO_PUTS, BIO_R_UNINITIALIZED); - return -2; - } - - ret = b->method->bputs(b, buf); - - if (ret > 0) { - b->num_write += (uint64_t)ret; - written = ret; - ret = 1; - } - - if (b->callback != NULL || b->callback_ex != NULL) - ret = (int)bio_call_callback(b, BIO_CB_PUTS | BIO_CB_RETURN, buf, 0, 0, - 0L, ret, &written); - - if (ret > 0) { - if (written > INT_MAX) { - BIOerr(BIO_F_BIO_PUTS, BIO_R_LENGTH_TOO_LONG); - ret = -1; - } else { - ret = (int)written; - } - } - - return ret; -} - -int BIO_gets(BIO *b, char *buf, int size) -{ - int ret; - size_t readbytes = 0; - - if ((b == NULL) || (b->method == NULL) || (b->method->bgets == NULL)) { - BIOerr(BIO_F_BIO_GETS, BIO_R_UNSUPPORTED_METHOD); - return -2; - } - - if (size < 0) { - BIOerr(BIO_F_BIO_GETS, BIO_R_INVALID_ARGUMENT); - return 0; - } - - if (b->callback != NULL || b->callback_ex != NULL) { - ret = (int)bio_call_callback(b, BIO_CB_GETS, buf, size, 0, 0L, 1, NULL); - if (ret <= 0) - return ret; - } - - if (!b->init) { - BIOerr(BIO_F_BIO_GETS, BIO_R_UNINITIALIZED); - return -2; - } - - ret = b->method->bgets(b, buf, size); - - if (ret > 0) { - readbytes = ret; - ret = 1; - } - - if (b->callback != NULL || b->callback_ex != NULL) - ret = (int)bio_call_callback(b, BIO_CB_GETS | BIO_CB_RETURN, buf, size, - 0, 0L, ret, &readbytes); - - if (ret > 0) { - /* Shouldn't happen */ - if (readbytes > (size_t)size) - ret = -1; - else - ret = (int)readbytes; - } - - return ret; -} - -int BIO_indent(BIO *b, int indent, int max) -{ - if (indent < 0) - indent = 0; - if (indent > max) - indent = max; - while (indent--) - if (BIO_puts(b, " ") != 1) - return 0; - return 1; -} - -long BIO_int_ctrl(BIO *b, int cmd, long larg, int iarg) -{ - int i; - - i = iarg; - return BIO_ctrl(b, cmd, larg, (char *)&i); -} - -void *BIO_ptr_ctrl(BIO *b, int cmd, long larg) -{ - void *p = NULL; - - if (BIO_ctrl(b, cmd, larg, (char *)&p) <= 0) - return NULL; - else - return p; -} - -long BIO_ctrl(BIO *b, int cmd, long larg, void *parg) -{ - long ret; - - if (b == NULL) - return 0; - - if ((b->method == NULL) || (b->method->ctrl == NULL)) { - BIOerr(BIO_F_BIO_CTRL, BIO_R_UNSUPPORTED_METHOD); - return -2; - } - - if (b->callback != NULL || b->callback_ex != NULL) { - ret = bio_call_callback(b, BIO_CB_CTRL, parg, 0, cmd, larg, 1L, NULL); - if (ret <= 0) - return ret; - } - - ret = b->method->ctrl(b, cmd, larg, parg); - - if (b->callback != NULL || b->callback_ex != NULL) - ret = bio_call_callback(b, BIO_CB_CTRL | BIO_CB_RETURN, parg, 0, cmd, - larg, ret, NULL); - - return ret; -} - -long BIO_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) -{ - long ret; - - if (b == NULL) - return 0; - - if ((b->method == NULL) || (b->method->callback_ctrl == NULL) - || (cmd != BIO_CTRL_SET_CALLBACK)) { - BIOerr(BIO_F_BIO_CALLBACK_CTRL, BIO_R_UNSUPPORTED_METHOD); - return -2; - } - - if (b->callback != NULL || b->callback_ex != NULL) { - ret = bio_call_callback(b, BIO_CB_CTRL, (void *)&fp, 0, cmd, 0, 1L, - NULL); - if (ret <= 0) - return ret; - } - - ret = b->method->callback_ctrl(b, cmd, fp); - - if (b->callback != NULL || b->callback_ex != NULL) - ret = bio_call_callback(b, BIO_CB_CTRL | BIO_CB_RETURN, (void *)&fp, 0, - cmd, 0, ret, NULL); - - return ret; -} - -/* - * It is unfortunate to duplicate in functions what the BIO_(w)pending macros - * do; but those macros have inappropriate return type, and for interfacing - * from other programming languages, C macros aren't much of a help anyway. - */ -size_t BIO_ctrl_pending(BIO *bio) -{ - return BIO_ctrl(bio, BIO_CTRL_PENDING, 0, NULL); -} - -size_t BIO_ctrl_wpending(BIO *bio) -{ - return BIO_ctrl(bio, BIO_CTRL_WPENDING, 0, NULL); -} - -/* put the 'bio' on the end of b's list of operators */ -BIO *BIO_push(BIO *b, BIO *bio) -{ - BIO *lb; - - if (b == NULL) - return bio; - lb = b; - while (lb->next_bio != NULL) - lb = lb->next_bio; - lb->next_bio = bio; - if (bio != NULL) - bio->prev_bio = lb; - /* called to do internal processing */ - BIO_ctrl(b, BIO_CTRL_PUSH, 0, lb); - return b; -} - -/* Remove the first and return the rest */ -BIO *BIO_pop(BIO *b) -{ - BIO *ret; - - if (b == NULL) - return NULL; - ret = b->next_bio; - - BIO_ctrl(b, BIO_CTRL_POP, 0, b); - - if (b->prev_bio != NULL) - b->prev_bio->next_bio = b->next_bio; - if (b->next_bio != NULL) - b->next_bio->prev_bio = b->prev_bio; - - b->next_bio = NULL; - b->prev_bio = NULL; - return ret; -} - -BIO *BIO_get_retry_BIO(BIO *bio, int *reason) -{ - BIO *b, *last; - - b = last = bio; - for (;;) { - if (!BIO_should_retry(b)) - break; - last = b; - b = b->next_bio; - if (b == NULL) - break; - } - if (reason != NULL) - *reason = last->retry_reason; - return last; -} - -int BIO_get_retry_reason(BIO *bio) -{ - return bio->retry_reason; -} - -void BIO_set_retry_reason(BIO *bio, int reason) -{ - bio->retry_reason = reason; -} - -BIO *BIO_find_type(BIO *bio, int type) -{ - int mt, mask; - - if (bio == NULL) - return NULL; - mask = type & 0xff; - do { - if (bio->method != NULL) { - mt = bio->method->type; - - if (!mask) { - if (mt & type) - return bio; - } else if (mt == type) - return bio; - } - bio = bio->next_bio; - } while (bio != NULL); - return NULL; -} - -BIO *BIO_next(BIO *b) -{ - if (b == NULL) - return NULL; - return b->next_bio; -} - -void BIO_set_next(BIO *b, BIO *next) -{ - b->next_bio = next; -} - -void BIO_free_all(BIO *bio) -{ - BIO *b; - int ref; - - while (bio != NULL) { - b = bio; - ref = b->references; - bio = bio->next_bio; - BIO_free(b); - /* Since ref count > 1, don't free anyone else. */ - if (ref > 1) - break; - } -} - -BIO *BIO_dup_chain(BIO *in) -{ - BIO *ret = NULL, *eoc = NULL, *bio, *new_bio; - - for (bio = in; bio != NULL; bio = bio->next_bio) { - if ((new_bio = BIO_new(bio->method)) == NULL) - goto err; - new_bio->callback = bio->callback; - new_bio->callback_ex = bio->callback_ex; - new_bio->cb_arg = bio->cb_arg; - new_bio->init = bio->init; - new_bio->shutdown = bio->shutdown; - new_bio->flags = bio->flags; - - /* This will let SSL_s_sock() work with stdin/stdout */ - new_bio->num = bio->num; - - if (!BIO_dup_state(bio, (char *)new_bio)) { - BIO_free(new_bio); - goto err; - } - - /* copy app data */ - if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_BIO, &new_bio->ex_data, - &bio->ex_data)) { - BIO_free(new_bio); - goto err; - } - - if (ret == NULL) { - eoc = new_bio; - ret = eoc; - } else { - BIO_push(eoc, new_bio); - eoc = new_bio; - } - } - return ret; - err: - BIO_free_all(ret); - - return NULL; -} - -void BIO_copy_next_retry(BIO *b) -{ - BIO_set_flags(b, BIO_get_retry_flags(b->next_bio)); - b->retry_reason = b->next_bio->retry_reason; -} - -int BIO_set_ex_data(BIO *bio, int idx, void *data) -{ - return CRYPTO_set_ex_data(&(bio->ex_data), idx, data); -} - -void *BIO_get_ex_data(BIO *bio, int idx) -{ - return CRYPTO_get_ex_data(&(bio->ex_data), idx); -} - -uint64_t BIO_number_read(BIO *bio) -{ - if (bio) - return bio->num_read; - return 0; -} - -uint64_t BIO_number_written(BIO *bio) -{ - if (bio) - return bio->num_write; - return 0; -} - -void bio_free_ex_data(BIO *bio) -{ - CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data); -} - -void bio_cleanup(void) -{ -#ifndef OPENSSL_NO_SOCK - bio_sock_cleanup_int(); - CRYPTO_THREAD_lock_free(bio_lookup_lock); - bio_lookup_lock = NULL; -#endif - CRYPTO_THREAD_lock_free(bio_type_lock); - bio_type_lock = NULL; -} +#include "internal/cryptlib.h" + + +/* + * Helper macro for the callback to determine whether an operator expects a + * len parameter or not + */ +#define HAS_LEN_OPER(o) ((o) == BIO_CB_READ || (o) == BIO_CB_WRITE || \ + (o) == BIO_CB_GETS) + +/* + * Helper function to work out whether to call the new style callback or the old + * one, and translate between the two. + * + * This has a long return type for consistency with the old callback. Similarly + * for the "long" used for "inret" + */ +static long bio_call_callback(BIO *b, int oper, const char *argp, size_t len, + int argi, long argl, long inret, size_t *processed) +{ + long ret; + int bareoper; + + if (b->callback_ex != NULL) + return b->callback_ex(b, oper, argp, len, argi, argl, inret, processed); + + /* Strip off any BIO_CB_RETURN flag */ + bareoper = oper & ~BIO_CB_RETURN; + + /* + * We have an old style callback, so we will have to do nasty casts and + * check for overflows. + */ + if (HAS_LEN_OPER(bareoper)) { + /* In this case |len| is set, and should be used instead of |argi| */ + if (len > INT_MAX) + return -1; + + argi = (int)len; + } + + if (inret > 0 && (oper & BIO_CB_RETURN) && bareoper != BIO_CB_CTRL) { + if (*processed > INT_MAX) + return -1; + inret = *processed; + } + + ret = b->callback(b, oper, argp, argi, argl, inret); + + if (ret > 0 && (oper & BIO_CB_RETURN) && bareoper != BIO_CB_CTRL) { + *processed = (size_t)ret; + ret = 1; + } + + return ret; +} + +BIO *BIO_new(const BIO_METHOD *method) +{ + BIO *bio = OPENSSL_zalloc(sizeof(*bio)); + + if (bio == NULL) { + BIOerr(BIO_F_BIO_NEW, ERR_R_MALLOC_FAILURE); + return NULL; + } + + bio->method = method; + bio->shutdown = 1; + bio->references = 1; + + if (!CRYPTO_new_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data)) + goto err; + + bio->lock = CRYPTO_THREAD_lock_new(); + if (bio->lock == NULL) { + BIOerr(BIO_F_BIO_NEW, ERR_R_MALLOC_FAILURE); + CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data); + goto err; + } + + if (method->create != NULL && !method->create(bio)) { + BIOerr(BIO_F_BIO_NEW, ERR_R_INIT_FAIL); + CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data); + CRYPTO_THREAD_lock_free(bio->lock); + goto err; + } + if (method->create == NULL) + bio->init = 1; + + return bio; + +err: + OPENSSL_free(bio); + return NULL; +} + +int BIO_free(BIO *a) +{ + int ret; + + if (a == NULL) + return 0; + + if (CRYPTO_DOWN_REF(&a->references, &ret, a->lock) <= 0) + return 0; + + REF_PRINT_COUNT("BIO", a); + if (ret > 0) + return 1; + REF_ASSERT_ISNT(ret < 0); + + if (a->callback != NULL || a->callback_ex != NULL) { + ret = (int)bio_call_callback(a, BIO_CB_FREE, NULL, 0, 0, 0L, 1L, NULL); + if (ret <= 0) + return ret; + } + + if ((a->method != NULL) && (a->method->destroy != NULL)) + a->method->destroy(a); + + CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, a, &a->ex_data); + + CRYPTO_THREAD_lock_free(a->lock); + + OPENSSL_free(a); + + return 1; +} + +void BIO_set_data(BIO *a, void *ptr) +{ + a->ptr = ptr; +} + +void *BIO_get_data(BIO *a) +{ + return a->ptr; +} + +void BIO_set_init(BIO *a, int init) +{ + a->init = init; +} + +int BIO_get_init(BIO *a) +{ + return a->init; +} + +void BIO_set_shutdown(BIO *a, int shut) +{ + a->shutdown = shut; +} + +int BIO_get_shutdown(BIO *a) +{ + return a->shutdown; +} + +void BIO_vfree(BIO *a) +{ + BIO_free(a); +} + +int BIO_up_ref(BIO *a) +{ + int i; + + if (CRYPTO_UP_REF(&a->references, &i, a->lock) <= 0) + return 0; + + REF_PRINT_COUNT("BIO", a); + REF_ASSERT_ISNT(i < 2); + return ((i > 1) ? 1 : 0); +} + +void BIO_clear_flags(BIO *b, int flags) +{ + b->flags &= ~flags; +} + +int BIO_test_flags(const BIO *b, int flags) +{ + return (b->flags & flags); +} + +void BIO_set_flags(BIO *b, int flags) +{ + b->flags |= flags; +} + +BIO_callback_fn BIO_get_callback(const BIO *b) +{ + return b->callback; +} + +void BIO_set_callback(BIO *b, BIO_callback_fn cb) +{ + b->callback = cb; +} + +BIO_callback_fn_ex BIO_get_callback_ex(const BIO *b) +{ + return b->callback_ex; +} + +void BIO_set_callback_ex(BIO *b, BIO_callback_fn_ex cb) +{ + b->callback_ex = cb; +} + +void BIO_set_callback_arg(BIO *b, char *arg) +{ + b->cb_arg = arg; +} + +char *BIO_get_callback_arg(const BIO *b) +{ + return b->cb_arg; +} + +const char *BIO_method_name(const BIO *b) +{ + return b->method->name; +} + +int BIO_method_type(const BIO *b) +{ + return b->method->type; +} + +/* + * This is essentially the same as BIO_read_ex() except that it allows + * 0 or a negative value to indicate failure (retryable or not) in the return. + * This is for compatibility with the old style BIO_read(), where existing code + * may make assumptions about the return value that it might get. + */ +static int bio_read_intern(BIO *b, void *data, size_t dlen, size_t *readbytes) +{ + int ret; + + if ((b == NULL) || (b->method == NULL) || (b->method->bread == NULL)) { + BIOerr(BIO_F_BIO_READ_INTERN, BIO_R_UNSUPPORTED_METHOD); + return -2; + } + + if ((b->callback != NULL || b->callback_ex != NULL) && + ((ret = (int)bio_call_callback(b, BIO_CB_READ, data, dlen, 0, 0L, 1L, + NULL)) <= 0)) + return ret; + + if (!b->init) { + BIOerr(BIO_F_BIO_READ_INTERN, BIO_R_UNINITIALIZED); + return -2; + } + + ret = b->method->bread(b, data, dlen, readbytes); + + if (ret > 0) + b->num_read += (uint64_t)*readbytes; + + if (b->callback != NULL || b->callback_ex != NULL) + ret = (int)bio_call_callback(b, BIO_CB_READ | BIO_CB_RETURN, data, + dlen, 0, 0L, ret, readbytes); + + /* Shouldn't happen */ + if (ret > 0 && *readbytes > dlen) { + BIOerr(BIO_F_BIO_READ_INTERN, ERR_R_INTERNAL_ERROR); + return -1; + } + + return ret; +} + +int BIO_read(BIO *b, void *data, int dlen) +{ + size_t readbytes; + int ret; + + if (dlen < 0) + return 0; + + ret = bio_read_intern(b, data, (size_t)dlen, &readbytes); + + if (ret > 0) { + /* *readbytes should always be <= dlen */ + ret = (int)readbytes; + } + + return ret; +} + +int BIO_read_ex(BIO *b, void *data, size_t dlen, size_t *readbytes) +{ + int ret; + + ret = bio_read_intern(b, data, dlen, readbytes); + + if (ret > 0) + ret = 1; + else + ret = 0; + + return ret; +} + +static int bio_write_intern(BIO *b, const void *data, size_t dlen, + size_t *written) +{ + int ret; + + if (b == NULL) + return 0; + + if ((b->method == NULL) || (b->method->bwrite == NULL)) { + BIOerr(BIO_F_BIO_WRITE_INTERN, BIO_R_UNSUPPORTED_METHOD); + return -2; + } + + if ((b->callback != NULL || b->callback_ex != NULL) && + ((ret = (int)bio_call_callback(b, BIO_CB_WRITE, data, dlen, 0, 0L, 1L, + NULL)) <= 0)) + return ret; + + if (!b->init) { + BIOerr(BIO_F_BIO_WRITE_INTERN, BIO_R_UNINITIALIZED); + return -2; + } + + ret = b->method->bwrite(b, data, dlen, written); + + if (ret > 0) + b->num_write += (uint64_t)*written; + + if (b->callback != NULL || b->callback_ex != NULL) + ret = (int)bio_call_callback(b, BIO_CB_WRITE | BIO_CB_RETURN, data, + dlen, 0, 0L, ret, written); + + return ret; +} + +int BIO_write(BIO *b, const void *data, int dlen) +{ + size_t written; + int ret; + + if (dlen < 0) + return 0; + + ret = bio_write_intern(b, data, (size_t)dlen, &written); + + if (ret > 0) { + /* *written should always be <= dlen */ + ret = (int)written; + } + + return ret; +} + +int BIO_write_ex(BIO *b, const void *data, size_t dlen, size_t *written) +{ + int ret; + + ret = bio_write_intern(b, data, dlen, written); + + if (ret > 0) + ret = 1; + else + ret = 0; + + return ret; +} + +int BIO_puts(BIO *b, const char *buf) +{ + int ret; + size_t written = 0; + + if ((b == NULL) || (b->method == NULL) || (b->method->bputs == NULL)) { + BIOerr(BIO_F_BIO_PUTS, BIO_R_UNSUPPORTED_METHOD); + return -2; + } + + if (b->callback != NULL || b->callback_ex != NULL) { + ret = (int)bio_call_callback(b, BIO_CB_PUTS, buf, 0, 0, 0L, 1L, NULL); + if (ret <= 0) + return ret; + } + + if (!b->init) { + BIOerr(BIO_F_BIO_PUTS, BIO_R_UNINITIALIZED); + return -2; + } + + ret = b->method->bputs(b, buf); + + if (ret > 0) { + b->num_write += (uint64_t)ret; + written = ret; + ret = 1; + } + + if (b->callback != NULL || b->callback_ex != NULL) + ret = (int)bio_call_callback(b, BIO_CB_PUTS | BIO_CB_RETURN, buf, 0, 0, + 0L, ret, &written); + + if (ret > 0) { + if (written > INT_MAX) { + BIOerr(BIO_F_BIO_PUTS, BIO_R_LENGTH_TOO_LONG); + ret = -1; + } else { + ret = (int)written; + } + } + + return ret; +} + +int BIO_gets(BIO *b, char *buf, int size) +{ + int ret; + size_t readbytes = 0; + + if ((b == NULL) || (b->method == NULL) || (b->method->bgets == NULL)) { + BIOerr(BIO_F_BIO_GETS, BIO_R_UNSUPPORTED_METHOD); + return -2; + } + + if (size < 0) { + BIOerr(BIO_F_BIO_GETS, BIO_R_INVALID_ARGUMENT); + return 0; + } + + if (b->callback != NULL || b->callback_ex != NULL) { + ret = (int)bio_call_callback(b, BIO_CB_GETS, buf, size, 0, 0L, 1, NULL); + if (ret <= 0) + return ret; + } + + if (!b->init) { + BIOerr(BIO_F_BIO_GETS, BIO_R_UNINITIALIZED); + return -2; + } + + ret = b->method->bgets(b, buf, size); + + if (ret > 0) { + readbytes = ret; + ret = 1; + } + + if (b->callback != NULL || b->callback_ex != NULL) + ret = (int)bio_call_callback(b, BIO_CB_GETS | BIO_CB_RETURN, buf, size, + 0, 0L, ret, &readbytes); + + if (ret > 0) { + /* Shouldn't happen */ + if (readbytes > (size_t)size) + ret = -1; + else + ret = (int)readbytes; + } + + return ret; +} + +int BIO_indent(BIO *b, int indent, int max) +{ + if (indent < 0) + indent = 0; + if (indent > max) + indent = max; + while (indent--) + if (BIO_puts(b, " ") != 1) + return 0; + return 1; +} + +long BIO_int_ctrl(BIO *b, int cmd, long larg, int iarg) +{ + int i; + + i = iarg; + return BIO_ctrl(b, cmd, larg, (char *)&i); +} + +void *BIO_ptr_ctrl(BIO *b, int cmd, long larg) +{ + void *p = NULL; + + if (BIO_ctrl(b, cmd, larg, (char *)&p) <= 0) + return NULL; + else + return p; +} + +long BIO_ctrl(BIO *b, int cmd, long larg, void *parg) +{ + long ret; + + if (b == NULL) + return 0; + + if ((b->method == NULL) || (b->method->ctrl == NULL)) { + BIOerr(BIO_F_BIO_CTRL, BIO_R_UNSUPPORTED_METHOD); + return -2; + } + + if (b->callback != NULL || b->callback_ex != NULL) { + ret = bio_call_callback(b, BIO_CB_CTRL, parg, 0, cmd, larg, 1L, NULL); + if (ret <= 0) + return ret; + } + + ret = b->method->ctrl(b, cmd, larg, parg); + + if (b->callback != NULL || b->callback_ex != NULL) + ret = bio_call_callback(b, BIO_CB_CTRL | BIO_CB_RETURN, parg, 0, cmd, + larg, ret, NULL); + + return ret; +} + +long BIO_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) +{ + long ret; + + if (b == NULL) + return 0; + + if ((b->method == NULL) || (b->method->callback_ctrl == NULL) + || (cmd != BIO_CTRL_SET_CALLBACK)) { + BIOerr(BIO_F_BIO_CALLBACK_CTRL, BIO_R_UNSUPPORTED_METHOD); + return -2; + } + + if (b->callback != NULL || b->callback_ex != NULL) { + ret = bio_call_callback(b, BIO_CB_CTRL, (void *)&fp, 0, cmd, 0, 1L, + NULL); + if (ret <= 0) + return ret; + } + + ret = b->method->callback_ctrl(b, cmd, fp); + + if (b->callback != NULL || b->callback_ex != NULL) + ret = bio_call_callback(b, BIO_CB_CTRL | BIO_CB_RETURN, (void *)&fp, 0, + cmd, 0, ret, NULL); + + return ret; +} + +/* + * It is unfortunate to duplicate in functions what the BIO_(w)pending macros + * do; but those macros have inappropriate return type, and for interfacing + * from other programming languages, C macros aren't much of a help anyway. + */ +size_t BIO_ctrl_pending(BIO *bio) +{ + return BIO_ctrl(bio, BIO_CTRL_PENDING, 0, NULL); +} + +size_t BIO_ctrl_wpending(BIO *bio) +{ + return BIO_ctrl(bio, BIO_CTRL_WPENDING, 0, NULL); +} + +/* put the 'bio' on the end of b's list of operators */ +BIO *BIO_push(BIO *b, BIO *bio) +{ + BIO *lb; + + if (b == NULL) + return bio; + lb = b; + while (lb->next_bio != NULL) + lb = lb->next_bio; + lb->next_bio = bio; + if (bio != NULL) + bio->prev_bio = lb; + /* called to do internal processing */ + BIO_ctrl(b, BIO_CTRL_PUSH, 0, lb); + return b; +} + +/* Remove the first and return the rest */ +BIO *BIO_pop(BIO *b) +{ + BIO *ret; + + if (b == NULL) + return NULL; + ret = b->next_bio; + + BIO_ctrl(b, BIO_CTRL_POP, 0, b); + + if (b->prev_bio != NULL) + b->prev_bio->next_bio = b->next_bio; + if (b->next_bio != NULL) + b->next_bio->prev_bio = b->prev_bio; + + b->next_bio = NULL; + b->prev_bio = NULL; + return ret; +} + +BIO *BIO_get_retry_BIO(BIO *bio, int *reason) +{ + BIO *b, *last; + + b = last = bio; + for (;;) { + if (!BIO_should_retry(b)) + break; + last = b; + b = b->next_bio; + if (b == NULL) + break; + } + if (reason != NULL) + *reason = last->retry_reason; + return last; +} + +int BIO_get_retry_reason(BIO *bio) +{ + return bio->retry_reason; +} + +void BIO_set_retry_reason(BIO *bio, int reason) +{ + bio->retry_reason = reason; +} + +BIO *BIO_find_type(BIO *bio, int type) +{ + int mt, mask; + + if (bio == NULL) + return NULL; + mask = type & 0xff; + do { + if (bio->method != NULL) { + mt = bio->method->type; + + if (!mask) { + if (mt & type) + return bio; + } else if (mt == type) + return bio; + } + bio = bio->next_bio; + } while (bio != NULL); + return NULL; +} + +BIO *BIO_next(BIO *b) +{ + if (b == NULL) + return NULL; + return b->next_bio; +} + +void BIO_set_next(BIO *b, BIO *next) +{ + b->next_bio = next; +} + +void BIO_free_all(BIO *bio) +{ + BIO *b; + int ref; + + while (bio != NULL) { + b = bio; + ref = b->references; + bio = bio->next_bio; + BIO_free(b); + /* Since ref count > 1, don't free anyone else. */ + if (ref > 1) + break; + } +} + +BIO *BIO_dup_chain(BIO *in) +{ + BIO *ret = NULL, *eoc = NULL, *bio, *new_bio; + + for (bio = in; bio != NULL; bio = bio->next_bio) { + if ((new_bio = BIO_new(bio->method)) == NULL) + goto err; + new_bio->callback = bio->callback; + new_bio->callback_ex = bio->callback_ex; + new_bio->cb_arg = bio->cb_arg; + new_bio->init = bio->init; + new_bio->shutdown = bio->shutdown; + new_bio->flags = bio->flags; + + /* This will let SSL_s_sock() work with stdin/stdout */ + new_bio->num = bio->num; + + if (!BIO_dup_state(bio, (char *)new_bio)) { + BIO_free(new_bio); + goto err; + } + + /* copy app data */ + if (!CRYPTO_dup_ex_data(CRYPTO_EX_INDEX_BIO, &new_bio->ex_data, + &bio->ex_data)) { + BIO_free(new_bio); + goto err; + } + + if (ret == NULL) { + eoc = new_bio; + ret = eoc; + } else { + BIO_push(eoc, new_bio); + eoc = new_bio; + } + } + return ret; + err: + BIO_free_all(ret); + + return NULL; +} + +void BIO_copy_next_retry(BIO *b) +{ + BIO_set_flags(b, BIO_get_retry_flags(b->next_bio)); + b->retry_reason = b->next_bio->retry_reason; +} + +int BIO_set_ex_data(BIO *bio, int idx, void *data) +{ + return CRYPTO_set_ex_data(&(bio->ex_data), idx, data); +} + +void *BIO_get_ex_data(BIO *bio, int idx) +{ + return CRYPTO_get_ex_data(&(bio->ex_data), idx); +} + +uint64_t BIO_number_read(BIO *bio) +{ + if (bio) + return bio->num_read; + return 0; +} + +uint64_t BIO_number_written(BIO *bio) +{ + if (bio) + return bio->num_write; + return 0; +} + +void bio_free_ex_data(BIO *bio) +{ + CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, bio, &bio->ex_data); +} + +void bio_cleanup(void) +{ +#ifndef OPENSSL_NO_SOCK + bio_sock_cleanup_int(); + CRYPTO_THREAD_lock_free(bio_lookup_lock); + bio_lookup_lock = NULL; +#endif + CRYPTO_THREAD_lock_free(bio_type_lock); + bio_type_lock = NULL; +} diff --git a/contrib/libs/openssl/crypto/bio/bio_meth.c b/contrib/libs/openssl/crypto/bio/bio_meth.c index 9da4f51bf9..da11646192 100644 --- a/contrib/libs/openssl/crypto/bio/bio_meth.c +++ b/contrib/libs/openssl/crypto/bio/bio_meth.c @@ -1,220 +1,220 @@ -/* - * 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 - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - +/* + * 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 + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + #include "bio_local.h" -#include "internal/thread_once.h" - -CRYPTO_RWLOCK *bio_type_lock = NULL; -static CRYPTO_ONCE bio_type_init = CRYPTO_ONCE_STATIC_INIT; - -DEFINE_RUN_ONCE_STATIC(do_bio_type_init) -{ - bio_type_lock = CRYPTO_THREAD_lock_new(); - return bio_type_lock != NULL; -} - -int BIO_get_new_index(void) -{ - static CRYPTO_REF_COUNT bio_count = BIO_TYPE_START; - int newval; - - if (!RUN_ONCE(&bio_type_init, do_bio_type_init)) { - BIOerr(BIO_F_BIO_GET_NEW_INDEX, ERR_R_MALLOC_FAILURE); - return -1; - } - if (!CRYPTO_UP_REF(&bio_count, &newval, bio_type_lock)) - return -1; - return newval; -} - -BIO_METHOD *BIO_meth_new(int type, const char *name) -{ - BIO_METHOD *biom = OPENSSL_zalloc(sizeof(BIO_METHOD)); - - if (biom == NULL - || (biom->name = OPENSSL_strdup(name)) == NULL) { - OPENSSL_free(biom); - BIOerr(BIO_F_BIO_METH_NEW, ERR_R_MALLOC_FAILURE); - return NULL; - } - biom->type = type; - return biom; -} - -void BIO_meth_free(BIO_METHOD *biom) -{ - if (biom != NULL) { - OPENSSL_free(biom->name); - OPENSSL_free(biom); - } -} - -int (*BIO_meth_get_write(const BIO_METHOD *biom)) (BIO *, const char *, int) -{ - return biom->bwrite_old; -} - -int (*BIO_meth_get_write_ex(const BIO_METHOD *biom)) (BIO *, const char *, size_t, - size_t *) -{ - return biom->bwrite; -} - -/* Conversion for old style bwrite to new style */ -int bwrite_conv(BIO *bio, const char *data, size_t datal, size_t *written) -{ - int ret; - - if (datal > INT_MAX) - datal = INT_MAX; - - ret = bio->method->bwrite_old(bio, data, (int)datal); - - if (ret <= 0) { - *written = 0; - return ret; - } - - *written = (size_t)ret; - - return 1; -} - -int BIO_meth_set_write(BIO_METHOD *biom, - int (*bwrite) (BIO *, const char *, int)) -{ - biom->bwrite_old = bwrite; - biom->bwrite = bwrite_conv; - return 1; -} - -int BIO_meth_set_write_ex(BIO_METHOD *biom, - int (*bwrite) (BIO *, const char *, size_t, size_t *)) -{ - biom->bwrite_old = NULL; - biom->bwrite = bwrite; - return 1; -} - -int (*BIO_meth_get_read(const BIO_METHOD *biom)) (BIO *, char *, int) -{ - return biom->bread_old; -} - -int (*BIO_meth_get_read_ex(const BIO_METHOD *biom)) (BIO *, char *, size_t, size_t *) -{ - return biom->bread; -} - -/* Conversion for old style bread to new style */ -int bread_conv(BIO *bio, char *data, size_t datal, size_t *readbytes) -{ - int ret; - - if (datal > INT_MAX) - datal = INT_MAX; - - ret = bio->method->bread_old(bio, data, (int)datal); - - if (ret <= 0) { - *readbytes = 0; - return ret; - } - - *readbytes = (size_t)ret; - - return 1; -} - -int BIO_meth_set_read(BIO_METHOD *biom, - int (*bread) (BIO *, char *, int)) -{ - biom->bread_old = bread; - biom->bread = bread_conv; - return 1; -} - -int BIO_meth_set_read_ex(BIO_METHOD *biom, - int (*bread) (BIO *, char *, size_t, size_t *)) -{ - biom->bread_old = NULL; - biom->bread = bread; - return 1; -} - -int (*BIO_meth_get_puts(const BIO_METHOD *biom)) (BIO *, const char *) -{ - return biom->bputs; -} - -int BIO_meth_set_puts(BIO_METHOD *biom, - int (*bputs) (BIO *, const char *)) -{ - biom->bputs = bputs; - return 1; -} - -int (*BIO_meth_get_gets(const BIO_METHOD *biom)) (BIO *, char *, int) -{ - return biom->bgets; -} - -int BIO_meth_set_gets(BIO_METHOD *biom, - int (*bgets) (BIO *, char *, int)) -{ - biom->bgets = bgets; - return 1; -} - -long (*BIO_meth_get_ctrl(const BIO_METHOD *biom)) (BIO *, int, long, void *) -{ - return biom->ctrl; -} - -int BIO_meth_set_ctrl(BIO_METHOD *biom, - long (*ctrl) (BIO *, int, long, void *)) -{ - biom->ctrl = ctrl; - return 1; -} - -int (*BIO_meth_get_create(const BIO_METHOD *biom)) (BIO *) -{ - return biom->create; -} - -int BIO_meth_set_create(BIO_METHOD *biom, int (*create) (BIO *)) -{ - biom->create = create; - return 1; -} - -int (*BIO_meth_get_destroy(const BIO_METHOD *biom)) (BIO *) -{ - return biom->destroy; -} - -int BIO_meth_set_destroy(BIO_METHOD *biom, int (*destroy) (BIO *)) -{ - biom->destroy = destroy; - return 1; -} - -long (*BIO_meth_get_callback_ctrl(const BIO_METHOD *biom)) (BIO *, int, BIO_info_cb *) -{ - return biom->callback_ctrl; -} - -int BIO_meth_set_callback_ctrl(BIO_METHOD *biom, - long (*callback_ctrl) (BIO *, int, - BIO_info_cb *)) -{ - biom->callback_ctrl = callback_ctrl; - return 1; -} +#include "internal/thread_once.h" + +CRYPTO_RWLOCK *bio_type_lock = NULL; +static CRYPTO_ONCE bio_type_init = CRYPTO_ONCE_STATIC_INIT; + +DEFINE_RUN_ONCE_STATIC(do_bio_type_init) +{ + bio_type_lock = CRYPTO_THREAD_lock_new(); + return bio_type_lock != NULL; +} + +int BIO_get_new_index(void) +{ + static CRYPTO_REF_COUNT bio_count = BIO_TYPE_START; + int newval; + + if (!RUN_ONCE(&bio_type_init, do_bio_type_init)) { + BIOerr(BIO_F_BIO_GET_NEW_INDEX, ERR_R_MALLOC_FAILURE); + return -1; + } + if (!CRYPTO_UP_REF(&bio_count, &newval, bio_type_lock)) + return -1; + return newval; +} + +BIO_METHOD *BIO_meth_new(int type, const char *name) +{ + BIO_METHOD *biom = OPENSSL_zalloc(sizeof(BIO_METHOD)); + + if (biom == NULL + || (biom->name = OPENSSL_strdup(name)) == NULL) { + OPENSSL_free(biom); + BIOerr(BIO_F_BIO_METH_NEW, ERR_R_MALLOC_FAILURE); + return NULL; + } + biom->type = type; + return biom; +} + +void BIO_meth_free(BIO_METHOD *biom) +{ + if (biom != NULL) { + OPENSSL_free(biom->name); + OPENSSL_free(biom); + } +} + +int (*BIO_meth_get_write(const BIO_METHOD *biom)) (BIO *, const char *, int) +{ + return biom->bwrite_old; +} + +int (*BIO_meth_get_write_ex(const BIO_METHOD *biom)) (BIO *, const char *, size_t, + size_t *) +{ + return biom->bwrite; +} + +/* Conversion for old style bwrite to new style */ +int bwrite_conv(BIO *bio, const char *data, size_t datal, size_t *written) +{ + int ret; + + if (datal > INT_MAX) + datal = INT_MAX; + + ret = bio->method->bwrite_old(bio, data, (int)datal); + + if (ret <= 0) { + *written = 0; + return ret; + } + + *written = (size_t)ret; + + return 1; +} + +int BIO_meth_set_write(BIO_METHOD *biom, + int (*bwrite) (BIO *, const char *, int)) +{ + biom->bwrite_old = bwrite; + biom->bwrite = bwrite_conv; + return 1; +} + +int BIO_meth_set_write_ex(BIO_METHOD *biom, + int (*bwrite) (BIO *, const char *, size_t, size_t *)) +{ + biom->bwrite_old = NULL; + biom->bwrite = bwrite; + return 1; +} + +int (*BIO_meth_get_read(const BIO_METHOD *biom)) (BIO *, char *, int) +{ + return biom->bread_old; +} + +int (*BIO_meth_get_read_ex(const BIO_METHOD *biom)) (BIO *, char *, size_t, size_t *) +{ + return biom->bread; +} + +/* Conversion for old style bread to new style */ +int bread_conv(BIO *bio, char *data, size_t datal, size_t *readbytes) +{ + int ret; + + if (datal > INT_MAX) + datal = INT_MAX; + + ret = bio->method->bread_old(bio, data, (int)datal); + + if (ret <= 0) { + *readbytes = 0; + return ret; + } + + *readbytes = (size_t)ret; + + return 1; +} + +int BIO_meth_set_read(BIO_METHOD *biom, + int (*bread) (BIO *, char *, int)) +{ + biom->bread_old = bread; + biom->bread = bread_conv; + return 1; +} + +int BIO_meth_set_read_ex(BIO_METHOD *biom, + int (*bread) (BIO *, char *, size_t, size_t *)) +{ + biom->bread_old = NULL; + biom->bread = bread; + return 1; +} + +int (*BIO_meth_get_puts(const BIO_METHOD *biom)) (BIO *, const char *) +{ + return biom->bputs; +} + +int BIO_meth_set_puts(BIO_METHOD *biom, + int (*bputs) (BIO *, const char *)) +{ + biom->bputs = bputs; + return 1; +} + +int (*BIO_meth_get_gets(const BIO_METHOD *biom)) (BIO *, char *, int) +{ + return biom->bgets; +} + +int BIO_meth_set_gets(BIO_METHOD *biom, + int (*bgets) (BIO *, char *, int)) +{ + biom->bgets = bgets; + return 1; +} + +long (*BIO_meth_get_ctrl(const BIO_METHOD *biom)) (BIO *, int, long, void *) +{ + return biom->ctrl; +} + +int BIO_meth_set_ctrl(BIO_METHOD *biom, + long (*ctrl) (BIO *, int, long, void *)) +{ + biom->ctrl = ctrl; + return 1; +} + +int (*BIO_meth_get_create(const BIO_METHOD *biom)) (BIO *) +{ + return biom->create; +} + +int BIO_meth_set_create(BIO_METHOD *biom, int (*create) (BIO *)) +{ + biom->create = create; + return 1; +} + +int (*BIO_meth_get_destroy(const BIO_METHOD *biom)) (BIO *) +{ + return biom->destroy; +} + +int BIO_meth_set_destroy(BIO_METHOD *biom, int (*destroy) (BIO *)) +{ + biom->destroy = destroy; + return 1; +} + +long (*BIO_meth_get_callback_ctrl(const BIO_METHOD *biom)) (BIO *, int, BIO_info_cb *) +{ + return biom->callback_ctrl; +} + +int BIO_meth_set_callback_ctrl(BIO_METHOD *biom, + long (*callback_ctrl) (BIO *, int, + BIO_info_cb *)) +{ + biom->callback_ctrl = callback_ctrl; + return 1; +} diff --git a/contrib/libs/openssl/crypto/bio/bss_acpt.c b/contrib/libs/openssl/crypto/bio/bss_acpt.c index 29b2b45749..4461eae233 100644 --- a/contrib/libs/openssl/crypto/bio/bss_acpt.c +++ b/contrib/libs/openssl/crypto/bio/bss_acpt.c @@ -1,568 +1,568 @@ -/* +/* * Copyright 1995-2020 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 - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -#include <stdio.h> -#include <errno.h> + * + * Licensed under the OpenSSL license (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 <stdio.h> +#include <errno.h> #include "bio_local.h" - -#ifndef OPENSSL_NO_SOCK - -typedef struct bio_accept_st { - int state; - int accept_family; - int bind_mode; /* Socket mode for BIO_listen */ - int accepted_mode; /* Socket mode for BIO_accept (set on accepted sock) */ - char *param_addr; - char *param_serv; - - int accept_sock; - - BIO_ADDRINFO *addr_first; - const BIO_ADDRINFO *addr_iter; - BIO_ADDR cache_accepting_addr; /* Useful if we asked for port 0 */ - char *cache_accepting_name, *cache_accepting_serv; - BIO_ADDR cache_peer_addr; - char *cache_peer_name, *cache_peer_serv; - - BIO *bio_chain; -} BIO_ACCEPT; - -static int acpt_write(BIO *h, const char *buf, int num); -static int acpt_read(BIO *h, char *buf, int size); -static int acpt_puts(BIO *h, const char *str); -static long acpt_ctrl(BIO *h, int cmd, long arg1, void *arg2); -static int acpt_new(BIO *h); -static int acpt_free(BIO *data); -static int acpt_state(BIO *b, BIO_ACCEPT *c); -static void acpt_close_socket(BIO *data); -static BIO_ACCEPT *BIO_ACCEPT_new(void); -static void BIO_ACCEPT_free(BIO_ACCEPT *a); - -# define ACPT_S_BEFORE 1 -# define ACPT_S_GET_ADDR 2 -# define ACPT_S_CREATE_SOCKET 3 -# define ACPT_S_LISTEN 4 -# define ACPT_S_ACCEPT 5 -# define ACPT_S_OK 6 - -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, */ - acpt_ctrl, - acpt_new, - acpt_free, - NULL, /* connect_callback_ctrl */ -}; - -const BIO_METHOD *BIO_s_accept(void) -{ - return &methods_acceptp; -} - -static int acpt_new(BIO *bi) -{ - BIO_ACCEPT *ba; - - bi->init = 0; - bi->num = (int)INVALID_SOCKET; - bi->flags = 0; - if ((ba = BIO_ACCEPT_new()) == NULL) - return 0; - bi->ptr = (char *)ba; - ba->state = ACPT_S_BEFORE; - bi->shutdown = 1; - return 1; -} - -static BIO_ACCEPT *BIO_ACCEPT_new(void) -{ - BIO_ACCEPT *ret; - - if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL) { - BIOerr(BIO_F_BIO_ACCEPT_NEW, ERR_R_MALLOC_FAILURE); - return NULL; - } - ret->accept_family = BIO_FAMILY_IPANY; - ret->accept_sock = (int)INVALID_SOCKET; - 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); - OPENSSL_free(a->cache_accepting_name); - OPENSSL_free(a->cache_accepting_serv); - OPENSSL_free(a->cache_peer_name); - OPENSSL_free(a->cache_peer_serv); - BIO_free(a->bio_chain); - OPENSSL_free(a); -} - -static void acpt_close_socket(BIO *bio) -{ - BIO_ACCEPT *c; - - c = (BIO_ACCEPT *)bio->ptr; - if (c->accept_sock != (int)INVALID_SOCKET) { - shutdown(c->accept_sock, 2); - closesocket(c->accept_sock); - c->accept_sock = (int)INVALID_SOCKET; - bio->num = (int)INVALID_SOCKET; - } -} - -static int acpt_free(BIO *a) -{ - BIO_ACCEPT *data; - - if (a == NULL) - return 0; - data = (BIO_ACCEPT *)a->ptr; - - if (a->shutdown) { - acpt_close_socket(a); - BIO_ACCEPT_free(data); - a->ptr = NULL; - a->flags = 0; - a->init = 0; - } - return 1; -} - -static int acpt_state(BIO *b, BIO_ACCEPT *c) -{ - BIO *bio = NULL, *dbio; - int s = -1, ret = -1; - - for (;;) { - 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); - goto exit_loop; - } - - /* Because we're starting a new bind, any cached name and serv - * are now obsolete and need to be cleaned out. - * QUESTION: should this be done in acpt_close_socket() instead? - */ - OPENSSL_free(c->cache_accepting_name); - c->cache_accepting_name = NULL; - OPENSSL_free(c->cache_accepting_serv); - c->cache_accepting_serv = NULL; - OPENSSL_free(c->cache_peer_name); - c->cache_peer_name = NULL; - OPENSSL_free(c->cache_peer_serv); - c->cache_peer_serv = NULL; - - c->state = ACPT_S_GET_ADDR; - break; - - case ACPT_S_GET_ADDR: - { - int family = AF_UNSPEC; - switch (c->accept_family) { - case BIO_FAMILY_IPV6: - if (1) { /* This is a trick we use to avoid bit rot. - * at least the "else" part will always be - * compiled. - */ -#ifdef AF_INET6 - family = AF_INET6; - } else { -#endif - BIOerr(BIO_F_ACPT_STATE, BIO_R_UNAVAILABLE_IP_FAMILY); - goto exit_loop; - } - break; - case BIO_FAMILY_IPV4: - family = AF_INET; - break; - case BIO_FAMILY_IPANY: - family = AF_UNSPEC; - break; - default: - BIOerr(BIO_F_ACPT_STATE, BIO_R_UNSUPPORTED_IP_FAMILY); - goto exit_loop; - } - if (BIO_lookup(c->param_addr, c->param_serv, BIO_LOOKUP_SERVER, - family, SOCK_STREAM, &c->addr_first) == 0) - goto exit_loop; - } - if (c->addr_first == NULL) { - BIOerr(BIO_F_ACPT_STATE, 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: + +#ifndef OPENSSL_NO_SOCK + +typedef struct bio_accept_st { + int state; + int accept_family; + int bind_mode; /* Socket mode for BIO_listen */ + int accepted_mode; /* Socket mode for BIO_accept (set on accepted sock) */ + char *param_addr; + char *param_serv; + + int accept_sock; + + BIO_ADDRINFO *addr_first; + const BIO_ADDRINFO *addr_iter; + BIO_ADDR cache_accepting_addr; /* Useful if we asked for port 0 */ + char *cache_accepting_name, *cache_accepting_serv; + BIO_ADDR cache_peer_addr; + char *cache_peer_name, *cache_peer_serv; + + BIO *bio_chain; +} BIO_ACCEPT; + +static int acpt_write(BIO *h, const char *buf, int num); +static int acpt_read(BIO *h, char *buf, int size); +static int acpt_puts(BIO *h, const char *str); +static long acpt_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int acpt_new(BIO *h); +static int acpt_free(BIO *data); +static int acpt_state(BIO *b, BIO_ACCEPT *c); +static void acpt_close_socket(BIO *data); +static BIO_ACCEPT *BIO_ACCEPT_new(void); +static void BIO_ACCEPT_free(BIO_ACCEPT *a); + +# define ACPT_S_BEFORE 1 +# define ACPT_S_GET_ADDR 2 +# define ACPT_S_CREATE_SOCKET 3 +# define ACPT_S_LISTEN 4 +# define ACPT_S_ACCEPT 5 +# define ACPT_S_OK 6 + +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, */ + acpt_ctrl, + acpt_new, + acpt_free, + NULL, /* connect_callback_ctrl */ +}; + +const BIO_METHOD *BIO_s_accept(void) +{ + return &methods_acceptp; +} + +static int acpt_new(BIO *bi) +{ + BIO_ACCEPT *ba; + + bi->init = 0; + bi->num = (int)INVALID_SOCKET; + bi->flags = 0; + if ((ba = BIO_ACCEPT_new()) == NULL) + return 0; + bi->ptr = (char *)ba; + ba->state = ACPT_S_BEFORE; + bi->shutdown = 1; + return 1; +} + +static BIO_ACCEPT *BIO_ACCEPT_new(void) +{ + BIO_ACCEPT *ret; + + if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL) { + BIOerr(BIO_F_BIO_ACCEPT_NEW, ERR_R_MALLOC_FAILURE); + return NULL; + } + ret->accept_family = BIO_FAMILY_IPANY; + ret->accept_sock = (int)INVALID_SOCKET; + 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); + OPENSSL_free(a->cache_accepting_name); + OPENSSL_free(a->cache_accepting_serv); + OPENSSL_free(a->cache_peer_name); + OPENSSL_free(a->cache_peer_serv); + BIO_free(a->bio_chain); + OPENSSL_free(a); +} + +static void acpt_close_socket(BIO *bio) +{ + BIO_ACCEPT *c; + + c = (BIO_ACCEPT *)bio->ptr; + if (c->accept_sock != (int)INVALID_SOCKET) { + shutdown(c->accept_sock, 2); + closesocket(c->accept_sock); + c->accept_sock = (int)INVALID_SOCKET; + bio->num = (int)INVALID_SOCKET; + } +} + +static int acpt_free(BIO *a) +{ + BIO_ACCEPT *data; + + if (a == NULL) + return 0; + data = (BIO_ACCEPT *)a->ptr; + + if (a->shutdown) { + acpt_close_socket(a); + BIO_ACCEPT_free(data); + a->ptr = NULL; + a->flags = 0; + a->init = 0; + } + return 1; +} + +static int acpt_state(BIO *b, BIO_ACCEPT *c) +{ + BIO *bio = NULL, *dbio; + int s = -1, ret = -1; + + for (;;) { + 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); + goto exit_loop; + } + + /* Because we're starting a new bind, any cached name and serv + * are now obsolete and need to be cleaned out. + * QUESTION: should this be done in acpt_close_socket() instead? + */ + OPENSSL_free(c->cache_accepting_name); + c->cache_accepting_name = NULL; + OPENSSL_free(c->cache_accepting_serv); + c->cache_accepting_serv = NULL; + OPENSSL_free(c->cache_peer_name); + c->cache_peer_name = NULL; + OPENSSL_free(c->cache_peer_serv); + c->cache_peer_serv = NULL; + + c->state = ACPT_S_GET_ADDR; + break; + + case ACPT_S_GET_ADDR: + { + int family = AF_UNSPEC; + switch (c->accept_family) { + case BIO_FAMILY_IPV6: + if (1) { /* This is a trick we use to avoid bit rot. + * at least the "else" part will always be + * compiled. + */ +#ifdef AF_INET6 + family = AF_INET6; + } else { +#endif + BIOerr(BIO_F_ACPT_STATE, BIO_R_UNAVAILABLE_IP_FAMILY); + goto exit_loop; + } + break; + case BIO_FAMILY_IPV4: + family = AF_INET; + break; + case BIO_FAMILY_IPANY: + family = AF_UNSPEC; + break; + default: + BIOerr(BIO_F_ACPT_STATE, BIO_R_UNSUPPORTED_IP_FAMILY); + goto exit_loop; + } + if (BIO_lookup(c->param_addr, c->param_serv, BIO_LOOKUP_SERVER, + family, SOCK_STREAM, &c->addr_first) == 0) + goto exit_loop; + } + if (c->addr_first == NULL) { + BIOerr(BIO_F_ACPT_STATE, 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: 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) { - 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); - goto exit_loop; - } + 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); + goto exit_loop; + } c->accept_sock = s; b->num = s; - c->state = ACPT_S_LISTEN; + c->state = ACPT_S_LISTEN; s = -1; - break; - - case ACPT_S_LISTEN: - { - if (!BIO_listen(c->accept_sock, - BIO_ADDRINFO_address(c->addr_iter), - c->bind_mode)) { - BIO_closesocket(c->accept_sock); - goto exit_loop; - } - } - - { - union BIO_sock_info_u info; - - info.addr = &c->cache_accepting_addr; - if (!BIO_sock_info(c->accept_sock, BIO_SOCK_INFO_ADDRESS, - &info)) { - BIO_closesocket(c->accept_sock); - goto exit_loop; - } - } - - c->cache_accepting_name = - BIO_ADDR_hostname_string(&c->cache_accepting_addr, 1); - c->cache_accepting_serv = - BIO_ADDR_service_string(&c->cache_accepting_addr, 1); - c->state = ACPT_S_ACCEPT; - s = -1; - ret = 1; - goto end; - - case ACPT_S_ACCEPT: - if (b->next_bio != NULL) { - c->state = ACPT_S_OK; - break; - } - 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); - - /* If the returned socket is invalid, this might still be - * retryable - */ - if (s < 0) { - if (BIO_sock_should_retry(s)) { - BIO_set_retry_special(b); - b->retry_reason = BIO_RR_ACCEPT; - goto end; - } - } - - /* If it wasn't retryable, we fail */ - if (s < 0) { - ret = s; - goto exit_loop; - } - - bio = BIO_new_socket(s, BIO_CLOSE); - if (bio == NULL) - goto exit_loop; - - BIO_set_callback(bio, BIO_get_callback(b)); - 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. - */ - if (c->bio_chain != NULL) { - if ((dbio = BIO_dup_chain(c->bio_chain)) == NULL) - goto exit_loop; - if (!BIO_push(dbio, bio)) - goto exit_loop; - bio = dbio; - } - if (BIO_push(b, bio) == NULL) - goto exit_loop; - - c->cache_peer_name = - BIO_ADDR_hostname_string(&c->cache_peer_addr, 1); - c->cache_peer_serv = - BIO_ADDR_service_string(&c->cache_peer_addr, 1); - c->state = ACPT_S_OK; - bio = NULL; - ret = 1; - goto end; - - case ACPT_S_OK: - if (b->next_bio == NULL) { - c->state = ACPT_S_ACCEPT; - break; - } - ret = 1; - goto end; - - default: - ret = 0; - goto end; - } - } - - exit_loop: - if (bio != NULL) - BIO_free(bio); - else if (s >= 0) - BIO_closesocket(s); - end: - return ret; -} - -static int acpt_read(BIO *b, char *out, int outl) -{ - int ret = 0; - BIO_ACCEPT *data; - - BIO_clear_retry_flags(b); - data = (BIO_ACCEPT *)b->ptr; - - while (b->next_bio == NULL) { - ret = acpt_state(b, data); - if (ret <= 0) - return ret; - } - - ret = BIO_read(b->next_bio, out, outl); - BIO_copy_next_retry(b); - return ret; -} - -static int acpt_write(BIO *b, const char *in, int inl) -{ - int ret; - BIO_ACCEPT *data; - - BIO_clear_retry_flags(b); - data = (BIO_ACCEPT *)b->ptr; - - while (b->next_bio == NULL) { - ret = acpt_state(b, data); - if (ret <= 0) - return ret; - } - - ret = BIO_write(b->next_bio, in, inl); - BIO_copy_next_retry(b); - return ret; -} - -static long acpt_ctrl(BIO *b, int cmd, long num, void *ptr) -{ - int *ip; - long ret = 1; - BIO_ACCEPT *data; - char **pp; - - data = (BIO_ACCEPT *)b->ptr; - - switch (cmd) { - case BIO_CTRL_RESET: - ret = 0; - data->state = ACPT_S_BEFORE; - acpt_close_socket(b); - BIO_ADDRINFO_free(data->addr_first); - data->addr_first = NULL; - b->flags = 0; - break; - case BIO_C_DO_STATE_MACHINE: - /* use this one to start the connection */ - ret = (long)acpt_state(b, data); - break; - case BIO_C_SET_ACCEPT: - if (ptr != NULL) { - if (num == 0) { - char *hold_serv = data->param_serv; - /* We affect the hostname regardless. However, the input - * string might contain a host:service spec, so we must - * parse it, which might or might not affect the service - */ - OPENSSL_free(data->param_addr); - data->param_addr = NULL; - ret = BIO_parse_hostserv(ptr, - &data->param_addr, - &data->param_serv, - BIO_PARSE_PRIO_SERV); - if (hold_serv != data->param_serv) - OPENSSL_free(hold_serv); - b->init = 1; - } else if (num == 1) { - OPENSSL_free(data->param_serv); + break; + + case ACPT_S_LISTEN: + { + if (!BIO_listen(c->accept_sock, + BIO_ADDRINFO_address(c->addr_iter), + c->bind_mode)) { + BIO_closesocket(c->accept_sock); + goto exit_loop; + } + } + + { + union BIO_sock_info_u info; + + info.addr = &c->cache_accepting_addr; + if (!BIO_sock_info(c->accept_sock, BIO_SOCK_INFO_ADDRESS, + &info)) { + BIO_closesocket(c->accept_sock); + goto exit_loop; + } + } + + c->cache_accepting_name = + BIO_ADDR_hostname_string(&c->cache_accepting_addr, 1); + c->cache_accepting_serv = + BIO_ADDR_service_string(&c->cache_accepting_addr, 1); + c->state = ACPT_S_ACCEPT; + s = -1; + ret = 1; + goto end; + + case ACPT_S_ACCEPT: + if (b->next_bio != NULL) { + c->state = ACPT_S_OK; + break; + } + 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); + + /* If the returned socket is invalid, this might still be + * retryable + */ + if (s < 0) { + if (BIO_sock_should_retry(s)) { + BIO_set_retry_special(b); + b->retry_reason = BIO_RR_ACCEPT; + goto end; + } + } + + /* If it wasn't retryable, we fail */ + if (s < 0) { + ret = s; + goto exit_loop; + } + + bio = BIO_new_socket(s, BIO_CLOSE); + if (bio == NULL) + goto exit_loop; + + BIO_set_callback(bio, BIO_get_callback(b)); + 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. + */ + if (c->bio_chain != NULL) { + if ((dbio = BIO_dup_chain(c->bio_chain)) == NULL) + goto exit_loop; + if (!BIO_push(dbio, bio)) + goto exit_loop; + bio = dbio; + } + if (BIO_push(b, bio) == NULL) + goto exit_loop; + + c->cache_peer_name = + BIO_ADDR_hostname_string(&c->cache_peer_addr, 1); + c->cache_peer_serv = + BIO_ADDR_service_string(&c->cache_peer_addr, 1); + c->state = ACPT_S_OK; + bio = NULL; + ret = 1; + goto end; + + case ACPT_S_OK: + if (b->next_bio == NULL) { + c->state = ACPT_S_ACCEPT; + break; + } + ret = 1; + goto end; + + default: + ret = 0; + goto end; + } + } + + exit_loop: + if (bio != NULL) + BIO_free(bio); + else if (s >= 0) + BIO_closesocket(s); + end: + return ret; +} + +static int acpt_read(BIO *b, char *out, int outl) +{ + int ret = 0; + BIO_ACCEPT *data; + + BIO_clear_retry_flags(b); + data = (BIO_ACCEPT *)b->ptr; + + while (b->next_bio == NULL) { + ret = acpt_state(b, data); + if (ret <= 0) + return ret; + } + + ret = BIO_read(b->next_bio, out, outl); + BIO_copy_next_retry(b); + return ret; +} + +static int acpt_write(BIO *b, const char *in, int inl) +{ + int ret; + BIO_ACCEPT *data; + + BIO_clear_retry_flags(b); + data = (BIO_ACCEPT *)b->ptr; + + while (b->next_bio == NULL) { + ret = acpt_state(b, data); + if (ret <= 0) + return ret; + } + + ret = BIO_write(b->next_bio, in, inl); + BIO_copy_next_retry(b); + return ret; +} + +static long acpt_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + int *ip; + long ret = 1; + BIO_ACCEPT *data; + char **pp; + + data = (BIO_ACCEPT *)b->ptr; + + switch (cmd) { + case BIO_CTRL_RESET: + ret = 0; + data->state = ACPT_S_BEFORE; + acpt_close_socket(b); + BIO_ADDRINFO_free(data->addr_first); + data->addr_first = NULL; + b->flags = 0; + break; + case BIO_C_DO_STATE_MACHINE: + /* use this one to start the connection */ + ret = (long)acpt_state(b, data); + break; + case BIO_C_SET_ACCEPT: + if (ptr != NULL) { + if (num == 0) { + char *hold_serv = data->param_serv; + /* We affect the hostname regardless. However, the input + * string might contain a host:service spec, so we must + * parse it, which might or might not affect the service + */ + OPENSSL_free(data->param_addr); + data->param_addr = NULL; + ret = BIO_parse_hostserv(ptr, + &data->param_addr, + &data->param_serv, + BIO_PARSE_PRIO_SERV); + if (hold_serv != data->param_serv) + OPENSSL_free(hold_serv); + b->init = 1; + } else if (num == 1) { + OPENSSL_free(data->param_serv); 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) { - BIO_free(data->bio_chain); - data->bio_chain = (BIO *)ptr; - } else if (num == 4) { - data->accept_family = *(int *)ptr; - } - } else { - if (num == 2) { - data->bind_mode &= ~BIO_SOCK_NONBLOCK; - } - } - break; - case BIO_C_SET_NBIO: - if (num != 0) - data->accepted_mode |= BIO_SOCK_NONBLOCK; - else - data->accepted_mode &= ~BIO_SOCK_NONBLOCK; - break; - case BIO_C_SET_FD: - b->num = *((int *)ptr); - data->accept_sock = b->num; - data->state = ACPT_S_ACCEPT; - b->shutdown = (int)num; - b->init = 1; - break; - case BIO_C_GET_FD: - if (b->init) { - ip = (int *)ptr; - if (ip != NULL) - *ip = data->accept_sock; - ret = data->accept_sock; - } else - ret = -1; - break; - case BIO_C_GET_ACCEPT: - if (b->init) { - if (num == 0 && ptr != NULL) { - pp = (char **)ptr; - *pp = data->cache_accepting_name; - } else if (num == 1 && ptr != NULL) { - pp = (char **)ptr; - *pp = data->cache_accepting_serv; - } else if (num == 2 && ptr != NULL) { - pp = (char **)ptr; - *pp = data->cache_peer_name; - } else if (num == 3 && ptr != NULL) { - pp = (char **)ptr; - *pp = data->cache_peer_serv; - } else if (num == 4) { - switch (BIO_ADDRINFO_family(data->addr_iter)) { -#ifdef AF_INET6 - case AF_INET6: - ret = BIO_FAMILY_IPV6; - break; -#endif - case AF_INET: - ret = BIO_FAMILY_IPV4; - break; - case 0: - ret = data->accept_family; - break; - default: - ret = -1; - break; - } - } else - ret = -1; - } else - ret = -1; - break; - case BIO_CTRL_GET_CLOSE: - ret = b->shutdown; - break; - case BIO_CTRL_SET_CLOSE: - b->shutdown = (int)num; - break; - case BIO_CTRL_PENDING: - case BIO_CTRL_WPENDING: - ret = 0; - break; - case BIO_CTRL_FLUSH: - break; - case BIO_C_SET_BIND_MODE: - data->bind_mode = (int)num; - break; - case BIO_C_GET_BIND_MODE: - ret = (long)data->bind_mode; - break; - case BIO_CTRL_DUP: - break; + } else if (num == 2) { + data->bind_mode |= BIO_SOCK_NONBLOCK; + } else if (num == 3) { + BIO_free(data->bio_chain); + data->bio_chain = (BIO *)ptr; + } else if (num == 4) { + data->accept_family = *(int *)ptr; + } + } else { + if (num == 2) { + data->bind_mode &= ~BIO_SOCK_NONBLOCK; + } + } + break; + case BIO_C_SET_NBIO: + if (num != 0) + data->accepted_mode |= BIO_SOCK_NONBLOCK; + else + data->accepted_mode &= ~BIO_SOCK_NONBLOCK; + break; + case BIO_C_SET_FD: + b->num = *((int *)ptr); + data->accept_sock = b->num; + data->state = ACPT_S_ACCEPT; + b->shutdown = (int)num; + b->init = 1; + break; + case BIO_C_GET_FD: + if (b->init) { + ip = (int *)ptr; + if (ip != NULL) + *ip = data->accept_sock; + ret = data->accept_sock; + } else + ret = -1; + break; + case BIO_C_GET_ACCEPT: + if (b->init) { + if (num == 0 && ptr != NULL) { + pp = (char **)ptr; + *pp = data->cache_accepting_name; + } else if (num == 1 && ptr != NULL) { + pp = (char **)ptr; + *pp = data->cache_accepting_serv; + } else if (num == 2 && ptr != NULL) { + pp = (char **)ptr; + *pp = data->cache_peer_name; + } else if (num == 3 && ptr != NULL) { + pp = (char **)ptr; + *pp = data->cache_peer_serv; + } else if (num == 4) { + switch (BIO_ADDRINFO_family(data->addr_iter)) { +#ifdef AF_INET6 + case AF_INET6: + ret = BIO_FAMILY_IPV6; + break; +#endif + case AF_INET: + ret = BIO_FAMILY_IPV4; + break; + case 0: + ret = data->accept_family; + break; + default: + ret = -1; + break; + } + } else + ret = -1; + } else + ret = -1; + break; + case BIO_CTRL_GET_CLOSE: + ret = b->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + b->shutdown = (int)num; + break; + case BIO_CTRL_PENDING: + case BIO_CTRL_WPENDING: + ret = 0; + break; + case BIO_CTRL_FLUSH: + break; + case BIO_C_SET_BIND_MODE: + data->bind_mode = (int)num; + break; + case BIO_C_GET_BIND_MODE: + ret = (long)data->bind_mode; + break; + case BIO_CTRL_DUP: + 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; -} - -static int acpt_puts(BIO *bp, const char *str) -{ - int n, ret; - - n = strlen(str); - ret = acpt_write(bp, str, n); - return ret; -} - -BIO *BIO_new_accept(const char *str) -{ - BIO *ret; - - ret = BIO_new(BIO_s_accept()); - if (ret == NULL) - return NULL; - if (BIO_set_accept_name(ret, str)) - return ret; - BIO_free(ret); - return NULL; -} - -#endif + default: + ret = 0; + break; + } + return ret; +} + +static int acpt_puts(BIO *bp, const char *str) +{ + int n, ret; + + n = strlen(str); + ret = acpt_write(bp, str, n); + return ret; +} + +BIO *BIO_new_accept(const char *str) +{ + BIO *ret; + + ret = BIO_new(BIO_s_accept()); + if (ret == NULL) + return NULL; + if (BIO_set_accept_name(ret, str)) + return ret; + BIO_free(ret); + return NULL; +} + +#endif diff --git a/contrib/libs/openssl/crypto/bio/bss_bio.c b/contrib/libs/openssl/crypto/bio/bss_bio.c index d0d00ab442..c97349e432 100644 --- a/contrib/libs/openssl/crypto/bio/bss_bio.c +++ b/contrib/libs/openssl/crypto/bio/bss_bio.c @@ -1,808 +1,808 @@ -/* - * Copyright 1999-2017 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 - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -/* - * Special method for a BIO where the other endpoint is also a BIO of this - * kind, handled by the same thread (i.e. the "peer" is actually ourselves, - * wearing a different hat). Such "BIO pairs" are mainly for using the SSL - * library with I/O interfaces for which no specific BIO method is available. - * See ssl/ssltest.c for some hints on how this can be used. - */ - -#include "e_os.h" -#include <assert.h> -#include <limits.h> -#include <stdlib.h> -#include <string.h> - +/* + * Copyright 1999-2017 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 + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Special method for a BIO where the other endpoint is also a BIO of this + * kind, handled by the same thread (i.e. the "peer" is actually ourselves, + * wearing a different hat). Such "BIO pairs" are mainly for using the SSL + * library with I/O interfaces for which no specific BIO method is available. + * See ssl/ssltest.c for some hints on how this can be used. + */ + +#include "e_os.h" +#include <assert.h> +#include <limits.h> +#include <stdlib.h> +#include <string.h> + #include "bio_local.h" -#include <openssl/err.h> -#include <openssl/crypto.h> - -static int bio_new(BIO *bio); -static int bio_free(BIO *bio); -static int bio_read(BIO *bio, char *buf, int size); -static int bio_write(BIO *bio, const char *buf, int num); -static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr); -static int bio_puts(BIO *bio, const char *str); - -static int bio_make_pair(BIO *bio1, BIO *bio2); -static void bio_destroy_pair(BIO *bio); - -static const BIO_METHOD methods_biop = { - BIO_TYPE_BIO, - "BIO pair", - /* TODO: Convert to new style write function */ - bwrite_conv, - bio_write, - /* TODO: Convert to new style read function */ - bread_conv, - bio_read, - bio_puts, - NULL /* no bio_gets */ , - bio_ctrl, - bio_new, - bio_free, - NULL /* no bio_callback_ctrl */ -}; - -const BIO_METHOD *BIO_s_bio(void) -{ - return &methods_biop; -} - -struct bio_bio_st { - BIO *peer; /* NULL if buf == NULL. If peer != NULL, then - * peer->ptr is also a bio_bio_st, and its - * "peer" member points back to us. peer != - * NULL iff init != 0 in the BIO. */ - /* This is for what we write (i.e. reading uses peer's struct): */ - int closed; /* valid iff peer != NULL */ - size_t len; /* valid iff buf != NULL; 0 if peer == NULL */ - size_t offset; /* valid iff buf != NULL; 0 if len == 0 */ - size_t size; - char *buf; /* "size" elements (if != NULL) */ - size_t request; /* valid iff peer != NULL; 0 if len != 0, - * otherwise set by peer to number of bytes - * it (unsuccessfully) tried to read, never - * more than buffer space (size-len) - * warrants. */ -}; - -static int bio_new(BIO *bio) -{ - struct bio_bio_st *b = OPENSSL_zalloc(sizeof(*b)); - - if (b == NULL) - return 0; - - /* enough for one TLS record (just a default) */ - b->size = 17 * 1024; - - bio->ptr = b; - return 1; -} - -static int bio_free(BIO *bio) -{ - struct bio_bio_st *b; - - if (bio == NULL) - return 0; - b = bio->ptr; - - assert(b != NULL); - - if (b->peer) - bio_destroy_pair(bio); - - OPENSSL_free(b->buf); - OPENSSL_free(b); - - return 1; -} - -static int bio_read(BIO *bio, char *buf, int size_) -{ - size_t size = size_; - size_t rest; - struct bio_bio_st *b, *peer_b; - - BIO_clear_retry_flags(bio); - - if (!bio->init) - return 0; - - b = bio->ptr; - assert(b != NULL); - assert(b->peer != NULL); - peer_b = b->peer->ptr; - assert(peer_b != NULL); - assert(peer_b->buf != NULL); - - peer_b->request = 0; /* will be set in "retry_read" situation */ - - if (buf == NULL || size == 0) - return 0; - - if (peer_b->len == 0) { - if (peer_b->closed) - return 0; /* writer has closed, and no data is left */ - else { - BIO_set_retry_read(bio); /* buffer is empty */ - if (size <= peer_b->size) - peer_b->request = size; - else - /* - * don't ask for more than the peer can deliver in one write - */ - peer_b->request = peer_b->size; - return -1; - } - } - - /* we can read */ - if (peer_b->len < size) - size = peer_b->len; - - /* now read "size" bytes */ - - rest = size; - - assert(rest > 0); - do { /* one or two iterations */ - size_t chunk; - - assert(rest <= peer_b->len); - if (peer_b->offset + rest <= peer_b->size) - chunk = rest; - else - /* wrap around ring buffer */ - chunk = peer_b->size - peer_b->offset; - assert(peer_b->offset + chunk <= peer_b->size); - - memcpy(buf, peer_b->buf + peer_b->offset, chunk); - - peer_b->len -= chunk; - if (peer_b->len) { - peer_b->offset += chunk; - assert(peer_b->offset <= peer_b->size); - if (peer_b->offset == peer_b->size) - peer_b->offset = 0; - buf += chunk; - } else { - /* buffer now empty, no need to advance "buf" */ - assert(chunk == rest); - peer_b->offset = 0; - } - rest -= chunk; - } - while (rest); - - return size; -} - -/*- - * non-copying interface: provide pointer to available data in buffer - * bio_nread0: return number of available bytes - * bio_nread: also advance index - * (example usage: bio_nread0(), read from buffer, bio_nread() - * or just bio_nread(), read from buffer) - */ -/* - * WARNING: The non-copying interface is largely untested as of yet and may - * contain bugs. - */ -static ossl_ssize_t bio_nread0(BIO *bio, char **buf) -{ - struct bio_bio_st *b, *peer_b; - ossl_ssize_t num; - - BIO_clear_retry_flags(bio); - - if (!bio->init) - return 0; - - b = bio->ptr; - assert(b != NULL); - assert(b->peer != NULL); - peer_b = b->peer->ptr; - assert(peer_b != NULL); - assert(peer_b->buf != NULL); - - peer_b->request = 0; - - if (peer_b->len == 0) { - char dummy; - - /* avoid code duplication -- nothing available for reading */ - return bio_read(bio, &dummy, 1); /* returns 0 or -1 */ - } - - num = peer_b->len; - if (peer_b->size < peer_b->offset + num) - /* no ring buffer wrap-around for non-copying interface */ - num = peer_b->size - peer_b->offset; - assert(num > 0); - - if (buf != NULL) - *buf = peer_b->buf + peer_b->offset; - return num; -} - -static ossl_ssize_t bio_nread(BIO *bio, char **buf, size_t num_) -{ - struct bio_bio_st *b, *peer_b; - ossl_ssize_t num, available; - - if (num_ > OSSL_SSIZE_MAX) - num = OSSL_SSIZE_MAX; - else - num = (ossl_ssize_t) num_; - - available = bio_nread0(bio, buf); - if (num > available) - num = available; - if (num <= 0) - return num; - - b = bio->ptr; - peer_b = b->peer->ptr; - - peer_b->len -= num; - if (peer_b->len) { - peer_b->offset += num; - assert(peer_b->offset <= peer_b->size); - if (peer_b->offset == peer_b->size) - peer_b->offset = 0; - } else - peer_b->offset = 0; - - return num; -} - -static int bio_write(BIO *bio, const char *buf, int num_) -{ - size_t num = num_; - size_t rest; - struct bio_bio_st *b; - - BIO_clear_retry_flags(bio); - - if (!bio->init || buf == NULL || num == 0) - return 0; - - b = bio->ptr; - assert(b != NULL); - assert(b->peer != NULL); - assert(b->buf != NULL); - - b->request = 0; - if (b->closed) { - /* we already closed */ - BIOerr(BIO_F_BIO_WRITE, BIO_R_BROKEN_PIPE); - return -1; - } - - assert(b->len <= b->size); - - if (b->len == b->size) { - BIO_set_retry_write(bio); /* buffer is full */ - return -1; - } - - /* we can write */ - if (num > b->size - b->len) - num = b->size - b->len; - - /* now write "num" bytes */ - - rest = num; - - assert(rest > 0); - do { /* one or two iterations */ - size_t write_offset; - size_t chunk; - - assert(b->len + rest <= b->size); - - write_offset = b->offset + b->len; - if (write_offset >= b->size) - write_offset -= b->size; - /* b->buf[write_offset] is the first byte we can write to. */ - - if (write_offset + rest <= b->size) - chunk = rest; - else - /* wrap around ring buffer */ - chunk = b->size - write_offset; - - memcpy(b->buf + write_offset, buf, chunk); - - b->len += chunk; - - assert(b->len <= b->size); - - rest -= chunk; - buf += chunk; - } - while (rest); - - return num; -} - -/*- - * non-copying interface: provide pointer to region to write to - * bio_nwrite0: check how much space is available - * bio_nwrite: also increase length - * (example usage: bio_nwrite0(), write to buffer, bio_nwrite() - * or just bio_nwrite(), write to buffer) - */ -static ossl_ssize_t bio_nwrite0(BIO *bio, char **buf) -{ - struct bio_bio_st *b; - size_t num; - size_t write_offset; - - BIO_clear_retry_flags(bio); - - if (!bio->init) - return 0; - - b = bio->ptr; - assert(b != NULL); - assert(b->peer != NULL); - assert(b->buf != NULL); - - b->request = 0; - if (b->closed) { - BIOerr(BIO_F_BIO_NWRITE0, BIO_R_BROKEN_PIPE); - return -1; - } - - assert(b->len <= b->size); - - if (b->len == b->size) { - BIO_set_retry_write(bio); - return -1; - } - - num = b->size - b->len; - write_offset = b->offset + b->len; - if (write_offset >= b->size) - write_offset -= b->size; - if (write_offset + num > b->size) - /* - * no ring buffer wrap-around for non-copying interface (to fulfil - * the promise by BIO_ctrl_get_write_guarantee, BIO_nwrite may have - * to be called twice) - */ - num = b->size - write_offset; - - if (buf != NULL) - *buf = b->buf + write_offset; - assert(write_offset + num <= b->size); - - return num; -} - -static ossl_ssize_t bio_nwrite(BIO *bio, char **buf, size_t num_) -{ - struct bio_bio_st *b; - ossl_ssize_t num, space; - - if (num_ > OSSL_SSIZE_MAX) - num = OSSL_SSIZE_MAX; - else - num = (ossl_ssize_t) num_; - - space = bio_nwrite0(bio, buf); - if (num > space) - num = space; - if (num <= 0) - return num; - b = bio->ptr; - assert(b != NULL); - b->len += num; - assert(b->len <= b->size); - - return num; -} - -static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr) -{ - long ret; - struct bio_bio_st *b = bio->ptr; - - assert(b != NULL); - - switch (cmd) { - /* specific CTRL codes */ - - case BIO_C_SET_WRITE_BUF_SIZE: - if (b->peer) { - BIOerr(BIO_F_BIO_CTRL, BIO_R_IN_USE); - ret = 0; - } else if (num == 0) { - BIOerr(BIO_F_BIO_CTRL, BIO_R_INVALID_ARGUMENT); - ret = 0; - } else { - size_t new_size = num; - - if (b->size != new_size) { - OPENSSL_free(b->buf); - b->buf = NULL; - b->size = new_size; - } - ret = 1; - } - break; - - case BIO_C_GET_WRITE_BUF_SIZE: - ret = (long)b->size; - break; - - case BIO_C_MAKE_BIO_PAIR: - { - BIO *other_bio = ptr; - - if (bio_make_pair(bio, other_bio)) - ret = 1; - else - ret = 0; - } - break; - - case BIO_C_DESTROY_BIO_PAIR: - /* - * Affects both BIOs in the pair -- call just once! Or let - * BIO_free(bio1); BIO_free(bio2); do the job. - */ - bio_destroy_pair(bio); - ret = 1; - break; - - case BIO_C_GET_WRITE_GUARANTEE: - /* - * How many bytes can the caller feed to the next write without - * having to keep any? - */ - if (b->peer == NULL || b->closed) - ret = 0; - else - ret = (long)b->size - b->len; - break; - - case BIO_C_GET_READ_REQUEST: - /* - * If the peer unsuccessfully tried to read, how many bytes were - * requested? (As with BIO_CTRL_PENDING, that number can usually be - * treated as boolean.) - */ - ret = (long)b->request; - break; - - case BIO_C_RESET_READ_REQUEST: - /* - * Reset request. (Can be useful after read attempts at the other - * side that are meant to be non-blocking, e.g. when probing SSL_read - * to see if any data is available.) - */ - b->request = 0; - ret = 1; - break; - - case BIO_C_SHUTDOWN_WR: - /* similar to shutdown(..., SHUT_WR) */ - b->closed = 1; - ret = 1; - break; - - case BIO_C_NREAD0: - /* prepare for non-copying read */ - ret = (long)bio_nread0(bio, ptr); - break; - - case BIO_C_NREAD: - /* non-copying read */ - ret = (long)bio_nread(bio, ptr, (size_t)num); - break; - - case BIO_C_NWRITE0: - /* prepare for non-copying write */ - ret = (long)bio_nwrite0(bio, ptr); - break; - - case BIO_C_NWRITE: - /* non-copying write */ - ret = (long)bio_nwrite(bio, ptr, (size_t)num); - break; - - /* standard CTRL codes follow */ - - case BIO_CTRL_RESET: - if (b->buf != NULL) { - b->len = 0; - b->offset = 0; - } - ret = 0; - break; - - case BIO_CTRL_GET_CLOSE: - ret = bio->shutdown; - break; - - case BIO_CTRL_SET_CLOSE: - bio->shutdown = (int)num; - ret = 1; - break; - - case BIO_CTRL_PENDING: - if (b->peer != NULL) { - struct bio_bio_st *peer_b = b->peer->ptr; - - ret = (long)peer_b->len; - } else - ret = 0; - break; - - case BIO_CTRL_WPENDING: - if (b->buf != NULL) - ret = (long)b->len; - else - ret = 0; - break; - - case BIO_CTRL_DUP: - /* See BIO_dup_chain for circumstances we have to expect. */ - { - BIO *other_bio = ptr; - struct bio_bio_st *other_b; - - assert(other_bio != NULL); - other_b = other_bio->ptr; - assert(other_b != NULL); - - assert(other_b->buf == NULL); /* other_bio is always fresh */ - - other_b->size = b->size; - } - - ret = 1; - break; - - case BIO_CTRL_FLUSH: - ret = 1; - break; - - case BIO_CTRL_EOF: - if (b->peer != NULL) { - struct bio_bio_st *peer_b = b->peer->ptr; - - if (peer_b->len == 0 && peer_b->closed) - ret = 1; - else - ret = 0; - } else { - ret = 1; - } - break; - - default: - ret = 0; - } - return ret; -} - -static int bio_puts(BIO *bio, const char *str) -{ - return bio_write(bio, str, strlen(str)); -} - -static int bio_make_pair(BIO *bio1, BIO *bio2) -{ - struct bio_bio_st *b1, *b2; - - assert(bio1 != NULL); - assert(bio2 != NULL); - - b1 = bio1->ptr; - b2 = bio2->ptr; - - if (b1->peer != NULL || b2->peer != NULL) { - BIOerr(BIO_F_BIO_MAKE_PAIR, BIO_R_IN_USE); - return 0; - } - - if (b1->buf == NULL) { - b1->buf = OPENSSL_malloc(b1->size); - if (b1->buf == NULL) { - BIOerr(BIO_F_BIO_MAKE_PAIR, ERR_R_MALLOC_FAILURE); - return 0; - } - b1->len = 0; - b1->offset = 0; - } - - if (b2->buf == NULL) { - b2->buf = OPENSSL_malloc(b2->size); - if (b2->buf == NULL) { - BIOerr(BIO_F_BIO_MAKE_PAIR, ERR_R_MALLOC_FAILURE); - return 0; - } - b2->len = 0; - b2->offset = 0; - } - - b1->peer = bio2; - b1->closed = 0; - b1->request = 0; - b2->peer = bio1; - b2->closed = 0; - b2->request = 0; - - bio1->init = 1; - bio2->init = 1; - - return 1; -} - -static void bio_destroy_pair(BIO *bio) -{ - struct bio_bio_st *b = bio->ptr; - - if (b != NULL) { - BIO *peer_bio = b->peer; - - if (peer_bio != NULL) { - struct bio_bio_st *peer_b = peer_bio->ptr; - - assert(peer_b != NULL); - assert(peer_b->peer == bio); - - peer_b->peer = NULL; - peer_bio->init = 0; - assert(peer_b->buf != NULL); - peer_b->len = 0; - peer_b->offset = 0; - - b->peer = NULL; - bio->init = 0; - assert(b->buf != NULL); - b->len = 0; - b->offset = 0; - } - } -} - -/* Exported convenience functions */ -int BIO_new_bio_pair(BIO **bio1_p, size_t writebuf1, - BIO **bio2_p, size_t writebuf2) -{ - BIO *bio1 = NULL, *bio2 = NULL; - long r; - int ret = 0; - - bio1 = BIO_new(BIO_s_bio()); - if (bio1 == NULL) - goto err; - bio2 = BIO_new(BIO_s_bio()); - if (bio2 == NULL) - goto err; - - if (writebuf1) { - r = BIO_set_write_buf_size(bio1, writebuf1); - if (!r) - goto err; - } - if (writebuf2) { - r = BIO_set_write_buf_size(bio2, writebuf2); - if (!r) - goto err; - } - - r = BIO_make_bio_pair(bio1, bio2); - if (!r) - goto err; - ret = 1; - - err: - if (ret == 0) { - BIO_free(bio1); - bio1 = NULL; - BIO_free(bio2); - bio2 = NULL; - } - - *bio1_p = bio1; - *bio2_p = bio2; - return ret; -} - -size_t BIO_ctrl_get_write_guarantee(BIO *bio) -{ - return BIO_ctrl(bio, BIO_C_GET_WRITE_GUARANTEE, 0, NULL); -} - -size_t BIO_ctrl_get_read_request(BIO *bio) -{ - return BIO_ctrl(bio, BIO_C_GET_READ_REQUEST, 0, NULL); -} - -int BIO_ctrl_reset_read_request(BIO *bio) -{ - return (BIO_ctrl(bio, BIO_C_RESET_READ_REQUEST, 0, NULL) != 0); -} - -/* - * BIO_nread0/nread/nwrite0/nwrite are available only for BIO pairs for now - * (conceivably some other BIOs could allow non-copying reads and writes - * too.) - */ -int BIO_nread0(BIO *bio, char **buf) -{ - long ret; - - if (!bio->init) { - BIOerr(BIO_F_BIO_NREAD0, BIO_R_UNINITIALIZED); - return -2; - } - - ret = BIO_ctrl(bio, BIO_C_NREAD0, 0, buf); - if (ret > INT_MAX) - return INT_MAX; - else - return (int)ret; -} - -int BIO_nread(BIO *bio, char **buf, int num) -{ - int ret; - - if (!bio->init) { - BIOerr(BIO_F_BIO_NREAD, BIO_R_UNINITIALIZED); - return -2; - } - - ret = (int)BIO_ctrl(bio, BIO_C_NREAD, num, buf); - if (ret > 0) - bio->num_read += ret; - return ret; -} - -int BIO_nwrite0(BIO *bio, char **buf) -{ - long ret; - - if (!bio->init) { - BIOerr(BIO_F_BIO_NWRITE0, BIO_R_UNINITIALIZED); - return -2; - } - - ret = BIO_ctrl(bio, BIO_C_NWRITE0, 0, buf); - if (ret > INT_MAX) - return INT_MAX; - else - return (int)ret; -} - -int BIO_nwrite(BIO *bio, char **buf, int num) -{ - int ret; - - if (!bio->init) { - BIOerr(BIO_F_BIO_NWRITE, BIO_R_UNINITIALIZED); - return -2; - } - - ret = BIO_ctrl(bio, BIO_C_NWRITE, num, buf); - if (ret > 0) - bio->num_write += ret; - return ret; -} +#include <openssl/err.h> +#include <openssl/crypto.h> + +static int bio_new(BIO *bio); +static int bio_free(BIO *bio); +static int bio_read(BIO *bio, char *buf, int size); +static int bio_write(BIO *bio, const char *buf, int num); +static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr); +static int bio_puts(BIO *bio, const char *str); + +static int bio_make_pair(BIO *bio1, BIO *bio2); +static void bio_destroy_pair(BIO *bio); + +static const BIO_METHOD methods_biop = { + BIO_TYPE_BIO, + "BIO pair", + /* TODO: Convert to new style write function */ + bwrite_conv, + bio_write, + /* TODO: Convert to new style read function */ + bread_conv, + bio_read, + bio_puts, + NULL /* no bio_gets */ , + bio_ctrl, + bio_new, + bio_free, + NULL /* no bio_callback_ctrl */ +}; + +const BIO_METHOD *BIO_s_bio(void) +{ + return &methods_biop; +} + +struct bio_bio_st { + BIO *peer; /* NULL if buf == NULL. If peer != NULL, then + * peer->ptr is also a bio_bio_st, and its + * "peer" member points back to us. peer != + * NULL iff init != 0 in the BIO. */ + /* This is for what we write (i.e. reading uses peer's struct): */ + int closed; /* valid iff peer != NULL */ + size_t len; /* valid iff buf != NULL; 0 if peer == NULL */ + size_t offset; /* valid iff buf != NULL; 0 if len == 0 */ + size_t size; + char *buf; /* "size" elements (if != NULL) */ + size_t request; /* valid iff peer != NULL; 0 if len != 0, + * otherwise set by peer to number of bytes + * it (unsuccessfully) tried to read, never + * more than buffer space (size-len) + * warrants. */ +}; + +static int bio_new(BIO *bio) +{ + struct bio_bio_st *b = OPENSSL_zalloc(sizeof(*b)); + + if (b == NULL) + return 0; + + /* enough for one TLS record (just a default) */ + b->size = 17 * 1024; + + bio->ptr = b; + return 1; +} + +static int bio_free(BIO *bio) +{ + struct bio_bio_st *b; + + if (bio == NULL) + return 0; + b = bio->ptr; + + assert(b != NULL); + + if (b->peer) + bio_destroy_pair(bio); + + OPENSSL_free(b->buf); + OPENSSL_free(b); + + return 1; +} + +static int bio_read(BIO *bio, char *buf, int size_) +{ + size_t size = size_; + size_t rest; + struct bio_bio_st *b, *peer_b; + + BIO_clear_retry_flags(bio); + + if (!bio->init) + return 0; + + b = bio->ptr; + assert(b != NULL); + assert(b->peer != NULL); + peer_b = b->peer->ptr; + assert(peer_b != NULL); + assert(peer_b->buf != NULL); + + peer_b->request = 0; /* will be set in "retry_read" situation */ + + if (buf == NULL || size == 0) + return 0; + + if (peer_b->len == 0) { + if (peer_b->closed) + return 0; /* writer has closed, and no data is left */ + else { + BIO_set_retry_read(bio); /* buffer is empty */ + if (size <= peer_b->size) + peer_b->request = size; + else + /* + * don't ask for more than the peer can deliver in one write + */ + peer_b->request = peer_b->size; + return -1; + } + } + + /* we can read */ + if (peer_b->len < size) + size = peer_b->len; + + /* now read "size" bytes */ + + rest = size; + + assert(rest > 0); + do { /* one or two iterations */ + size_t chunk; + + assert(rest <= peer_b->len); + if (peer_b->offset + rest <= peer_b->size) + chunk = rest; + else + /* wrap around ring buffer */ + chunk = peer_b->size - peer_b->offset; + assert(peer_b->offset + chunk <= peer_b->size); + + memcpy(buf, peer_b->buf + peer_b->offset, chunk); + + peer_b->len -= chunk; + if (peer_b->len) { + peer_b->offset += chunk; + assert(peer_b->offset <= peer_b->size); + if (peer_b->offset == peer_b->size) + peer_b->offset = 0; + buf += chunk; + } else { + /* buffer now empty, no need to advance "buf" */ + assert(chunk == rest); + peer_b->offset = 0; + } + rest -= chunk; + } + while (rest); + + return size; +} + +/*- + * non-copying interface: provide pointer to available data in buffer + * bio_nread0: return number of available bytes + * bio_nread: also advance index + * (example usage: bio_nread0(), read from buffer, bio_nread() + * or just bio_nread(), read from buffer) + */ +/* + * WARNING: The non-copying interface is largely untested as of yet and may + * contain bugs. + */ +static ossl_ssize_t bio_nread0(BIO *bio, char **buf) +{ + struct bio_bio_st *b, *peer_b; + ossl_ssize_t num; + + BIO_clear_retry_flags(bio); + + if (!bio->init) + return 0; + + b = bio->ptr; + assert(b != NULL); + assert(b->peer != NULL); + peer_b = b->peer->ptr; + assert(peer_b != NULL); + assert(peer_b->buf != NULL); + + peer_b->request = 0; + + if (peer_b->len == 0) { + char dummy; + + /* avoid code duplication -- nothing available for reading */ + return bio_read(bio, &dummy, 1); /* returns 0 or -1 */ + } + + num = peer_b->len; + if (peer_b->size < peer_b->offset + num) + /* no ring buffer wrap-around for non-copying interface */ + num = peer_b->size - peer_b->offset; + assert(num > 0); + + if (buf != NULL) + *buf = peer_b->buf + peer_b->offset; + return num; +} + +static ossl_ssize_t bio_nread(BIO *bio, char **buf, size_t num_) +{ + struct bio_bio_st *b, *peer_b; + ossl_ssize_t num, available; + + if (num_ > OSSL_SSIZE_MAX) + num = OSSL_SSIZE_MAX; + else + num = (ossl_ssize_t) num_; + + available = bio_nread0(bio, buf); + if (num > available) + num = available; + if (num <= 0) + return num; + + b = bio->ptr; + peer_b = b->peer->ptr; + + peer_b->len -= num; + if (peer_b->len) { + peer_b->offset += num; + assert(peer_b->offset <= peer_b->size); + if (peer_b->offset == peer_b->size) + peer_b->offset = 0; + } else + peer_b->offset = 0; + + return num; +} + +static int bio_write(BIO *bio, const char *buf, int num_) +{ + size_t num = num_; + size_t rest; + struct bio_bio_st *b; + + BIO_clear_retry_flags(bio); + + if (!bio->init || buf == NULL || num == 0) + return 0; + + b = bio->ptr; + assert(b != NULL); + assert(b->peer != NULL); + assert(b->buf != NULL); + + b->request = 0; + if (b->closed) { + /* we already closed */ + BIOerr(BIO_F_BIO_WRITE, BIO_R_BROKEN_PIPE); + return -1; + } + + assert(b->len <= b->size); + + if (b->len == b->size) { + BIO_set_retry_write(bio); /* buffer is full */ + return -1; + } + + /* we can write */ + if (num > b->size - b->len) + num = b->size - b->len; + + /* now write "num" bytes */ + + rest = num; + + assert(rest > 0); + do { /* one or two iterations */ + size_t write_offset; + size_t chunk; + + assert(b->len + rest <= b->size); + + write_offset = b->offset + b->len; + if (write_offset >= b->size) + write_offset -= b->size; + /* b->buf[write_offset] is the first byte we can write to. */ + + if (write_offset + rest <= b->size) + chunk = rest; + else + /* wrap around ring buffer */ + chunk = b->size - write_offset; + + memcpy(b->buf + write_offset, buf, chunk); + + b->len += chunk; + + assert(b->len <= b->size); + + rest -= chunk; + buf += chunk; + } + while (rest); + + return num; +} + +/*- + * non-copying interface: provide pointer to region to write to + * bio_nwrite0: check how much space is available + * bio_nwrite: also increase length + * (example usage: bio_nwrite0(), write to buffer, bio_nwrite() + * or just bio_nwrite(), write to buffer) + */ +static ossl_ssize_t bio_nwrite0(BIO *bio, char **buf) +{ + struct bio_bio_st *b; + size_t num; + size_t write_offset; + + BIO_clear_retry_flags(bio); + + if (!bio->init) + return 0; + + b = bio->ptr; + assert(b != NULL); + assert(b->peer != NULL); + assert(b->buf != NULL); + + b->request = 0; + if (b->closed) { + BIOerr(BIO_F_BIO_NWRITE0, BIO_R_BROKEN_PIPE); + return -1; + } + + assert(b->len <= b->size); + + if (b->len == b->size) { + BIO_set_retry_write(bio); + return -1; + } + + num = b->size - b->len; + write_offset = b->offset + b->len; + if (write_offset >= b->size) + write_offset -= b->size; + if (write_offset + num > b->size) + /* + * no ring buffer wrap-around for non-copying interface (to fulfil + * the promise by BIO_ctrl_get_write_guarantee, BIO_nwrite may have + * to be called twice) + */ + num = b->size - write_offset; + + if (buf != NULL) + *buf = b->buf + write_offset; + assert(write_offset + num <= b->size); + + return num; +} + +static ossl_ssize_t bio_nwrite(BIO *bio, char **buf, size_t num_) +{ + struct bio_bio_st *b; + ossl_ssize_t num, space; + + if (num_ > OSSL_SSIZE_MAX) + num = OSSL_SSIZE_MAX; + else + num = (ossl_ssize_t) num_; + + space = bio_nwrite0(bio, buf); + if (num > space) + num = space; + if (num <= 0) + return num; + b = bio->ptr; + assert(b != NULL); + b->len += num; + assert(b->len <= b->size); + + return num; +} + +static long bio_ctrl(BIO *bio, int cmd, long num, void *ptr) +{ + long ret; + struct bio_bio_st *b = bio->ptr; + + assert(b != NULL); + + switch (cmd) { + /* specific CTRL codes */ + + case BIO_C_SET_WRITE_BUF_SIZE: + if (b->peer) { + BIOerr(BIO_F_BIO_CTRL, BIO_R_IN_USE); + ret = 0; + } else if (num == 0) { + BIOerr(BIO_F_BIO_CTRL, BIO_R_INVALID_ARGUMENT); + ret = 0; + } else { + size_t new_size = num; + + if (b->size != new_size) { + OPENSSL_free(b->buf); + b->buf = NULL; + b->size = new_size; + } + ret = 1; + } + break; + + case BIO_C_GET_WRITE_BUF_SIZE: + ret = (long)b->size; + break; + + case BIO_C_MAKE_BIO_PAIR: + { + BIO *other_bio = ptr; + + if (bio_make_pair(bio, other_bio)) + ret = 1; + else + ret = 0; + } + break; + + case BIO_C_DESTROY_BIO_PAIR: + /* + * Affects both BIOs in the pair -- call just once! Or let + * BIO_free(bio1); BIO_free(bio2); do the job. + */ + bio_destroy_pair(bio); + ret = 1; + break; + + case BIO_C_GET_WRITE_GUARANTEE: + /* + * How many bytes can the caller feed to the next write without + * having to keep any? + */ + if (b->peer == NULL || b->closed) + ret = 0; + else + ret = (long)b->size - b->len; + break; + + case BIO_C_GET_READ_REQUEST: + /* + * If the peer unsuccessfully tried to read, how many bytes were + * requested? (As with BIO_CTRL_PENDING, that number can usually be + * treated as boolean.) + */ + ret = (long)b->request; + break; + + case BIO_C_RESET_READ_REQUEST: + /* + * Reset request. (Can be useful after read attempts at the other + * side that are meant to be non-blocking, e.g. when probing SSL_read + * to see if any data is available.) + */ + b->request = 0; + ret = 1; + break; + + case BIO_C_SHUTDOWN_WR: + /* similar to shutdown(..., SHUT_WR) */ + b->closed = 1; + ret = 1; + break; + + case BIO_C_NREAD0: + /* prepare for non-copying read */ + ret = (long)bio_nread0(bio, ptr); + break; + + case BIO_C_NREAD: + /* non-copying read */ + ret = (long)bio_nread(bio, ptr, (size_t)num); + break; + + case BIO_C_NWRITE0: + /* prepare for non-copying write */ + ret = (long)bio_nwrite0(bio, ptr); + break; + + case BIO_C_NWRITE: + /* non-copying write */ + ret = (long)bio_nwrite(bio, ptr, (size_t)num); + break; + + /* standard CTRL codes follow */ + + case BIO_CTRL_RESET: + if (b->buf != NULL) { + b->len = 0; + b->offset = 0; + } + ret = 0; + break; + + case BIO_CTRL_GET_CLOSE: + ret = bio->shutdown; + break; + + case BIO_CTRL_SET_CLOSE: + bio->shutdown = (int)num; + ret = 1; + break; + + case BIO_CTRL_PENDING: + if (b->peer != NULL) { + struct bio_bio_st *peer_b = b->peer->ptr; + + ret = (long)peer_b->len; + } else + ret = 0; + break; + + case BIO_CTRL_WPENDING: + if (b->buf != NULL) + ret = (long)b->len; + else + ret = 0; + break; + + case BIO_CTRL_DUP: + /* See BIO_dup_chain for circumstances we have to expect. */ + { + BIO *other_bio = ptr; + struct bio_bio_st *other_b; + + assert(other_bio != NULL); + other_b = other_bio->ptr; + assert(other_b != NULL); + + assert(other_b->buf == NULL); /* other_bio is always fresh */ + + other_b->size = b->size; + } + + ret = 1; + break; + + case BIO_CTRL_FLUSH: + ret = 1; + break; + + case BIO_CTRL_EOF: + if (b->peer != NULL) { + struct bio_bio_st *peer_b = b->peer->ptr; + + if (peer_b->len == 0 && peer_b->closed) + ret = 1; + else + ret = 0; + } else { + ret = 1; + } + break; + + default: + ret = 0; + } + return ret; +} + +static int bio_puts(BIO *bio, const char *str) +{ + return bio_write(bio, str, strlen(str)); +} + +static int bio_make_pair(BIO *bio1, BIO *bio2) +{ + struct bio_bio_st *b1, *b2; + + assert(bio1 != NULL); + assert(bio2 != NULL); + + b1 = bio1->ptr; + b2 = bio2->ptr; + + if (b1->peer != NULL || b2->peer != NULL) { + BIOerr(BIO_F_BIO_MAKE_PAIR, BIO_R_IN_USE); + return 0; + } + + if (b1->buf == NULL) { + b1->buf = OPENSSL_malloc(b1->size); + if (b1->buf == NULL) { + BIOerr(BIO_F_BIO_MAKE_PAIR, ERR_R_MALLOC_FAILURE); + return 0; + } + b1->len = 0; + b1->offset = 0; + } + + if (b2->buf == NULL) { + b2->buf = OPENSSL_malloc(b2->size); + if (b2->buf == NULL) { + BIOerr(BIO_F_BIO_MAKE_PAIR, ERR_R_MALLOC_FAILURE); + return 0; + } + b2->len = 0; + b2->offset = 0; + } + + b1->peer = bio2; + b1->closed = 0; + b1->request = 0; + b2->peer = bio1; + b2->closed = 0; + b2->request = 0; + + bio1->init = 1; + bio2->init = 1; + + return 1; +} + +static void bio_destroy_pair(BIO *bio) +{ + struct bio_bio_st *b = bio->ptr; + + if (b != NULL) { + BIO *peer_bio = b->peer; + + if (peer_bio != NULL) { + struct bio_bio_st *peer_b = peer_bio->ptr; + + assert(peer_b != NULL); + assert(peer_b->peer == bio); + + peer_b->peer = NULL; + peer_bio->init = 0; + assert(peer_b->buf != NULL); + peer_b->len = 0; + peer_b->offset = 0; + + b->peer = NULL; + bio->init = 0; + assert(b->buf != NULL); + b->len = 0; + b->offset = 0; + } + } +} + +/* Exported convenience functions */ +int BIO_new_bio_pair(BIO **bio1_p, size_t writebuf1, + BIO **bio2_p, size_t writebuf2) +{ + BIO *bio1 = NULL, *bio2 = NULL; + long r; + int ret = 0; + + bio1 = BIO_new(BIO_s_bio()); + if (bio1 == NULL) + goto err; + bio2 = BIO_new(BIO_s_bio()); + if (bio2 == NULL) + goto err; + + if (writebuf1) { + r = BIO_set_write_buf_size(bio1, writebuf1); + if (!r) + goto err; + } + if (writebuf2) { + r = BIO_set_write_buf_size(bio2, writebuf2); + if (!r) + goto err; + } + + r = BIO_make_bio_pair(bio1, bio2); + if (!r) + goto err; + ret = 1; + + err: + if (ret == 0) { + BIO_free(bio1); + bio1 = NULL; + BIO_free(bio2); + bio2 = NULL; + } + + *bio1_p = bio1; + *bio2_p = bio2; + return ret; +} + +size_t BIO_ctrl_get_write_guarantee(BIO *bio) +{ + return BIO_ctrl(bio, BIO_C_GET_WRITE_GUARANTEE, 0, NULL); +} + +size_t BIO_ctrl_get_read_request(BIO *bio) +{ + return BIO_ctrl(bio, BIO_C_GET_READ_REQUEST, 0, NULL); +} + +int BIO_ctrl_reset_read_request(BIO *bio) +{ + return (BIO_ctrl(bio, BIO_C_RESET_READ_REQUEST, 0, NULL) != 0); +} + +/* + * BIO_nread0/nread/nwrite0/nwrite are available only for BIO pairs for now + * (conceivably some other BIOs could allow non-copying reads and writes + * too.) + */ +int BIO_nread0(BIO *bio, char **buf) +{ + long ret; + + if (!bio->init) { + BIOerr(BIO_F_BIO_NREAD0, BIO_R_UNINITIALIZED); + return -2; + } + + ret = BIO_ctrl(bio, BIO_C_NREAD0, 0, buf); + if (ret > INT_MAX) + return INT_MAX; + else + return (int)ret; +} + +int BIO_nread(BIO *bio, char **buf, int num) +{ + int ret; + + if (!bio->init) { + BIOerr(BIO_F_BIO_NREAD, BIO_R_UNINITIALIZED); + return -2; + } + + ret = (int)BIO_ctrl(bio, BIO_C_NREAD, num, buf); + if (ret > 0) + bio->num_read += ret; + return ret; +} + +int BIO_nwrite0(BIO *bio, char **buf) +{ + long ret; + + if (!bio->init) { + BIOerr(BIO_F_BIO_NWRITE0, BIO_R_UNINITIALIZED); + return -2; + } + + ret = BIO_ctrl(bio, BIO_C_NWRITE0, 0, buf); + if (ret > INT_MAX) + return INT_MAX; + else + return (int)ret; +} + +int BIO_nwrite(BIO *bio, char **buf, int num) +{ + int ret; + + if (!bio->init) { + BIOerr(BIO_F_BIO_NWRITE, BIO_R_UNINITIALIZED); + return -2; + } + + ret = BIO_ctrl(bio, BIO_C_NWRITE, num, buf); + if (ret > 0) + bio->num_write += ret; + return ret; +} diff --git a/contrib/libs/openssl/crypto/bio/bss_conn.c b/contrib/libs/openssl/crypto/bio/bss_conn.c index 338aaff555..807a82b23b 100644 --- a/contrib/libs/openssl/crypto/bio/bss_conn.c +++ b/contrib/libs/openssl/crypto/bio/bss_conn.c @@ -1,193 +1,193 @@ -/* +/* * Copyright 1995-2020 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 - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -#include <stdio.h> -#include <errno.h> - + * + * Licensed under the OpenSSL license (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 <stdio.h> +#include <errno.h> + #include "bio_local.h" - -#ifndef OPENSSL_NO_SOCK - -typedef struct bio_connect_st { - int state; - int connect_family; - char *param_hostname; - char *param_service; - int connect_mode; - - BIO_ADDRINFO *addr_first; - const BIO_ADDRINFO *addr_iter; - /* - * int socket; this will be kept in bio->num so that it is compatible - * with the bss_sock bio - */ - /* - * called when the connection is initially made callback(BIO,state,ret); - * The callback should return 'ret'. state is for compatibility with the - * ssl info_callback - */ - BIO_info_cb *info_callback; -} BIO_CONNECT; - -static int conn_write(BIO *h, const char *buf, int num); -static int conn_read(BIO *h, char *buf, int size); -static int conn_puts(BIO *h, const char *str); -static long conn_ctrl(BIO *h, int cmd, long arg1, void *arg2); -static int conn_new(BIO *h); -static int conn_free(BIO *data); -static long conn_callback_ctrl(BIO *h, int cmd, BIO_info_cb *); - -static int conn_state(BIO *b, BIO_CONNECT *c); -static void conn_close_socket(BIO *data); -BIO_CONNECT *BIO_CONNECT_new(void); -void BIO_CONNECT_free(BIO_CONNECT *a); - -#define BIO_CONN_S_BEFORE 1 -#define BIO_CONN_S_GET_ADDR 2 -#define BIO_CONN_S_CREATE_SOCKET 3 -#define BIO_CONN_S_CONNECT 4 -#define BIO_CONN_S_OK 5 -#define BIO_CONN_S_BLOCKED_CONNECT 6 + +#ifndef OPENSSL_NO_SOCK + +typedef struct bio_connect_st { + int state; + int connect_family; + char *param_hostname; + char *param_service; + int connect_mode; + + BIO_ADDRINFO *addr_first; + const BIO_ADDRINFO *addr_iter; + /* + * int socket; this will be kept in bio->num so that it is compatible + * with the bss_sock bio + */ + /* + * called when the connection is initially made callback(BIO,state,ret); + * The callback should return 'ret'. state is for compatibility with the + * ssl info_callback + */ + BIO_info_cb *info_callback; +} BIO_CONNECT; + +static int conn_write(BIO *h, const char *buf, int num); +static int conn_read(BIO *h, char *buf, int size); +static int conn_puts(BIO *h, const char *str); +static long conn_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int conn_new(BIO *h); +static int conn_free(BIO *data); +static long conn_callback_ctrl(BIO *h, int cmd, BIO_info_cb *); + +static int conn_state(BIO *b, BIO_CONNECT *c); +static void conn_close_socket(BIO *data); +BIO_CONNECT *BIO_CONNECT_new(void); +void BIO_CONNECT_free(BIO_CONNECT *a); + +#define BIO_CONN_S_BEFORE 1 +#define BIO_CONN_S_GET_ADDR 2 +#define BIO_CONN_S_CREATE_SOCKET 3 +#define BIO_CONN_S_CONNECT 4 +#define BIO_CONN_S_OK 5 +#define BIO_CONN_S_BLOCKED_CONNECT 6 #define BIO_CONN_S_CONNECT_ERROR 7 - -static const BIO_METHOD methods_connectp = { - BIO_TYPE_CONNECT, - "socket connect", - /* TODO: Convert to new style write function */ - bwrite_conv, - conn_write, - /* TODO: Convert to new style read function */ - bread_conv, - conn_read, - conn_puts, - NULL, /* conn_gets, */ - conn_ctrl, - conn_new, - conn_free, - conn_callback_ctrl, -}; - -static int conn_state(BIO *b, BIO_CONNECT *c) -{ - int ret = -1, i; - BIO_info_cb *cb = NULL; - - if (c->info_callback != NULL) - cb = c->info_callback; - - for (;;) { - switch (c->state) { - case BIO_CONN_S_BEFORE: - if (c->param_hostname == NULL && c->param_service == NULL) { - BIOerr(BIO_F_CONN_STATE, BIO_R_NO_HOSTNAME_OR_SERVICE_SPECIFIED); - ERR_add_error_data(4, - "hostname=", c->param_hostname, - " service=", c->param_service); - goto exit_loop; - } - c->state = BIO_CONN_S_GET_ADDR; - break; - - case BIO_CONN_S_GET_ADDR: - { - int family = AF_UNSPEC; - switch (c->connect_family) { - case BIO_FAMILY_IPV6: - if (1) { /* This is a trick we use to avoid bit rot. - * at least the "else" part will always be - * compiled. - */ -#ifdef AF_INET6 - family = AF_INET6; - } else { -#endif - BIOerr(BIO_F_CONN_STATE, BIO_R_UNAVAILABLE_IP_FAMILY); - goto exit_loop; - } - break; - case BIO_FAMILY_IPV4: - family = AF_INET; - break; - case BIO_FAMILY_IPANY: - family = AF_UNSPEC; - break; - default: - BIOerr(BIO_F_CONN_STATE, BIO_R_UNSUPPORTED_IP_FAMILY); - goto exit_loop; - } - if (BIO_lookup(c->param_hostname, c->param_service, - BIO_LOOKUP_CLIENT, - family, SOCK_STREAM, &c->addr_first) == 0) - goto exit_loop; - } - if (c->addr_first == NULL) { - BIOerr(BIO_F_CONN_STATE, BIO_R_LOOKUP_RETURNED_NOTHING); - goto exit_loop; - } - c->addr_iter = c->addr_first; - c->state = BIO_CONN_S_CREATE_SOCKET; - break; - - case BIO_CONN_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_hostname, - " service=", c->param_service); - BIOerr(BIO_F_CONN_STATE, BIO_R_UNABLE_TO_CREATE_SOCKET); - goto exit_loop; - } - b->num = ret; - c->state = BIO_CONN_S_CONNECT; - break; - - case BIO_CONN_S_CONNECT: - BIO_clear_retry_flags(b); - ret = BIO_connect(b->num, BIO_ADDRINFO_address(c->addr_iter), - BIO_SOCK_KEEPALIVE | c->connect_mode); - b->retry_reason = 0; - if (ret == 0) { - if (BIO_sock_should_retry(ret)) { - BIO_set_retry_special(b); - c->state = BIO_CONN_S_BLOCKED_CONNECT; - b->retry_reason = BIO_RR_CONNECT; - ERR_clear_error(); - } else if ((c->addr_iter = BIO_ADDRINFO_next(c->addr_iter)) - != NULL) { - /* - * if there are more addresses to try, do that first - */ - BIO_closesocket(b->num); - c->state = BIO_CONN_S_CREATE_SOCKET; - ERR_clear_error(); - break; - } else { - SYSerr(SYS_F_CONNECT, get_last_socket_error()); - ERR_add_error_data(4, - "hostname=", c->param_hostname, - " service=", c->param_service); + +static const BIO_METHOD methods_connectp = { + BIO_TYPE_CONNECT, + "socket connect", + /* TODO: Convert to new style write function */ + bwrite_conv, + conn_write, + /* TODO: Convert to new style read function */ + bread_conv, + conn_read, + conn_puts, + NULL, /* conn_gets, */ + conn_ctrl, + conn_new, + conn_free, + conn_callback_ctrl, +}; + +static int conn_state(BIO *b, BIO_CONNECT *c) +{ + int ret = -1, i; + BIO_info_cb *cb = NULL; + + if (c->info_callback != NULL) + cb = c->info_callback; + + for (;;) { + switch (c->state) { + case BIO_CONN_S_BEFORE: + if (c->param_hostname == NULL && c->param_service == NULL) { + BIOerr(BIO_F_CONN_STATE, BIO_R_NO_HOSTNAME_OR_SERVICE_SPECIFIED); + ERR_add_error_data(4, + "hostname=", c->param_hostname, + " service=", c->param_service); + goto exit_loop; + } + c->state = BIO_CONN_S_GET_ADDR; + break; + + case BIO_CONN_S_GET_ADDR: + { + int family = AF_UNSPEC; + switch (c->connect_family) { + case BIO_FAMILY_IPV6: + if (1) { /* This is a trick we use to avoid bit rot. + * at least the "else" part will always be + * compiled. + */ +#ifdef AF_INET6 + family = AF_INET6; + } else { +#endif + BIOerr(BIO_F_CONN_STATE, BIO_R_UNAVAILABLE_IP_FAMILY); + goto exit_loop; + } + break; + case BIO_FAMILY_IPV4: + family = AF_INET; + break; + case BIO_FAMILY_IPANY: + family = AF_UNSPEC; + break; + default: + BIOerr(BIO_F_CONN_STATE, BIO_R_UNSUPPORTED_IP_FAMILY); + goto exit_loop; + } + if (BIO_lookup(c->param_hostname, c->param_service, + BIO_LOOKUP_CLIENT, + family, SOCK_STREAM, &c->addr_first) == 0) + goto exit_loop; + } + if (c->addr_first == NULL) { + BIOerr(BIO_F_CONN_STATE, BIO_R_LOOKUP_RETURNED_NOTHING); + goto exit_loop; + } + c->addr_iter = c->addr_first; + c->state = BIO_CONN_S_CREATE_SOCKET; + break; + + case BIO_CONN_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_hostname, + " service=", c->param_service); + BIOerr(BIO_F_CONN_STATE, BIO_R_UNABLE_TO_CREATE_SOCKET); + goto exit_loop; + } + b->num = ret; + c->state = BIO_CONN_S_CONNECT; + break; + + case BIO_CONN_S_CONNECT: + BIO_clear_retry_flags(b); + ret = BIO_connect(b->num, BIO_ADDRINFO_address(c->addr_iter), + BIO_SOCK_KEEPALIVE | c->connect_mode); + b->retry_reason = 0; + if (ret == 0) { + if (BIO_sock_should_retry(ret)) { + BIO_set_retry_special(b); + c->state = BIO_CONN_S_BLOCKED_CONNECT; + b->retry_reason = BIO_RR_CONNECT; + ERR_clear_error(); + } else if ((c->addr_iter = BIO_ADDRINFO_next(c->addr_iter)) + != NULL) { + /* + * if there are more addresses to try, do that first + */ + BIO_closesocket(b->num); + c->state = BIO_CONN_S_CREATE_SOCKET; + ERR_clear_error(); + break; + } else { + SYSerr(SYS_F_CONNECT, get_last_socket_error()); + ERR_add_error_data(4, + "hostname=", c->param_hostname, + " service=", c->param_service); c->state = BIO_CONN_S_CONNECT_ERROR; break; - } - goto exit_loop; - } else { - c->state = BIO_CONN_S_OK; - } - break; - - case BIO_CONN_S_BLOCKED_CONNECT: - i = BIO_sock_error(b->num); + } + goto exit_loop; + } else { + c->state = BIO_CONN_S_OK; + } + break; + + case BIO_CONN_S_BLOCKED_CONNECT: + i = BIO_sock_error(b->num); if (i != 0) { - BIO_clear_retry_flags(b); + BIO_clear_retry_flags(b); if ((c->addr_iter = BIO_ADDRINFO_next(c->addr_iter)) != NULL) { /* * if there are more addresses to try, do that first @@ -197,376 +197,376 @@ static int conn_state(BIO *b, BIO_CONNECT *c) ERR_clear_error(); break; } - SYSerr(SYS_F_CONNECT, i); - ERR_add_error_data(4, - "hostname=", c->param_hostname, - " service=", c->param_service); - BIOerr(BIO_F_CONN_STATE, BIO_R_NBIO_CONNECT_ERROR); - ret = 0; - goto exit_loop; - } else - c->state = BIO_CONN_S_OK; - break; - + SYSerr(SYS_F_CONNECT, i); + ERR_add_error_data(4, + "hostname=", c->param_hostname, + " service=", c->param_service); + BIOerr(BIO_F_CONN_STATE, BIO_R_NBIO_CONNECT_ERROR); + ret = 0; + goto exit_loop; + } else + c->state = BIO_CONN_S_OK; + break; + case BIO_CONN_S_CONNECT_ERROR: BIOerr(BIO_F_CONN_STATE, BIO_R_CONNECT_ERROR); ret = 0; goto exit_loop; - case BIO_CONN_S_OK: - ret = 1; - goto exit_loop; - default: - /* abort(); */ - goto exit_loop; - } - - if (cb != NULL) { - if ((ret = cb((BIO *)b, c->state, ret)) == 0) - goto end; - } - } - - /* Loop does not exit */ - exit_loop: - if (cb != NULL) - ret = cb((BIO *)b, c->state, ret); - end: - return ret; -} - -BIO_CONNECT *BIO_CONNECT_new(void) -{ - BIO_CONNECT *ret; - - if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL) { - BIOerr(BIO_F_BIO_CONNECT_NEW, ERR_R_MALLOC_FAILURE); - return NULL; - } - ret->state = BIO_CONN_S_BEFORE; - ret->connect_family = BIO_FAMILY_IPANY; - return ret; -} - -void BIO_CONNECT_free(BIO_CONNECT *a) -{ - if (a == NULL) - return; - OPENSSL_free(a->param_hostname); - OPENSSL_free(a->param_service); - BIO_ADDRINFO_free(a->addr_first); - OPENSSL_free(a); -} - -const BIO_METHOD *BIO_s_connect(void) -{ - return &methods_connectp; -} - -static int conn_new(BIO *bi) -{ - bi->init = 0; - bi->num = (int)INVALID_SOCKET; - bi->flags = 0; - if ((bi->ptr = (char *)BIO_CONNECT_new()) == NULL) - return 0; - else - return 1; -} - -static void conn_close_socket(BIO *bio) -{ - BIO_CONNECT *c; - - c = (BIO_CONNECT *)bio->ptr; - if (bio->num != (int)INVALID_SOCKET) { - /* Only do a shutdown if things were established */ - if (c->state == BIO_CONN_S_OK) - shutdown(bio->num, 2); - BIO_closesocket(bio->num); - bio->num = (int)INVALID_SOCKET; - } -} - -static int conn_free(BIO *a) -{ - BIO_CONNECT *data; - - if (a == NULL) - return 0; - data = (BIO_CONNECT *)a->ptr; - - if (a->shutdown) { - conn_close_socket(a); - BIO_CONNECT_free(data); - a->ptr = NULL; - a->flags = 0; - a->init = 0; - } - return 1; -} - -static int conn_read(BIO *b, char *out, int outl) -{ - int ret = 0; - BIO_CONNECT *data; - - data = (BIO_CONNECT *)b->ptr; - if (data->state != BIO_CONN_S_OK) { - ret = conn_state(b, data); - if (ret <= 0) - return ret; - } - - if (out != NULL) { - clear_socket_error(); - ret = readsocket(b->num, out, outl); - BIO_clear_retry_flags(b); - if (ret <= 0) { - if (BIO_sock_should_retry(ret)) - BIO_set_retry_read(b); + case BIO_CONN_S_OK: + ret = 1; + goto exit_loop; + default: + /* abort(); */ + goto exit_loop; + } + + if (cb != NULL) { + if ((ret = cb((BIO *)b, c->state, ret)) == 0) + goto end; + } + } + + /* Loop does not exit */ + exit_loop: + if (cb != NULL) + ret = cb((BIO *)b, c->state, ret); + end: + return ret; +} + +BIO_CONNECT *BIO_CONNECT_new(void) +{ + BIO_CONNECT *ret; + + if ((ret = OPENSSL_zalloc(sizeof(*ret))) == NULL) { + BIOerr(BIO_F_BIO_CONNECT_NEW, ERR_R_MALLOC_FAILURE); + return NULL; + } + ret->state = BIO_CONN_S_BEFORE; + ret->connect_family = BIO_FAMILY_IPANY; + return ret; +} + +void BIO_CONNECT_free(BIO_CONNECT *a) +{ + if (a == NULL) + return; + OPENSSL_free(a->param_hostname); + OPENSSL_free(a->param_service); + BIO_ADDRINFO_free(a->addr_first); + OPENSSL_free(a); +} + +const BIO_METHOD *BIO_s_connect(void) +{ + return &methods_connectp; +} + +static int conn_new(BIO *bi) +{ + bi->init = 0; + bi->num = (int)INVALID_SOCKET; + bi->flags = 0; + if ((bi->ptr = (char *)BIO_CONNECT_new()) == NULL) + return 0; + else + return 1; +} + +static void conn_close_socket(BIO *bio) +{ + BIO_CONNECT *c; + + c = (BIO_CONNECT *)bio->ptr; + if (bio->num != (int)INVALID_SOCKET) { + /* Only do a shutdown if things were established */ + if (c->state == BIO_CONN_S_OK) + shutdown(bio->num, 2); + BIO_closesocket(bio->num); + bio->num = (int)INVALID_SOCKET; + } +} + +static int conn_free(BIO *a) +{ + BIO_CONNECT *data; + + if (a == NULL) + return 0; + data = (BIO_CONNECT *)a->ptr; + + if (a->shutdown) { + conn_close_socket(a); + BIO_CONNECT_free(data); + a->ptr = NULL; + a->flags = 0; + a->init = 0; + } + return 1; +} + +static int conn_read(BIO *b, char *out, int outl) +{ + int ret = 0; + BIO_CONNECT *data; + + data = (BIO_CONNECT *)b->ptr; + if (data->state != BIO_CONN_S_OK) { + ret = conn_state(b, data); + if (ret <= 0) + return ret; + } + + if (out != NULL) { + clear_socket_error(); + ret = readsocket(b->num, out, outl); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (BIO_sock_should_retry(ret)) + BIO_set_retry_read(b); else if (ret == 0) b->flags |= BIO_FLAGS_IN_EOF; - } - } - return ret; -} - -static int conn_write(BIO *b, const char *in, int inl) -{ - int ret; - BIO_CONNECT *data; - - data = (BIO_CONNECT *)b->ptr; - if (data->state != BIO_CONN_S_OK) { - ret = conn_state(b, data); - if (ret <= 0) - return ret; - } - - clear_socket_error(); - ret = writesocket(b->num, in, inl); - BIO_clear_retry_flags(b); - if (ret <= 0) { - if (BIO_sock_should_retry(ret)) - BIO_set_retry_write(b); - } - return ret; -} - -static long conn_ctrl(BIO *b, int cmd, long num, void *ptr) -{ - BIO *dbio; - int *ip; - const char **pptr = NULL; - long ret = 1; - BIO_CONNECT *data; - - data = (BIO_CONNECT *)b->ptr; - - switch (cmd) { - case BIO_CTRL_RESET: - ret = 0; - data->state = BIO_CONN_S_BEFORE; - conn_close_socket(b); - BIO_ADDRINFO_free(data->addr_first); - data->addr_first = NULL; - b->flags = 0; - break; - case BIO_C_DO_STATE_MACHINE: - /* use this one to start the connection */ - if (data->state != BIO_CONN_S_OK) - ret = (long)conn_state(b, data); - else - ret = 1; - break; - case BIO_C_GET_CONNECT: - if (ptr != NULL) { - pptr = (const char **)ptr; - if (num == 0) { - *pptr = data->param_hostname; - } else if (num == 1) { - *pptr = data->param_service; - } else if (num == 2) { - *pptr = (const char *)BIO_ADDRINFO_address(data->addr_iter); - } else if (num == 3) { - switch (BIO_ADDRINFO_family(data->addr_iter)) { -# ifdef AF_INET6 - case AF_INET6: - ret = BIO_FAMILY_IPV6; - break; -# endif - case AF_INET: - ret = BIO_FAMILY_IPV4; - break; - case 0: - ret = data->connect_family; - break; - default: - ret = -1; - break; - } - } else { - ret = 0; - } - } else { - ret = 0; - } - break; - case BIO_C_SET_CONNECT: - if (ptr != NULL) { - b->init = 1; + } + } + return ret; +} + +static int conn_write(BIO *b, const char *in, int inl) +{ + int ret; + BIO_CONNECT *data; + + data = (BIO_CONNECT *)b->ptr; + if (data->state != BIO_CONN_S_OK) { + ret = conn_state(b, data); + if (ret <= 0) + return ret; + } + + clear_socket_error(); + ret = writesocket(b->num, in, inl); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (BIO_sock_should_retry(ret)) + BIO_set_retry_write(b); + } + return ret; +} + +static long conn_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + BIO *dbio; + int *ip; + const char **pptr = NULL; + long ret = 1; + BIO_CONNECT *data; + + data = (BIO_CONNECT *)b->ptr; + + switch (cmd) { + case BIO_CTRL_RESET: + ret = 0; + data->state = BIO_CONN_S_BEFORE; + conn_close_socket(b); + BIO_ADDRINFO_free(data->addr_first); + data->addr_first = NULL; + b->flags = 0; + break; + case BIO_C_DO_STATE_MACHINE: + /* use this one to start the connection */ + if (data->state != BIO_CONN_S_OK) + ret = (long)conn_state(b, data); + else + ret = 1; + break; + case BIO_C_GET_CONNECT: + if (ptr != NULL) { + pptr = (const char **)ptr; + if (num == 0) { + *pptr = data->param_hostname; + } else if (num == 1) { + *pptr = data->param_service; + } else if (num == 2) { + *pptr = (const char *)BIO_ADDRINFO_address(data->addr_iter); + } else if (num == 3) { + switch (BIO_ADDRINFO_family(data->addr_iter)) { +# ifdef AF_INET6 + case AF_INET6: + ret = BIO_FAMILY_IPV6; + break; +# endif + case AF_INET: + ret = BIO_FAMILY_IPV4; + break; + case 0: + ret = data->connect_family; + break; + default: + ret = -1; + break; + } + } else { + ret = 0; + } + } else { + ret = 0; + } + break; + case BIO_C_SET_CONNECT: + if (ptr != NULL) { + b->init = 1; if (num == 0) { /* BIO_set_conn_hostname */ - char *hold_service = data->param_service; - /* We affect the hostname regardless. However, the input - * string might contain a host:service spec, so we must - * parse it, which might or might not affect the service - */ - - OPENSSL_free(data->param_hostname); - data->param_hostname = NULL; - ret = BIO_parse_hostserv(ptr, - &data->param_hostname, - &data->param_service, - BIO_PARSE_PRIO_HOST); - if (hold_service != data->param_service) - OPENSSL_free(hold_service); + char *hold_service = data->param_service; + /* We affect the hostname regardless. However, the input + * string might contain a host:service spec, so we must + * parse it, which might or might not affect the service + */ + + OPENSSL_free(data->param_hostname); + data->param_hostname = NULL; + ret = BIO_parse_hostserv(ptr, + &data->param_hostname, + &data->param_service, + BIO_PARSE_PRIO_HOST); + if (hold_service != data->param_service) + OPENSSL_free(hold_service); } else if (num == 1) { /* BIO_set_conn_port */ - OPENSSL_free(data->param_service); + OPENSSL_free(data->param_service); if ((data->param_service = OPENSSL_strdup(ptr)) == NULL) ret = 0; } else if (num == 2) { /* BIO_set_conn_address */ - const BIO_ADDR *addr = (const BIO_ADDR *)ptr; + const BIO_ADDR *addr = (const BIO_ADDR *)ptr; char *host = BIO_ADDR_hostname_string(addr, 1); char *service = BIO_ADDR_service_string(addr, 1); ret = host != NULL && service != NULL; - if (ret) { + if (ret) { OPENSSL_free(data->param_hostname); data->param_hostname = host; OPENSSL_free(data->param_service); data->param_service = service; - BIO_ADDRINFO_free(data->addr_first); - data->addr_first = NULL; - data->addr_iter = NULL; + BIO_ADDRINFO_free(data->addr_first); + data->addr_first = NULL; + data->addr_iter = NULL; } else { OPENSSL_free(host); OPENSSL_free(service); - } + } } else if (num == 3) { /* BIO_set_conn_ip_family */ - data->connect_family = *(int *)ptr; - } else { - ret = 0; - } - } - break; - case BIO_C_SET_NBIO: - if (num != 0) - data->connect_mode |= BIO_SOCK_NONBLOCK; - else - data->connect_mode &= ~BIO_SOCK_NONBLOCK; - break; - case BIO_C_SET_CONNECT_MODE: - data->connect_mode = (int)num; - break; - case BIO_C_GET_FD: - if (b->init) { - ip = (int *)ptr; - if (ip != NULL) - *ip = b->num; - ret = b->num; - } else - ret = -1; - break; - case BIO_CTRL_GET_CLOSE: - ret = b->shutdown; - break; - case BIO_CTRL_SET_CLOSE: - b->shutdown = (int)num; - break; - case BIO_CTRL_PENDING: - case BIO_CTRL_WPENDING: - ret = 0; - break; - case BIO_CTRL_FLUSH: - break; - case BIO_CTRL_DUP: - { - dbio = (BIO *)ptr; - if (data->param_hostname) - BIO_set_conn_hostname(dbio, data->param_hostname); - if (data->param_service) - BIO_set_conn_port(dbio, data->param_service); - BIO_set_conn_ip_family(dbio, data->connect_family); - BIO_set_conn_mode(dbio, data->connect_mode); - /* - * FIXME: the cast of the function seems unlikely to be a good - * idea - */ - (void)BIO_set_info_callback(dbio, data->info_callback); - } - break; - case BIO_CTRL_SET_CALLBACK: - ret = 0; /* use callback ctrl */ - break; - case BIO_CTRL_GET_CALLBACK: - { - BIO_info_cb **fptr; - - fptr = (BIO_info_cb **)ptr; - *fptr = data->info_callback; - } - break; + data->connect_family = *(int *)ptr; + } else { + ret = 0; + } + } + break; + case BIO_C_SET_NBIO: + if (num != 0) + data->connect_mode |= BIO_SOCK_NONBLOCK; + else + data->connect_mode &= ~BIO_SOCK_NONBLOCK; + break; + case BIO_C_SET_CONNECT_MODE: + data->connect_mode = (int)num; + break; + case BIO_C_GET_FD: + if (b->init) { + ip = (int *)ptr; + if (ip != NULL) + *ip = b->num; + ret = b->num; + } else + ret = -1; + break; + case BIO_CTRL_GET_CLOSE: + ret = b->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + b->shutdown = (int)num; + break; + case BIO_CTRL_PENDING: + case BIO_CTRL_WPENDING: + ret = 0; + break; + case BIO_CTRL_FLUSH: + break; + case BIO_CTRL_DUP: + { + dbio = (BIO *)ptr; + if (data->param_hostname) + BIO_set_conn_hostname(dbio, data->param_hostname); + if (data->param_service) + BIO_set_conn_port(dbio, data->param_service); + BIO_set_conn_ip_family(dbio, data->connect_family); + BIO_set_conn_mode(dbio, data->connect_mode); + /* + * FIXME: the cast of the function seems unlikely to be a good + * idea + */ + (void)BIO_set_info_callback(dbio, data->info_callback); + } + break; + case BIO_CTRL_SET_CALLBACK: + ret = 0; /* use callback ctrl */ + break; + case BIO_CTRL_GET_CALLBACK: + { + BIO_info_cb **fptr; + + fptr = (BIO_info_cb **)ptr; + *fptr = data->info_callback; + } + break; case BIO_CTRL_EOF: ret = (b->flags & BIO_FLAGS_IN_EOF) != 0 ? 1 : 0; break; - default: - ret = 0; - break; - } - return ret; -} - -static long conn_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) -{ - long ret = 1; - BIO_CONNECT *data; - - data = (BIO_CONNECT *)b->ptr; - - switch (cmd) { - case BIO_CTRL_SET_CALLBACK: - { - data->info_callback = fp; - } - break; - default: - ret = 0; - break; - } - return ret; -} - -static int conn_puts(BIO *bp, const char *str) -{ - int n, ret; - - n = strlen(str); - ret = conn_write(bp, str, n); - return ret; -} - -BIO *BIO_new_connect(const char *str) -{ - BIO *ret; - - ret = BIO_new(BIO_s_connect()); - if (ret == NULL) - return NULL; - if (BIO_set_conn_hostname(ret, str)) - return ret; - BIO_free(ret); - return NULL; -} - -#endif + default: + ret = 0; + break; + } + return ret; +} + +static long conn_callback_ctrl(BIO *b, int cmd, BIO_info_cb *fp) +{ + long ret = 1; + BIO_CONNECT *data; + + data = (BIO_CONNECT *)b->ptr; + + switch (cmd) { + case BIO_CTRL_SET_CALLBACK: + { + data->info_callback = fp; + } + break; + default: + ret = 0; + break; + } + return ret; +} + +static int conn_puts(BIO *bp, const char *str) +{ + int n, ret; + + n = strlen(str); + ret = conn_write(bp, str, n); + return ret; +} + +BIO *BIO_new_connect(const char *str) +{ + BIO *ret; + + ret = BIO_new(BIO_s_connect()); + if (ret == NULL) + return NULL; + if (BIO_set_conn_hostname(ret, str)) + return ret; + BIO_free(ret); + return NULL; +} + +#endif diff --git a/contrib/libs/openssl/crypto/bio/bss_dgram.c b/contrib/libs/openssl/crypto/bio/bss_dgram.c index 745766826d..942fd8b514 100644 --- a/contrib/libs/openssl/crypto/bio/bss_dgram.c +++ b/contrib/libs/openssl/crypto/bio/bss_dgram.c @@ -1,1925 +1,1925 @@ -/* +/* * Copyright 2005-2019 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 - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -#include <stdio.h> -#include <errno.h> - + * + * Licensed under the OpenSSL license (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 <stdio.h> +#include <errno.h> + #include "bio_local.h" -#ifndef OPENSSL_NO_DGRAM - -# ifndef OPENSSL_NO_SCTP -# include <netinet/sctp.h> -# include <fcntl.h> -# define OPENSSL_SCTP_DATA_CHUNK_TYPE 0x00 -# define OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE 0xc0 -# endif - -# if defined(OPENSSL_SYS_LINUX) && !defined(IP_MTU) -# define IP_MTU 14 /* linux is lame */ -# endif - -# if OPENSSL_USE_IPV6 && !defined(IPPROTO_IPV6) -# define IPPROTO_IPV6 41 /* windows is lame */ -# endif - -# if defined(__FreeBSD__) && defined(IN6_IS_ADDR_V4MAPPED) -/* Standard definition causes type-punning problems. */ -# undef IN6_IS_ADDR_V4MAPPED -# define s6_addr32 __u6_addr.__u6_addr32 -# define IN6_IS_ADDR_V4MAPPED(a) \ - (((a)->s6_addr32[0] == 0) && \ - ((a)->s6_addr32[1] == 0) && \ - ((a)->s6_addr32[2] == htonl(0x0000ffff))) -# endif - -static int dgram_write(BIO *h, const char *buf, int num); -static int dgram_read(BIO *h, char *buf, int size); -static int dgram_puts(BIO *h, const char *str); -static long dgram_ctrl(BIO *h, int cmd, long arg1, void *arg2); -static int dgram_new(BIO *h); -static int dgram_free(BIO *data); -static int dgram_clear(BIO *bio); - -# ifndef OPENSSL_NO_SCTP -static int dgram_sctp_write(BIO *h, const char *buf, int num); -static int dgram_sctp_read(BIO *h, char *buf, int size); -static int dgram_sctp_puts(BIO *h, const char *str); -static long dgram_sctp_ctrl(BIO *h, int cmd, long arg1, void *arg2); -static int dgram_sctp_new(BIO *h); -static int dgram_sctp_free(BIO *data); -# ifdef SCTP_AUTHENTICATION_EVENT -static void dgram_sctp_handle_auth_free_key_event(BIO *b, union sctp_notification - *snp); -# endif -# endif - -static int BIO_dgram_should_retry(int s); - -static void get_current_time(struct timeval *t); - -static const BIO_METHOD methods_dgramp = { - BIO_TYPE_DGRAM, - "datagram socket", - /* TODO: Convert to new style write function */ - bwrite_conv, - dgram_write, - /* TODO: Convert to new style read function */ - bread_conv, - dgram_read, - dgram_puts, - NULL, /* dgram_gets, */ - dgram_ctrl, - dgram_new, - dgram_free, - NULL, /* dgram_callback_ctrl */ -}; - -# ifndef OPENSSL_NO_SCTP -static const BIO_METHOD methods_dgramp_sctp = { - BIO_TYPE_DGRAM_SCTP, - "datagram sctp socket", - /* TODO: Convert to new style write function */ - bwrite_conv, - dgram_sctp_write, - /* TODO: Convert to new style write function */ - bread_conv, - dgram_sctp_read, - dgram_sctp_puts, - NULL, /* dgram_gets, */ - dgram_sctp_ctrl, - dgram_sctp_new, - dgram_sctp_free, - NULL, /* dgram_callback_ctrl */ -}; -# endif - -typedef struct bio_dgram_data_st { - BIO_ADDR peer; - unsigned int connected; - unsigned int _errno; - unsigned int mtu; - struct timeval next_timeout; - struct timeval socket_timeout; - unsigned int peekmode; -} bio_dgram_data; - -# ifndef OPENSSL_NO_SCTP -typedef struct bio_dgram_sctp_save_message_st { - BIO *bio; - char *data; - int length; -} bio_dgram_sctp_save_message; - -typedef struct bio_dgram_sctp_data_st { - BIO_ADDR peer; - unsigned int connected; - unsigned int _errno; - unsigned int mtu; - struct bio_dgram_sctp_sndinfo sndinfo; - struct bio_dgram_sctp_rcvinfo rcvinfo; - struct bio_dgram_sctp_prinfo prinfo; - void (*handle_notifications) (BIO *bio, void *context, void *buf); - void *notification_context; - int in_handshake; - int ccs_rcvd; - int ccs_sent; - int save_shutdown; - int peer_auth_tested; -} bio_dgram_sctp_data; -# endif - -const BIO_METHOD *BIO_s_datagram(void) -{ - return &methods_dgramp; -} - -BIO *BIO_new_dgram(int fd, int close_flag) -{ - BIO *ret; - - ret = BIO_new(BIO_s_datagram()); - if (ret == NULL) - return NULL; - BIO_set_fd(ret, fd, close_flag); - return ret; -} - -static int dgram_new(BIO *bi) -{ - bio_dgram_data *data = OPENSSL_zalloc(sizeof(*data)); - - if (data == NULL) - return 0; - bi->ptr = data; - return 1; -} - -static int dgram_free(BIO *a) -{ - bio_dgram_data *data; - - if (a == NULL) - return 0; - if (!dgram_clear(a)) - return 0; - - data = (bio_dgram_data *)a->ptr; - OPENSSL_free(data); - - return 1; -} - -static int dgram_clear(BIO *a) -{ - if (a == NULL) - return 0; - if (a->shutdown) { - if (a->init) { - BIO_closesocket(a->num); - } - a->init = 0; - a->flags = 0; - } - return 1; -} - -static void dgram_adjust_rcv_timeout(BIO *b) -{ -# if defined(SO_RCVTIMEO) - bio_dgram_data *data = (bio_dgram_data *)b->ptr; - union { - size_t s; - int i; - } sz = { - 0 - }; - - /* Is a timer active? */ - if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0) { - struct timeval timenow, timeleft; - - /* Read current socket timeout */ -# ifdef OPENSSL_SYS_WINDOWS - int timeout; - - sz.i = sizeof(timeout); - if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, - (void *)&timeout, &sz.i) < 0) { - perror("getsockopt"); - } else { - data->socket_timeout.tv_sec = timeout / 1000; - data->socket_timeout.tv_usec = (timeout % 1000) * 1000; - } -# else - sz.i = sizeof(data->socket_timeout); - if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, - &(data->socket_timeout), (void *)&sz) < 0) { - perror("getsockopt"); - } else if (sizeof(sz.s) != sizeof(sz.i) && sz.i == 0) - OPENSSL_assert(sz.s <= sizeof(data->socket_timeout)); -# endif - - /* Get current time */ - get_current_time(&timenow); - - /* Calculate time left until timer expires */ - memcpy(&timeleft, &(data->next_timeout), sizeof(struct timeval)); - if (timeleft.tv_usec < timenow.tv_usec) { - timeleft.tv_usec = 1000000 - timenow.tv_usec + timeleft.tv_usec; - timeleft.tv_sec--; - } else { - timeleft.tv_usec -= timenow.tv_usec; - } - if (timeleft.tv_sec < timenow.tv_sec) { - timeleft.tv_sec = 0; - timeleft.tv_usec = 1; - } else { - timeleft.tv_sec -= timenow.tv_sec; - } - - /* - * Adjust socket timeout if next handshake message timer will expire - * earlier. - */ - if ((data->socket_timeout.tv_sec == 0 - && data->socket_timeout.tv_usec == 0) - || (data->socket_timeout.tv_sec > timeleft.tv_sec) - || (data->socket_timeout.tv_sec == timeleft.tv_sec - && data->socket_timeout.tv_usec >= timeleft.tv_usec)) { -# ifdef OPENSSL_SYS_WINDOWS - timeout = timeleft.tv_sec * 1000 + timeleft.tv_usec / 1000; - if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, - (void *)&timeout, sizeof(timeout)) < 0) { - perror("setsockopt"); - } -# else - if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, &timeleft, - sizeof(struct timeval)) < 0) { - perror("setsockopt"); - } -# endif - } - } -# endif -} - -static void dgram_reset_rcv_timeout(BIO *b) -{ -# if defined(SO_RCVTIMEO) - bio_dgram_data *data = (bio_dgram_data *)b->ptr; - - /* Is a timer active? */ - if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0) { -# ifdef OPENSSL_SYS_WINDOWS - int timeout = data->socket_timeout.tv_sec * 1000 + - data->socket_timeout.tv_usec / 1000; - if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, - (void *)&timeout, sizeof(timeout)) < 0) { - perror("setsockopt"); - } -# else - if (setsockopt - (b->num, SOL_SOCKET, SO_RCVTIMEO, &(data->socket_timeout), - sizeof(struct timeval)) < 0) { - perror("setsockopt"); - } -# endif - } -# endif -} - -static int dgram_read(BIO *b, char *out, int outl) -{ - int ret = 0; - bio_dgram_data *data = (bio_dgram_data *)b->ptr; - int flags = 0; - - BIO_ADDR peer; - socklen_t len = sizeof(peer); - - if (out != NULL) { - clear_socket_error(); - memset(&peer, 0, sizeof(peer)); - dgram_adjust_rcv_timeout(b); - if (data->peekmode) - flags = MSG_PEEK; - ret = recvfrom(b->num, out, outl, flags, - BIO_ADDR_sockaddr_noconst(&peer), &len); - - if (!data->connected && ret >= 0) - BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, &peer); - - BIO_clear_retry_flags(b); - if (ret < 0) { - if (BIO_dgram_should_retry(ret)) { - BIO_set_retry_read(b); - data->_errno = get_last_socket_error(); - } - } - - dgram_reset_rcv_timeout(b); - } - return ret; -} - -static int dgram_write(BIO *b, const char *in, int inl) -{ - int ret; - bio_dgram_data *data = (bio_dgram_data *)b->ptr; - clear_socket_error(); - - if (data->connected) - ret = writesocket(b->num, in, inl); - else { - int peerlen = BIO_ADDR_sockaddr_size(&data->peer); - - ret = sendto(b->num, in, inl, 0, - BIO_ADDR_sockaddr(&data->peer), peerlen); - } - - BIO_clear_retry_flags(b); - if (ret <= 0) { - if (BIO_dgram_should_retry(ret)) { - BIO_set_retry_write(b); - data->_errno = get_last_socket_error(); - } - } - return ret; -} - -static long dgram_get_mtu_overhead(bio_dgram_data *data) -{ - long ret; - - switch (BIO_ADDR_family(&data->peer)) { - case AF_INET: - /* - * Assume this is UDP - 20 bytes for IP, 8 bytes for UDP - */ - ret = 28; - break; -# if OPENSSL_USE_IPV6 - case AF_INET6: - { -# ifdef IN6_IS_ADDR_V4MAPPED - struct in6_addr tmp_addr; - if (BIO_ADDR_rawaddress(&data->peer, &tmp_addr, NULL) - && IN6_IS_ADDR_V4MAPPED(&tmp_addr)) - /* - * Assume this is UDP - 20 bytes for IP, 8 bytes for UDP - */ - ret = 28; - else -# endif - /* - * Assume this is UDP - 40 bytes for IP, 8 bytes for UDP - */ - ret = 48; - } - break; -# endif - default: - /* We don't know. Go with the historical default */ - ret = 28; - break; - } - return ret; -} - -static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr) -{ - long ret = 1; - int *ip; - bio_dgram_data *data = NULL; - int sockopt_val = 0; - int d_errno; -# if defined(OPENSSL_SYS_LINUX) && (defined(IP_MTU_DISCOVER) || defined(IP_MTU)) - socklen_t sockopt_len; /* assume that system supporting IP_MTU is - * modern enough to define socklen_t */ - socklen_t addr_len; - BIO_ADDR addr; -# endif - - data = (bio_dgram_data *)b->ptr; - - switch (cmd) { - case BIO_CTRL_RESET: - num = 0; - ret = 0; - break; - case BIO_CTRL_INFO: - ret = 0; - break; - case BIO_C_SET_FD: - dgram_clear(b); - b->num = *((int *)ptr); - b->shutdown = (int)num; - b->init = 1; - break; - case BIO_C_GET_FD: - if (b->init) { - ip = (int *)ptr; - if (ip != NULL) - *ip = b->num; - ret = b->num; - } else - ret = -1; - break; - case BIO_CTRL_GET_CLOSE: - ret = b->shutdown; - break; - case BIO_CTRL_SET_CLOSE: - b->shutdown = (int)num; - break; - case BIO_CTRL_PENDING: - case BIO_CTRL_WPENDING: - ret = 0; - break; - case BIO_CTRL_DUP: - case BIO_CTRL_FLUSH: - ret = 1; - break; - case BIO_CTRL_DGRAM_CONNECT: - BIO_ADDR_make(&data->peer, BIO_ADDR_sockaddr((BIO_ADDR *)ptr)); - break; - /* (Linux)kernel sets DF bit on outgoing IP packets */ - case BIO_CTRL_DGRAM_MTU_DISCOVER: -# if defined(OPENSSL_SYS_LINUX) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO) - addr_len = (socklen_t) sizeof(addr); - memset(&addr, 0, sizeof(addr)); - if (getsockname(b->num, &addr.sa, &addr_len) < 0) { - ret = 0; - break; - } - switch (addr.sa.sa_family) { - case AF_INET: - sockopt_val = IP_PMTUDISC_DO; - if ((ret = setsockopt(b->num, IPPROTO_IP, IP_MTU_DISCOVER, - &sockopt_val, sizeof(sockopt_val))) < 0) - perror("setsockopt"); - break; -# if OPENSSL_USE_IPV6 && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO) - case AF_INET6: - sockopt_val = IPV6_PMTUDISC_DO; - if ((ret = setsockopt(b->num, IPPROTO_IPV6, IPV6_MTU_DISCOVER, - &sockopt_val, sizeof(sockopt_val))) < 0) - perror("setsockopt"); - break; -# endif - default: - ret = -1; - break; - } -# else - ret = -1; -# endif - break; - case BIO_CTRL_DGRAM_QUERY_MTU: -# if defined(OPENSSL_SYS_LINUX) && defined(IP_MTU) - addr_len = (socklen_t) sizeof(addr); - memset(&addr, 0, sizeof(addr)); - if (getsockname(b->num, &addr.sa, &addr_len) < 0) { - ret = 0; - break; - } - sockopt_len = sizeof(sockopt_val); - switch (addr.sa.sa_family) { - case AF_INET: - if ((ret = - getsockopt(b->num, IPPROTO_IP, IP_MTU, (void *)&sockopt_val, - &sockopt_len)) < 0 || sockopt_val < 0) { - ret = 0; - } else { - /* - * we assume that the transport protocol is UDP and no IP - * options are used. - */ - data->mtu = sockopt_val - 8 - 20; - ret = data->mtu; - } - break; -# if OPENSSL_USE_IPV6 && defined(IPV6_MTU) - case AF_INET6: - if ((ret = - getsockopt(b->num, IPPROTO_IPV6, IPV6_MTU, - (void *)&sockopt_val, &sockopt_len)) < 0 - || sockopt_val < 0) { - ret = 0; - } else { - /* - * we assume that the transport protocol is UDP and no IPV6 - * options are used. - */ - data->mtu = sockopt_val - 8 - 40; - ret = data->mtu; - } - break; -# endif - default: - ret = 0; - break; - } -# else - ret = 0; -# endif - break; - case BIO_CTRL_DGRAM_GET_FALLBACK_MTU: - ret = -dgram_get_mtu_overhead(data); - switch (BIO_ADDR_family(&data->peer)) { - case AF_INET: - ret += 576; - break; -# if OPENSSL_USE_IPV6 - case AF_INET6: - { -# ifdef IN6_IS_ADDR_V4MAPPED - struct in6_addr tmp_addr; - if (BIO_ADDR_rawaddress(&data->peer, &tmp_addr, NULL) - && IN6_IS_ADDR_V4MAPPED(&tmp_addr)) - ret += 576; - else -# endif - ret += 1280; - } - break; -# endif - default: - ret += 576; - break; - } - break; - case BIO_CTRL_DGRAM_GET_MTU: - return data->mtu; - case BIO_CTRL_DGRAM_SET_MTU: - data->mtu = num; - ret = num; - break; - case BIO_CTRL_DGRAM_SET_CONNECTED: - if (ptr != NULL) { - data->connected = 1; - BIO_ADDR_make(&data->peer, BIO_ADDR_sockaddr((BIO_ADDR *)ptr)); - } else { - data->connected = 0; - memset(&data->peer, 0, sizeof(data->peer)); - } - break; - case BIO_CTRL_DGRAM_GET_PEER: - ret = BIO_ADDR_sockaddr_size(&data->peer); - /* FIXME: if num < ret, we will only return part of an address. - That should bee an error, no? */ - if (num == 0 || num > ret) - num = ret; - memcpy(ptr, &data->peer, (ret = num)); - break; - case BIO_CTRL_DGRAM_SET_PEER: - BIO_ADDR_make(&data->peer, BIO_ADDR_sockaddr((BIO_ADDR *)ptr)); - break; - case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT: - memcpy(&(data->next_timeout), ptr, sizeof(struct timeval)); - break; -# if defined(SO_RCVTIMEO) - case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT: -# ifdef OPENSSL_SYS_WINDOWS - { - struct timeval *tv = (struct timeval *)ptr; - int timeout = tv->tv_sec * 1000 + tv->tv_usec / 1000; - if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, - (void *)&timeout, sizeof(timeout)) < 0) { - perror("setsockopt"); - ret = -1; - } - } -# else - if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, ptr, - sizeof(struct timeval)) < 0) { - perror("setsockopt"); - ret = -1; - } -# endif - break; - case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT: - { - union { - size_t s; - int i; - } sz = { - 0 - }; -# ifdef OPENSSL_SYS_WINDOWS - int timeout; - struct timeval *tv = (struct timeval *)ptr; - - sz.i = sizeof(timeout); - if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, - (void *)&timeout, &sz.i) < 0) { - perror("getsockopt"); - ret = -1; - } else { - tv->tv_sec = timeout / 1000; - tv->tv_usec = (timeout % 1000) * 1000; - ret = sizeof(*tv); - } -# else - sz.i = sizeof(struct timeval); - if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, - ptr, (void *)&sz) < 0) { - perror("getsockopt"); - ret = -1; - } else if (sizeof(sz.s) != sizeof(sz.i) && sz.i == 0) { - OPENSSL_assert(sz.s <= sizeof(struct timeval)); - ret = (int)sz.s; - } else - ret = sz.i; -# endif - } - break; -# endif -# if defined(SO_SNDTIMEO) - case BIO_CTRL_DGRAM_SET_SEND_TIMEOUT: -# ifdef OPENSSL_SYS_WINDOWS - { - struct timeval *tv = (struct timeval *)ptr; - int timeout = tv->tv_sec * 1000 + tv->tv_usec / 1000; - if (setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, - (void *)&timeout, sizeof(timeout)) < 0) { - perror("setsockopt"); - ret = -1; - } - } -# else - if (setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, ptr, - sizeof(struct timeval)) < 0) { - perror("setsockopt"); - ret = -1; - } -# endif - break; - case BIO_CTRL_DGRAM_GET_SEND_TIMEOUT: - { - union { - size_t s; - int i; - } sz = { - 0 - }; -# ifdef OPENSSL_SYS_WINDOWS - int timeout; - struct timeval *tv = (struct timeval *)ptr; - - sz.i = sizeof(timeout); - if (getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, - (void *)&timeout, &sz.i) < 0) { - perror("getsockopt"); - ret = -1; - } else { - tv->tv_sec = timeout / 1000; - tv->tv_usec = (timeout % 1000) * 1000; - ret = sizeof(*tv); - } -# else - sz.i = sizeof(struct timeval); - if (getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, - ptr, (void *)&sz) < 0) { - perror("getsockopt"); - ret = -1; - } else if (sizeof(sz.s) != sizeof(sz.i) && sz.i == 0) { - OPENSSL_assert(sz.s <= sizeof(struct timeval)); - ret = (int)sz.s; - } else - ret = sz.i; -# endif - } - break; -# endif - case BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP: - /* fall-through */ - case BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP: -# ifdef OPENSSL_SYS_WINDOWS - d_errno = (data->_errno == WSAETIMEDOUT); -# else - d_errno = (data->_errno == EAGAIN); -# endif - if (d_errno) { - ret = 1; - data->_errno = 0; - } else - ret = 0; - break; -# ifdef EMSGSIZE - case BIO_CTRL_DGRAM_MTU_EXCEEDED: - if (data->_errno == EMSGSIZE) { - ret = 1; - data->_errno = 0; - } else - ret = 0; - break; -# endif - case BIO_CTRL_DGRAM_SET_DONT_FRAG: - sockopt_val = num ? 1 : 0; - - switch (data->peer.sa.sa_family) { - case AF_INET: -# if defined(IP_DONTFRAG) - if ((ret = setsockopt(b->num, IPPROTO_IP, IP_DONTFRAG, - &sockopt_val, sizeof(sockopt_val))) < 0) { - perror("setsockopt"); - ret = -1; - } -# elif defined(OPENSSL_SYS_LINUX) && defined(IP_MTU_DISCOVER) && defined (IP_PMTUDISC_PROBE) - if ((sockopt_val = num ? IP_PMTUDISC_PROBE : IP_PMTUDISC_DONT), - (ret = setsockopt(b->num, IPPROTO_IP, IP_MTU_DISCOVER, - &sockopt_val, sizeof(sockopt_val))) < 0) { - perror("setsockopt"); - ret = -1; - } -# elif defined(OPENSSL_SYS_WINDOWS) && defined(IP_DONTFRAGMENT) - if ((ret = setsockopt(b->num, IPPROTO_IP, IP_DONTFRAGMENT, - (const char *)&sockopt_val, - sizeof(sockopt_val))) < 0) { - perror("setsockopt"); - ret = -1; - } -# else - ret = -1; -# endif - break; -# if OPENSSL_USE_IPV6 - case AF_INET6: -# if defined(IPV6_DONTFRAG) - if ((ret = setsockopt(b->num, IPPROTO_IPV6, IPV6_DONTFRAG, - (const void *)&sockopt_val, - sizeof(sockopt_val))) < 0) { - perror("setsockopt"); - ret = -1; - } -# elif defined(OPENSSL_SYS_LINUX) && defined(IPV6_MTUDISCOVER) - if ((sockopt_val = num ? IP_PMTUDISC_PROBE : IP_PMTUDISC_DONT), - (ret = setsockopt(b->num, IPPROTO_IPV6, IPV6_MTU_DISCOVER, - &sockopt_val, sizeof(sockopt_val))) < 0) { - perror("setsockopt"); - ret = -1; - } -# else - ret = -1; -# endif - break; -# endif - default: - ret = -1; - break; - } - break; - case BIO_CTRL_DGRAM_GET_MTU_OVERHEAD: - ret = dgram_get_mtu_overhead(data); - break; - - /* - * BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE is used here for compatibility - * reasons. When BIO_CTRL_DGRAM_SET_PEEK_MODE was first defined its value - * was incorrectly clashing with BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE. The - * value has been updated to a non-clashing value. However to preserve +#ifndef OPENSSL_NO_DGRAM + +# ifndef OPENSSL_NO_SCTP +# include <netinet/sctp.h> +# include <fcntl.h> +# define OPENSSL_SCTP_DATA_CHUNK_TYPE 0x00 +# define OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE 0xc0 +# endif + +# if defined(OPENSSL_SYS_LINUX) && !defined(IP_MTU) +# define IP_MTU 14 /* linux is lame */ +# endif + +# if OPENSSL_USE_IPV6 && !defined(IPPROTO_IPV6) +# define IPPROTO_IPV6 41 /* windows is lame */ +# endif + +# if defined(__FreeBSD__) && defined(IN6_IS_ADDR_V4MAPPED) +/* Standard definition causes type-punning problems. */ +# undef IN6_IS_ADDR_V4MAPPED +# define s6_addr32 __u6_addr.__u6_addr32 +# define IN6_IS_ADDR_V4MAPPED(a) \ + (((a)->s6_addr32[0] == 0) && \ + ((a)->s6_addr32[1] == 0) && \ + ((a)->s6_addr32[2] == htonl(0x0000ffff))) +# endif + +static int dgram_write(BIO *h, const char *buf, int num); +static int dgram_read(BIO *h, char *buf, int size); +static int dgram_puts(BIO *h, const char *str); +static long dgram_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int dgram_new(BIO *h); +static int dgram_free(BIO *data); +static int dgram_clear(BIO *bio); + +# ifndef OPENSSL_NO_SCTP +static int dgram_sctp_write(BIO *h, const char *buf, int num); +static int dgram_sctp_read(BIO *h, char *buf, int size); +static int dgram_sctp_puts(BIO *h, const char *str); +static long dgram_sctp_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int dgram_sctp_new(BIO *h); +static int dgram_sctp_free(BIO *data); +# ifdef SCTP_AUTHENTICATION_EVENT +static void dgram_sctp_handle_auth_free_key_event(BIO *b, union sctp_notification + *snp); +# endif +# endif + +static int BIO_dgram_should_retry(int s); + +static void get_current_time(struct timeval *t); + +static const BIO_METHOD methods_dgramp = { + BIO_TYPE_DGRAM, + "datagram socket", + /* TODO: Convert to new style write function */ + bwrite_conv, + dgram_write, + /* TODO: Convert to new style read function */ + bread_conv, + dgram_read, + dgram_puts, + NULL, /* dgram_gets, */ + dgram_ctrl, + dgram_new, + dgram_free, + NULL, /* dgram_callback_ctrl */ +}; + +# ifndef OPENSSL_NO_SCTP +static const BIO_METHOD methods_dgramp_sctp = { + BIO_TYPE_DGRAM_SCTP, + "datagram sctp socket", + /* TODO: Convert to new style write function */ + bwrite_conv, + dgram_sctp_write, + /* TODO: Convert to new style write function */ + bread_conv, + dgram_sctp_read, + dgram_sctp_puts, + NULL, /* dgram_gets, */ + dgram_sctp_ctrl, + dgram_sctp_new, + dgram_sctp_free, + NULL, /* dgram_callback_ctrl */ +}; +# endif + +typedef struct bio_dgram_data_st { + BIO_ADDR peer; + unsigned int connected; + unsigned int _errno; + unsigned int mtu; + struct timeval next_timeout; + struct timeval socket_timeout; + unsigned int peekmode; +} bio_dgram_data; + +# ifndef OPENSSL_NO_SCTP +typedef struct bio_dgram_sctp_save_message_st { + BIO *bio; + char *data; + int length; +} bio_dgram_sctp_save_message; + +typedef struct bio_dgram_sctp_data_st { + BIO_ADDR peer; + unsigned int connected; + unsigned int _errno; + unsigned int mtu; + struct bio_dgram_sctp_sndinfo sndinfo; + struct bio_dgram_sctp_rcvinfo rcvinfo; + struct bio_dgram_sctp_prinfo prinfo; + void (*handle_notifications) (BIO *bio, void *context, void *buf); + void *notification_context; + int in_handshake; + int ccs_rcvd; + int ccs_sent; + int save_shutdown; + int peer_auth_tested; +} bio_dgram_sctp_data; +# endif + +const BIO_METHOD *BIO_s_datagram(void) +{ + return &methods_dgramp; +} + +BIO *BIO_new_dgram(int fd, int close_flag) +{ + BIO *ret; + + ret = BIO_new(BIO_s_datagram()); + if (ret == NULL) + return NULL; + BIO_set_fd(ret, fd, close_flag); + return ret; +} + +static int dgram_new(BIO *bi) +{ + bio_dgram_data *data = OPENSSL_zalloc(sizeof(*data)); + + if (data == NULL) + return 0; + bi->ptr = data; + return 1; +} + +static int dgram_free(BIO *a) +{ + bio_dgram_data *data; + + if (a == NULL) + return 0; + if (!dgram_clear(a)) + return 0; + + data = (bio_dgram_data *)a->ptr; + OPENSSL_free(data); + + return 1; +} + +static int dgram_clear(BIO *a) +{ + if (a == NULL) + return 0; + if (a->shutdown) { + if (a->init) { + BIO_closesocket(a->num); + } + a->init = 0; + a->flags = 0; + } + return 1; +} + +static void dgram_adjust_rcv_timeout(BIO *b) +{ +# if defined(SO_RCVTIMEO) + bio_dgram_data *data = (bio_dgram_data *)b->ptr; + union { + size_t s; + int i; + } sz = { + 0 + }; + + /* Is a timer active? */ + if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0) { + struct timeval timenow, timeleft; + + /* Read current socket timeout */ +# ifdef OPENSSL_SYS_WINDOWS + int timeout; + + sz.i = sizeof(timeout); + if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, + (void *)&timeout, &sz.i) < 0) { + perror("getsockopt"); + } else { + data->socket_timeout.tv_sec = timeout / 1000; + data->socket_timeout.tv_usec = (timeout % 1000) * 1000; + } +# else + sz.i = sizeof(data->socket_timeout); + if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, + &(data->socket_timeout), (void *)&sz) < 0) { + perror("getsockopt"); + } else if (sizeof(sz.s) != sizeof(sz.i) && sz.i == 0) + OPENSSL_assert(sz.s <= sizeof(data->socket_timeout)); +# endif + + /* Get current time */ + get_current_time(&timenow); + + /* Calculate time left until timer expires */ + memcpy(&timeleft, &(data->next_timeout), sizeof(struct timeval)); + if (timeleft.tv_usec < timenow.tv_usec) { + timeleft.tv_usec = 1000000 - timenow.tv_usec + timeleft.tv_usec; + timeleft.tv_sec--; + } else { + timeleft.tv_usec -= timenow.tv_usec; + } + if (timeleft.tv_sec < timenow.tv_sec) { + timeleft.tv_sec = 0; + timeleft.tv_usec = 1; + } else { + timeleft.tv_sec -= timenow.tv_sec; + } + + /* + * Adjust socket timeout if next handshake message timer will expire + * earlier. + */ + if ((data->socket_timeout.tv_sec == 0 + && data->socket_timeout.tv_usec == 0) + || (data->socket_timeout.tv_sec > timeleft.tv_sec) + || (data->socket_timeout.tv_sec == timeleft.tv_sec + && data->socket_timeout.tv_usec >= timeleft.tv_usec)) { +# ifdef OPENSSL_SYS_WINDOWS + timeout = timeleft.tv_sec * 1000 + timeleft.tv_usec / 1000; + if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, + (void *)&timeout, sizeof(timeout)) < 0) { + perror("setsockopt"); + } +# else + if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, &timeleft, + sizeof(struct timeval)) < 0) { + perror("setsockopt"); + } +# endif + } + } +# endif +} + +static void dgram_reset_rcv_timeout(BIO *b) +{ +# if defined(SO_RCVTIMEO) + bio_dgram_data *data = (bio_dgram_data *)b->ptr; + + /* Is a timer active? */ + if (data->next_timeout.tv_sec > 0 || data->next_timeout.tv_usec > 0) { +# ifdef OPENSSL_SYS_WINDOWS + int timeout = data->socket_timeout.tv_sec * 1000 + + data->socket_timeout.tv_usec / 1000; + if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, + (void *)&timeout, sizeof(timeout)) < 0) { + perror("setsockopt"); + } +# else + if (setsockopt + (b->num, SOL_SOCKET, SO_RCVTIMEO, &(data->socket_timeout), + sizeof(struct timeval)) < 0) { + perror("setsockopt"); + } +# endif + } +# endif +} + +static int dgram_read(BIO *b, char *out, int outl) +{ + int ret = 0; + bio_dgram_data *data = (bio_dgram_data *)b->ptr; + int flags = 0; + + BIO_ADDR peer; + socklen_t len = sizeof(peer); + + if (out != NULL) { + clear_socket_error(); + memset(&peer, 0, sizeof(peer)); + dgram_adjust_rcv_timeout(b); + if (data->peekmode) + flags = MSG_PEEK; + ret = recvfrom(b->num, out, outl, flags, + BIO_ADDR_sockaddr_noconst(&peer), &len); + + if (!data->connected && ret >= 0) + BIO_ctrl(b, BIO_CTRL_DGRAM_SET_PEER, 0, &peer); + + BIO_clear_retry_flags(b); + if (ret < 0) { + if (BIO_dgram_should_retry(ret)) { + BIO_set_retry_read(b); + data->_errno = get_last_socket_error(); + } + } + + dgram_reset_rcv_timeout(b); + } + return ret; +} + +static int dgram_write(BIO *b, const char *in, int inl) +{ + int ret; + bio_dgram_data *data = (bio_dgram_data *)b->ptr; + clear_socket_error(); + + if (data->connected) + ret = writesocket(b->num, in, inl); + else { + int peerlen = BIO_ADDR_sockaddr_size(&data->peer); + + ret = sendto(b->num, in, inl, 0, + BIO_ADDR_sockaddr(&data->peer), peerlen); + } + + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (BIO_dgram_should_retry(ret)) { + BIO_set_retry_write(b); + data->_errno = get_last_socket_error(); + } + } + return ret; +} + +static long dgram_get_mtu_overhead(bio_dgram_data *data) +{ + long ret; + + switch (BIO_ADDR_family(&data->peer)) { + case AF_INET: + /* + * Assume this is UDP - 20 bytes for IP, 8 bytes for UDP + */ + ret = 28; + break; +# if OPENSSL_USE_IPV6 + case AF_INET6: + { +# ifdef IN6_IS_ADDR_V4MAPPED + struct in6_addr tmp_addr; + if (BIO_ADDR_rawaddress(&data->peer, &tmp_addr, NULL) + && IN6_IS_ADDR_V4MAPPED(&tmp_addr)) + /* + * Assume this is UDP - 20 bytes for IP, 8 bytes for UDP + */ + ret = 28; + else +# endif + /* + * Assume this is UDP - 40 bytes for IP, 8 bytes for UDP + */ + ret = 48; + } + break; +# endif + default: + /* We don't know. Go with the historical default */ + ret = 28; + break; + } + return ret; +} + +static long dgram_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + long ret = 1; + int *ip; + bio_dgram_data *data = NULL; + int sockopt_val = 0; + int d_errno; +# if defined(OPENSSL_SYS_LINUX) && (defined(IP_MTU_DISCOVER) || defined(IP_MTU)) + socklen_t sockopt_len; /* assume that system supporting IP_MTU is + * modern enough to define socklen_t */ + socklen_t addr_len; + BIO_ADDR addr; +# endif + + data = (bio_dgram_data *)b->ptr; + + switch (cmd) { + case BIO_CTRL_RESET: + num = 0; + ret = 0; + break; + case BIO_CTRL_INFO: + ret = 0; + break; + case BIO_C_SET_FD: + dgram_clear(b); + b->num = *((int *)ptr); + b->shutdown = (int)num; + b->init = 1; + break; + case BIO_C_GET_FD: + if (b->init) { + ip = (int *)ptr; + if (ip != NULL) + *ip = b->num; + ret = b->num; + } else + ret = -1; + break; + case BIO_CTRL_GET_CLOSE: + ret = b->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + b->shutdown = (int)num; + break; + case BIO_CTRL_PENDING: + case BIO_CTRL_WPENDING: + ret = 0; + break; + case BIO_CTRL_DUP: + case BIO_CTRL_FLUSH: + ret = 1; + break; + case BIO_CTRL_DGRAM_CONNECT: + BIO_ADDR_make(&data->peer, BIO_ADDR_sockaddr((BIO_ADDR *)ptr)); + break; + /* (Linux)kernel sets DF bit on outgoing IP packets */ + case BIO_CTRL_DGRAM_MTU_DISCOVER: +# if defined(OPENSSL_SYS_LINUX) && defined(IP_MTU_DISCOVER) && defined(IP_PMTUDISC_DO) + addr_len = (socklen_t) sizeof(addr); + memset(&addr, 0, sizeof(addr)); + if (getsockname(b->num, &addr.sa, &addr_len) < 0) { + ret = 0; + break; + } + switch (addr.sa.sa_family) { + case AF_INET: + sockopt_val = IP_PMTUDISC_DO; + if ((ret = setsockopt(b->num, IPPROTO_IP, IP_MTU_DISCOVER, + &sockopt_val, sizeof(sockopt_val))) < 0) + perror("setsockopt"); + break; +# if OPENSSL_USE_IPV6 && defined(IPV6_MTU_DISCOVER) && defined(IPV6_PMTUDISC_DO) + case AF_INET6: + sockopt_val = IPV6_PMTUDISC_DO; + if ((ret = setsockopt(b->num, IPPROTO_IPV6, IPV6_MTU_DISCOVER, + &sockopt_val, sizeof(sockopt_val))) < 0) + perror("setsockopt"); + break; +# endif + default: + ret = -1; + break; + } +# else + ret = -1; +# endif + break; + case BIO_CTRL_DGRAM_QUERY_MTU: +# if defined(OPENSSL_SYS_LINUX) && defined(IP_MTU) + addr_len = (socklen_t) sizeof(addr); + memset(&addr, 0, sizeof(addr)); + if (getsockname(b->num, &addr.sa, &addr_len) < 0) { + ret = 0; + break; + } + sockopt_len = sizeof(sockopt_val); + switch (addr.sa.sa_family) { + case AF_INET: + if ((ret = + getsockopt(b->num, IPPROTO_IP, IP_MTU, (void *)&sockopt_val, + &sockopt_len)) < 0 || sockopt_val < 0) { + ret = 0; + } else { + /* + * we assume that the transport protocol is UDP and no IP + * options are used. + */ + data->mtu = sockopt_val - 8 - 20; + ret = data->mtu; + } + break; +# if OPENSSL_USE_IPV6 && defined(IPV6_MTU) + case AF_INET6: + if ((ret = + getsockopt(b->num, IPPROTO_IPV6, IPV6_MTU, + (void *)&sockopt_val, &sockopt_len)) < 0 + || sockopt_val < 0) { + ret = 0; + } else { + /* + * we assume that the transport protocol is UDP and no IPV6 + * options are used. + */ + data->mtu = sockopt_val - 8 - 40; + ret = data->mtu; + } + break; +# endif + default: + ret = 0; + break; + } +# else + ret = 0; +# endif + break; + case BIO_CTRL_DGRAM_GET_FALLBACK_MTU: + ret = -dgram_get_mtu_overhead(data); + switch (BIO_ADDR_family(&data->peer)) { + case AF_INET: + ret += 576; + break; +# if OPENSSL_USE_IPV6 + case AF_INET6: + { +# ifdef IN6_IS_ADDR_V4MAPPED + struct in6_addr tmp_addr; + if (BIO_ADDR_rawaddress(&data->peer, &tmp_addr, NULL) + && IN6_IS_ADDR_V4MAPPED(&tmp_addr)) + ret += 576; + else +# endif + ret += 1280; + } + break; +# endif + default: + ret += 576; + break; + } + break; + case BIO_CTRL_DGRAM_GET_MTU: + return data->mtu; + case BIO_CTRL_DGRAM_SET_MTU: + data->mtu = num; + ret = num; + break; + case BIO_CTRL_DGRAM_SET_CONNECTED: + if (ptr != NULL) { + data->connected = 1; + BIO_ADDR_make(&data->peer, BIO_ADDR_sockaddr((BIO_ADDR *)ptr)); + } else { + data->connected = 0; + memset(&data->peer, 0, sizeof(data->peer)); + } + break; + case BIO_CTRL_DGRAM_GET_PEER: + ret = BIO_ADDR_sockaddr_size(&data->peer); + /* FIXME: if num < ret, we will only return part of an address. + That should bee an error, no? */ + if (num == 0 || num > ret) + num = ret; + memcpy(ptr, &data->peer, (ret = num)); + break; + case BIO_CTRL_DGRAM_SET_PEER: + BIO_ADDR_make(&data->peer, BIO_ADDR_sockaddr((BIO_ADDR *)ptr)); + break; + case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT: + memcpy(&(data->next_timeout), ptr, sizeof(struct timeval)); + break; +# if defined(SO_RCVTIMEO) + case BIO_CTRL_DGRAM_SET_RECV_TIMEOUT: +# ifdef OPENSSL_SYS_WINDOWS + { + struct timeval *tv = (struct timeval *)ptr; + int timeout = tv->tv_sec * 1000 + tv->tv_usec / 1000; + if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, + (void *)&timeout, sizeof(timeout)) < 0) { + perror("setsockopt"); + ret = -1; + } + } +# else + if (setsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, ptr, + sizeof(struct timeval)) < 0) { + perror("setsockopt"); + ret = -1; + } +# endif + break; + case BIO_CTRL_DGRAM_GET_RECV_TIMEOUT: + { + union { + size_t s; + int i; + } sz = { + 0 + }; +# ifdef OPENSSL_SYS_WINDOWS + int timeout; + struct timeval *tv = (struct timeval *)ptr; + + sz.i = sizeof(timeout); + if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, + (void *)&timeout, &sz.i) < 0) { + perror("getsockopt"); + ret = -1; + } else { + tv->tv_sec = timeout / 1000; + tv->tv_usec = (timeout % 1000) * 1000; + ret = sizeof(*tv); + } +# else + sz.i = sizeof(struct timeval); + if (getsockopt(b->num, SOL_SOCKET, SO_RCVTIMEO, + ptr, (void *)&sz) < 0) { + perror("getsockopt"); + ret = -1; + } else if (sizeof(sz.s) != sizeof(sz.i) && sz.i == 0) { + OPENSSL_assert(sz.s <= sizeof(struct timeval)); + ret = (int)sz.s; + } else + ret = sz.i; +# endif + } + break; +# endif +# if defined(SO_SNDTIMEO) + case BIO_CTRL_DGRAM_SET_SEND_TIMEOUT: +# ifdef OPENSSL_SYS_WINDOWS + { + struct timeval *tv = (struct timeval *)ptr; + int timeout = tv->tv_sec * 1000 + tv->tv_usec / 1000; + if (setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, + (void *)&timeout, sizeof(timeout)) < 0) { + perror("setsockopt"); + ret = -1; + } + } +# else + if (setsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, ptr, + sizeof(struct timeval)) < 0) { + perror("setsockopt"); + ret = -1; + } +# endif + break; + case BIO_CTRL_DGRAM_GET_SEND_TIMEOUT: + { + union { + size_t s; + int i; + } sz = { + 0 + }; +# ifdef OPENSSL_SYS_WINDOWS + int timeout; + struct timeval *tv = (struct timeval *)ptr; + + sz.i = sizeof(timeout); + if (getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, + (void *)&timeout, &sz.i) < 0) { + perror("getsockopt"); + ret = -1; + } else { + tv->tv_sec = timeout / 1000; + tv->tv_usec = (timeout % 1000) * 1000; + ret = sizeof(*tv); + } +# else + sz.i = sizeof(struct timeval); + if (getsockopt(b->num, SOL_SOCKET, SO_SNDTIMEO, + ptr, (void *)&sz) < 0) { + perror("getsockopt"); + ret = -1; + } else if (sizeof(sz.s) != sizeof(sz.i) && sz.i == 0) { + OPENSSL_assert(sz.s <= sizeof(struct timeval)); + ret = (int)sz.s; + } else + ret = sz.i; +# endif + } + break; +# endif + case BIO_CTRL_DGRAM_GET_SEND_TIMER_EXP: + /* fall-through */ + case BIO_CTRL_DGRAM_GET_RECV_TIMER_EXP: +# ifdef OPENSSL_SYS_WINDOWS + d_errno = (data->_errno == WSAETIMEDOUT); +# else + d_errno = (data->_errno == EAGAIN); +# endif + if (d_errno) { + ret = 1; + data->_errno = 0; + } else + ret = 0; + break; +# ifdef EMSGSIZE + case BIO_CTRL_DGRAM_MTU_EXCEEDED: + if (data->_errno == EMSGSIZE) { + ret = 1; + data->_errno = 0; + } else + ret = 0; + break; +# endif + case BIO_CTRL_DGRAM_SET_DONT_FRAG: + sockopt_val = num ? 1 : 0; + + switch (data->peer.sa.sa_family) { + case AF_INET: +# if defined(IP_DONTFRAG) + if ((ret = setsockopt(b->num, IPPROTO_IP, IP_DONTFRAG, + &sockopt_val, sizeof(sockopt_val))) < 0) { + perror("setsockopt"); + ret = -1; + } +# elif defined(OPENSSL_SYS_LINUX) && defined(IP_MTU_DISCOVER) && defined (IP_PMTUDISC_PROBE) + if ((sockopt_val = num ? IP_PMTUDISC_PROBE : IP_PMTUDISC_DONT), + (ret = setsockopt(b->num, IPPROTO_IP, IP_MTU_DISCOVER, + &sockopt_val, sizeof(sockopt_val))) < 0) { + perror("setsockopt"); + ret = -1; + } +# elif defined(OPENSSL_SYS_WINDOWS) && defined(IP_DONTFRAGMENT) + if ((ret = setsockopt(b->num, IPPROTO_IP, IP_DONTFRAGMENT, + (const char *)&sockopt_val, + sizeof(sockopt_val))) < 0) { + perror("setsockopt"); + ret = -1; + } +# else + ret = -1; +# endif + break; +# if OPENSSL_USE_IPV6 + case AF_INET6: +# if defined(IPV6_DONTFRAG) + if ((ret = setsockopt(b->num, IPPROTO_IPV6, IPV6_DONTFRAG, + (const void *)&sockopt_val, + sizeof(sockopt_val))) < 0) { + perror("setsockopt"); + ret = -1; + } +# elif defined(OPENSSL_SYS_LINUX) && defined(IPV6_MTUDISCOVER) + if ((sockopt_val = num ? IP_PMTUDISC_PROBE : IP_PMTUDISC_DONT), + (ret = setsockopt(b->num, IPPROTO_IPV6, IPV6_MTU_DISCOVER, + &sockopt_val, sizeof(sockopt_val))) < 0) { + perror("setsockopt"); + ret = -1; + } +# else + ret = -1; +# endif + break; +# endif + default: + ret = -1; + break; + } + break; + case BIO_CTRL_DGRAM_GET_MTU_OVERHEAD: + ret = dgram_get_mtu_overhead(data); + break; + + /* + * BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE is used here for compatibility + * reasons. When BIO_CTRL_DGRAM_SET_PEEK_MODE was first defined its value + * was incorrectly clashing with BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE. The + * value has been updated to a non-clashing value. However to preserve * binary compatibility we now respond to both the old value and the new one - */ - case BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE: - case BIO_CTRL_DGRAM_SET_PEEK_MODE: - data->peekmode = (unsigned int)num; - break; - default: - ret = 0; - break; - } - return ret; -} - -static int dgram_puts(BIO *bp, const char *str) -{ - int n, ret; - - n = strlen(str); - ret = dgram_write(bp, str, n); - return ret; -} - -# ifndef OPENSSL_NO_SCTP -const BIO_METHOD *BIO_s_datagram_sctp(void) -{ - return &methods_dgramp_sctp; -} - -BIO *BIO_new_dgram_sctp(int fd, int close_flag) -{ - BIO *bio; - int ret, optval = 20000; - int auth_data = 0, auth_forward = 0; - unsigned char *p; - struct sctp_authchunk auth; - struct sctp_authchunks *authchunks; - socklen_t sockopt_len; -# ifdef SCTP_AUTHENTICATION_EVENT -# ifdef SCTP_EVENT - struct sctp_event event; -# else - struct sctp_event_subscribe event; -# endif -# endif - - bio = BIO_new(BIO_s_datagram_sctp()); - if (bio == NULL) - return NULL; - BIO_set_fd(bio, fd, close_flag); - - /* Activate SCTP-AUTH for DATA and FORWARD-TSN chunks */ - auth.sauth_chunk = OPENSSL_SCTP_DATA_CHUNK_TYPE; - ret = - setsockopt(fd, IPPROTO_SCTP, SCTP_AUTH_CHUNK, &auth, - sizeof(struct sctp_authchunk)); - if (ret < 0) { - BIO_vfree(bio); - BIOerr(BIO_F_BIO_NEW_DGRAM_SCTP, ERR_R_SYS_LIB); - ERR_add_error_data(1, "Ensure SCTP AUTH chunks are enabled in kernel"); - return NULL; - } - auth.sauth_chunk = OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE; - ret = - setsockopt(fd, IPPROTO_SCTP, SCTP_AUTH_CHUNK, &auth, - sizeof(struct sctp_authchunk)); - if (ret < 0) { - BIO_vfree(bio); - BIOerr(BIO_F_BIO_NEW_DGRAM_SCTP, ERR_R_SYS_LIB); - ERR_add_error_data(1, "Ensure SCTP AUTH chunks are enabled in kernel"); - return NULL; - } - - /* - * Test if activation was successful. When using accept(), SCTP-AUTH has - * to be activated for the listening socket already, otherwise the - * connected socket won't use it. Similarly with connect(): the socket - * prior to connection must be activated for SCTP-AUTH - */ - sockopt_len = (socklen_t) (sizeof(sctp_assoc_t) + 256 * sizeof(uint8_t)); - authchunks = OPENSSL_zalloc(sockopt_len); - if (authchunks == NULL) { - BIO_vfree(bio); - return NULL; - } - ret = getsockopt(fd, IPPROTO_SCTP, SCTP_LOCAL_AUTH_CHUNKS, authchunks, - &sockopt_len); - if (ret < 0) { - OPENSSL_free(authchunks); - BIO_vfree(bio); - return NULL; - } - - for (p = (unsigned char *)authchunks->gauth_chunks; - p < (unsigned char *)authchunks + sockopt_len; - p += sizeof(uint8_t)) { - if (*p == OPENSSL_SCTP_DATA_CHUNK_TYPE) - auth_data = 1; - if (*p == OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE) - auth_forward = 1; - } - - OPENSSL_free(authchunks); - - if (!auth_data || !auth_forward) { - BIO_vfree(bio); - BIOerr(BIO_F_BIO_NEW_DGRAM_SCTP, ERR_R_SYS_LIB); - ERR_add_error_data(1, - "Ensure SCTP AUTH chunks are enabled on the " - "underlying socket"); - return NULL; - } - -# ifdef SCTP_AUTHENTICATION_EVENT -# ifdef SCTP_EVENT - memset(&event, 0, sizeof(event)); - event.se_assoc_id = 0; - event.se_type = SCTP_AUTHENTICATION_EVENT; - event.se_on = 1; - ret = - setsockopt(fd, IPPROTO_SCTP, SCTP_EVENT, &event, - sizeof(struct sctp_event)); - if (ret < 0) { - BIO_vfree(bio); - return NULL; - } -# else - sockopt_len = (socklen_t) sizeof(struct sctp_event_subscribe); - ret = getsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, &sockopt_len); - if (ret < 0) { - BIO_vfree(bio); - return NULL; - } - - event.sctp_authentication_event = 1; - - ret = - setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, - sizeof(struct sctp_event_subscribe)); - if (ret < 0) { - BIO_vfree(bio); - return NULL; - } -# endif -# endif - - /* - * Disable partial delivery by setting the min size larger than the max - * record size of 2^14 + 2048 + 13 - */ - ret = - setsockopt(fd, IPPROTO_SCTP, SCTP_PARTIAL_DELIVERY_POINT, &optval, - sizeof(optval)); - if (ret < 0) { - BIO_vfree(bio); - return NULL; - } - - return bio; -} - -int BIO_dgram_is_sctp(BIO *bio) -{ - return (BIO_method_type(bio) == BIO_TYPE_DGRAM_SCTP); -} - -static int dgram_sctp_new(BIO *bi) -{ - bio_dgram_sctp_data *data = NULL; - - bi->init = 0; - bi->num = 0; - if ((data = OPENSSL_zalloc(sizeof(*data))) == NULL) { - BIOerr(BIO_F_DGRAM_SCTP_NEW, ERR_R_MALLOC_FAILURE); - return 0; - } -# ifdef SCTP_PR_SCTP_NONE - data->prinfo.pr_policy = SCTP_PR_SCTP_NONE; -# endif - bi->ptr = data; - - bi->flags = 0; - return 1; -} - -static int dgram_sctp_free(BIO *a) -{ - bio_dgram_sctp_data *data; - - if (a == NULL) - return 0; - if (!dgram_clear(a)) - return 0; - - data = (bio_dgram_sctp_data *) a->ptr; - if (data != NULL) - OPENSSL_free(data); - - return 1; -} - -# ifdef SCTP_AUTHENTICATION_EVENT -void dgram_sctp_handle_auth_free_key_event(BIO *b, - union sctp_notification *snp) -{ - int ret; - struct sctp_authkey_event *authkeyevent = &snp->sn_auth_event; - - if (authkeyevent->auth_indication == SCTP_AUTH_FREE_KEY) { - struct sctp_authkeyid authkeyid; - - /* delete key */ - authkeyid.scact_keynumber = authkeyevent->auth_keynumber; - ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DELETE_KEY, - &authkeyid, sizeof(struct sctp_authkeyid)); - } -} -# endif - -static int dgram_sctp_read(BIO *b, char *out, int outl) -{ - int ret = 0, n = 0, i, optval; - socklen_t optlen; - bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr; - union sctp_notification *snp; - struct msghdr msg; - struct iovec iov; - struct cmsghdr *cmsg; - char cmsgbuf[512]; - - if (out != NULL) { - clear_socket_error(); - - do { - memset(&data->rcvinfo, 0, sizeof(data->rcvinfo)); - iov.iov_base = out; - iov.iov_len = outl; - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = cmsgbuf; - msg.msg_controllen = 512; - msg.msg_flags = 0; - n = recvmsg(b->num, &msg, 0); - - if (n <= 0) { - if (n < 0) - ret = n; - break; - } - - if (msg.msg_controllen > 0) { - for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; - cmsg = CMSG_NXTHDR(&msg, cmsg)) { - if (cmsg->cmsg_level != IPPROTO_SCTP) - continue; -# ifdef SCTP_RCVINFO - if (cmsg->cmsg_type == SCTP_RCVINFO) { - struct sctp_rcvinfo *rcvinfo; - - rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg); - data->rcvinfo.rcv_sid = rcvinfo->rcv_sid; - data->rcvinfo.rcv_ssn = rcvinfo->rcv_ssn; - data->rcvinfo.rcv_flags = rcvinfo->rcv_flags; - data->rcvinfo.rcv_ppid = rcvinfo->rcv_ppid; - data->rcvinfo.rcv_tsn = rcvinfo->rcv_tsn; - data->rcvinfo.rcv_cumtsn = rcvinfo->rcv_cumtsn; - data->rcvinfo.rcv_context = rcvinfo->rcv_context; - } -# endif -# ifdef SCTP_SNDRCV - if (cmsg->cmsg_type == SCTP_SNDRCV) { - struct sctp_sndrcvinfo *sndrcvinfo; - - sndrcvinfo = - (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); - data->rcvinfo.rcv_sid = sndrcvinfo->sinfo_stream; - data->rcvinfo.rcv_ssn = sndrcvinfo->sinfo_ssn; - data->rcvinfo.rcv_flags = sndrcvinfo->sinfo_flags; - data->rcvinfo.rcv_ppid = sndrcvinfo->sinfo_ppid; - data->rcvinfo.rcv_tsn = sndrcvinfo->sinfo_tsn; - data->rcvinfo.rcv_cumtsn = sndrcvinfo->sinfo_cumtsn; - data->rcvinfo.rcv_context = sndrcvinfo->sinfo_context; - } -# endif - } - } - - if (msg.msg_flags & MSG_NOTIFICATION) { - snp = (union sctp_notification *)out; - if (snp->sn_header.sn_type == SCTP_SENDER_DRY_EVENT) { -# ifdef SCTP_EVENT - struct sctp_event event; -# else - struct sctp_event_subscribe event; - socklen_t eventsize; -# endif - - /* disable sender dry event */ -# ifdef SCTP_EVENT - memset(&event, 0, sizeof(event)); - event.se_assoc_id = 0; - event.se_type = SCTP_SENDER_DRY_EVENT; - event.se_on = 0; - i = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, - sizeof(struct sctp_event)); - if (i < 0) { - ret = i; - break; - } -# else - eventsize = sizeof(struct sctp_event_subscribe); - i = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, - &eventsize); - if (i < 0) { - ret = i; - break; - } - - event.sctp_sender_dry_event = 0; - - i = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, - sizeof(struct sctp_event_subscribe)); - if (i < 0) { - ret = i; - break; - } -# endif - } -# ifdef SCTP_AUTHENTICATION_EVENT - if (snp->sn_header.sn_type == SCTP_AUTHENTICATION_EVENT) - dgram_sctp_handle_auth_free_key_event(b, snp); -# endif - - if (data->handle_notifications != NULL) - data->handle_notifications(b, data->notification_context, - (void *)out); - - memset(out, 0, outl); - } else - ret += n; - } - while ((msg.msg_flags & MSG_NOTIFICATION) && (msg.msg_flags & MSG_EOR) - && (ret < outl)); - - if (ret > 0 && !(msg.msg_flags & MSG_EOR)) { - /* Partial message read, this should never happen! */ - - /* - * The buffer was too small, this means the peer sent a message - * that was larger than allowed. - */ - if (ret == outl) - return -1; - - /* - * Test if socket buffer can handle max record size (2^14 + 2048 - * + 13) - */ - optlen = (socklen_t) sizeof(int); - ret = getsockopt(b->num, SOL_SOCKET, SO_RCVBUF, &optval, &optlen); - if (ret >= 0) - OPENSSL_assert(optval >= 18445); - - /* - * Test if SCTP doesn't partially deliver below max record size - * (2^14 + 2048 + 13) - */ - optlen = (socklen_t) sizeof(int); - ret = - getsockopt(b->num, IPPROTO_SCTP, SCTP_PARTIAL_DELIVERY_POINT, - &optval, &optlen); - if (ret >= 0) - OPENSSL_assert(optval >= 18445); - - /* - * Partially delivered notification??? Probably a bug.... - */ - OPENSSL_assert(!(msg.msg_flags & MSG_NOTIFICATION)); - - /* - * Everything seems ok till now, so it's most likely a message - * dropped by PR-SCTP. - */ - memset(out, 0, outl); - BIO_set_retry_read(b); - return -1; - } - - BIO_clear_retry_flags(b); - if (ret < 0) { - if (BIO_dgram_should_retry(ret)) { - BIO_set_retry_read(b); - data->_errno = get_last_socket_error(); - } - } - - /* Test if peer uses SCTP-AUTH before continuing */ - if (!data->peer_auth_tested) { - int ii, auth_data = 0, auth_forward = 0; - unsigned char *p; - struct sctp_authchunks *authchunks; - - optlen = - (socklen_t) (sizeof(sctp_assoc_t) + 256 * sizeof(uint8_t)); - authchunks = OPENSSL_malloc(optlen); - if (authchunks == NULL) { - BIOerr(BIO_F_DGRAM_SCTP_READ, ERR_R_MALLOC_FAILURE); - return -1; - } - memset(authchunks, 0, optlen); - ii = getsockopt(b->num, IPPROTO_SCTP, SCTP_PEER_AUTH_CHUNKS, - authchunks, &optlen); - - if (ii >= 0) - for (p = (unsigned char *)authchunks->gauth_chunks; - p < (unsigned char *)authchunks + optlen; - p += sizeof(uint8_t)) { - if (*p == OPENSSL_SCTP_DATA_CHUNK_TYPE) - auth_data = 1; - if (*p == OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE) - auth_forward = 1; - } - - OPENSSL_free(authchunks); - - if (!auth_data || !auth_forward) { - BIOerr(BIO_F_DGRAM_SCTP_READ, BIO_R_CONNECT_ERROR); - return -1; - } - - data->peer_auth_tested = 1; - } - } - return ret; -} - -/* - * dgram_sctp_write - send message on SCTP socket - * @b: BIO to write to - * @in: data to send - * @inl: amount of bytes in @in to send - * - * Returns -1 on error or the sent amount of bytes on success - */ -static int dgram_sctp_write(BIO *b, const char *in, int inl) -{ - int ret; - bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr; - struct bio_dgram_sctp_sndinfo *sinfo = &(data->sndinfo); - struct bio_dgram_sctp_prinfo *pinfo = &(data->prinfo); - struct bio_dgram_sctp_sndinfo handshake_sinfo; - struct iovec iov[1]; - struct msghdr msg; - struct cmsghdr *cmsg; -# if defined(SCTP_SNDINFO) && defined(SCTP_PRINFO) - char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndinfo)) + - CMSG_SPACE(sizeof(struct sctp_prinfo))]; - struct sctp_sndinfo *sndinfo; - struct sctp_prinfo *prinfo; -# else - char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; - struct sctp_sndrcvinfo *sndrcvinfo; -# endif - - clear_socket_error(); - - /* - * If we're send anything else than application data, disable all user - * parameters and flags. - */ - if (in[0] != 23) { - memset(&handshake_sinfo, 0, sizeof(handshake_sinfo)); -# ifdef SCTP_SACK_IMMEDIATELY - handshake_sinfo.snd_flags = SCTP_SACK_IMMEDIATELY; -# endif - sinfo = &handshake_sinfo; - } - - /* We can only send a shutdown alert if the socket is dry */ - if (data->save_shutdown) { - ret = BIO_dgram_sctp_wait_for_dry(b); - if (ret < 0) - return -1; - if (ret == 0) { - BIO_clear_retry_flags(b); - BIO_set_retry_write(b); - return -1; - } - } - - iov[0].iov_base = (char *)in; - iov[0].iov_len = inl; - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = iov; - msg.msg_iovlen = 1; - msg.msg_control = (caddr_t) cmsgbuf; - msg.msg_controllen = 0; - msg.msg_flags = 0; -# if defined(SCTP_SNDINFO) && defined(SCTP_PRINFO) - cmsg = (struct cmsghdr *)cmsgbuf; - cmsg->cmsg_level = IPPROTO_SCTP; - cmsg->cmsg_type = SCTP_SNDINFO; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo)); - sndinfo = (struct sctp_sndinfo *)CMSG_DATA(cmsg); - memset(sndinfo, 0, sizeof(*sndinfo)); - sndinfo->snd_sid = sinfo->snd_sid; - sndinfo->snd_flags = sinfo->snd_flags; - sndinfo->snd_ppid = sinfo->snd_ppid; - sndinfo->snd_context = sinfo->snd_context; - msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo)); - - cmsg = - (struct cmsghdr *)&cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndinfo))]; - cmsg->cmsg_level = IPPROTO_SCTP; - cmsg->cmsg_type = SCTP_PRINFO; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo)); - prinfo = (struct sctp_prinfo *)CMSG_DATA(cmsg); - memset(prinfo, 0, sizeof(*prinfo)); - prinfo->pr_policy = pinfo->pr_policy; - prinfo->pr_value = pinfo->pr_value; - msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo)); -# else - cmsg = (struct cmsghdr *)cmsgbuf; - cmsg->cmsg_level = IPPROTO_SCTP; - cmsg->cmsg_type = SCTP_SNDRCV; - cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); - sndrcvinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); - memset(sndrcvinfo, 0, sizeof(*sndrcvinfo)); - sndrcvinfo->sinfo_stream = sinfo->snd_sid; - sndrcvinfo->sinfo_flags = sinfo->snd_flags; -# ifdef __FreeBSD__ - sndrcvinfo->sinfo_flags |= pinfo->pr_policy; -# endif - sndrcvinfo->sinfo_ppid = sinfo->snd_ppid; - sndrcvinfo->sinfo_context = sinfo->snd_context; - sndrcvinfo->sinfo_timetolive = pinfo->pr_value; - msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndrcvinfo)); -# endif - - ret = sendmsg(b->num, &msg, 0); - - BIO_clear_retry_flags(b); - if (ret <= 0) { - if (BIO_dgram_should_retry(ret)) { - BIO_set_retry_write(b); - data->_errno = get_last_socket_error(); - } - } - return ret; -} - -static long dgram_sctp_ctrl(BIO *b, int cmd, long num, void *ptr) -{ - long ret = 1; - bio_dgram_sctp_data *data = NULL; - socklen_t sockopt_len = 0; - struct sctp_authkeyid authkeyid; - struct sctp_authkey *authkey = NULL; - - data = (bio_dgram_sctp_data *) b->ptr; - - switch (cmd) { - case BIO_CTRL_DGRAM_QUERY_MTU: - /* - * Set to maximum (2^14) and ignore user input to enable transport - * protocol fragmentation. Returns always 2^14. - */ - data->mtu = 16384; - ret = data->mtu; - break; - case BIO_CTRL_DGRAM_SET_MTU: - /* - * Set to maximum (2^14) and ignore input to enable transport - * protocol fragmentation. Returns always 2^14. - */ - data->mtu = 16384; - ret = data->mtu; - break; - case BIO_CTRL_DGRAM_SET_CONNECTED: - case BIO_CTRL_DGRAM_CONNECT: - /* Returns always -1. */ - ret = -1; - break; - case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT: - /* - * SCTP doesn't need the DTLS timer Returns always 1. - */ - break; - case BIO_CTRL_DGRAM_GET_MTU_OVERHEAD: - /* - * We allow transport protocol fragmentation so this is irrelevant - */ - ret = 0; - break; - case BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE: - if (num > 0) - data->in_handshake = 1; - else - data->in_handshake = 0; - - ret = - setsockopt(b->num, IPPROTO_SCTP, SCTP_NODELAY, - &data->in_handshake, sizeof(int)); - break; - case BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY: - /* - * New shared key for SCTP AUTH. Returns 0 on success, -1 otherwise. - */ - - /* Get active key */ - sockopt_len = sizeof(struct sctp_authkeyid); - ret = - getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, &authkeyid, - &sockopt_len); - if (ret < 0) - break; - - /* Add new key */ - sockopt_len = sizeof(struct sctp_authkey) + 64 * sizeof(uint8_t); - authkey = OPENSSL_malloc(sockopt_len); - if (authkey == NULL) { - ret = -1; - break; - } - memset(authkey, 0, sockopt_len); - authkey->sca_keynumber = authkeyid.scact_keynumber + 1; -# ifndef __FreeBSD__ - /* - * This field is missing in FreeBSD 8.2 and earlier, and FreeBSD 8.3 - * and higher work without it. - */ - authkey->sca_keylength = 64; -# endif - memcpy(&authkey->sca_key[0], ptr, 64 * sizeof(uint8_t)); - - ret = - setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_KEY, authkey, - sockopt_len); - OPENSSL_free(authkey); - authkey = NULL; - if (ret < 0) - break; - - /* Reset active key */ - ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, - &authkeyid, sizeof(struct sctp_authkeyid)); - if (ret < 0) - break; - - break; - case BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY: - /* Returns 0 on success, -1 otherwise. */ - - /* Get active key */ - sockopt_len = sizeof(struct sctp_authkeyid); - ret = - getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, &authkeyid, - &sockopt_len); - if (ret < 0) - break; - - /* Set active key */ - authkeyid.scact_keynumber = authkeyid.scact_keynumber + 1; - ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, - &authkeyid, sizeof(struct sctp_authkeyid)); - if (ret < 0) - break; - - /* - * CCS has been sent, so remember that and fall through to check if - * we need to deactivate an old key - */ - data->ccs_sent = 1; - /* fall-through */ - - case BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD: - /* Returns 0 on success, -1 otherwise. */ - - /* - * Has this command really been called or is this just a - * fall-through? - */ - if (cmd == BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD) - data->ccs_rcvd = 1; - - /* - * CSS has been both, received and sent, so deactivate an old key - */ - if (data->ccs_rcvd == 1 && data->ccs_sent == 1) { - /* Get active key */ - sockopt_len = sizeof(struct sctp_authkeyid); - ret = - getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, - &authkeyid, &sockopt_len); - if (ret < 0) - break; - - /* - * Deactivate key or delete second last key if - * SCTP_AUTHENTICATION_EVENT is not available. - */ - authkeyid.scact_keynumber = authkeyid.scact_keynumber - 1; -# ifdef SCTP_AUTH_DEACTIVATE_KEY - sockopt_len = sizeof(struct sctp_authkeyid); - ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DEACTIVATE_KEY, - &authkeyid, sockopt_len); - if (ret < 0) - break; -# endif -# ifndef SCTP_AUTHENTICATION_EVENT - if (authkeyid.scact_keynumber > 0) { - authkeyid.scact_keynumber = authkeyid.scact_keynumber - 1; - ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DELETE_KEY, - &authkeyid, sizeof(struct sctp_authkeyid)); - if (ret < 0) - break; - } -# endif - - data->ccs_rcvd = 0; - data->ccs_sent = 0; - } - break; - case BIO_CTRL_DGRAM_SCTP_GET_SNDINFO: - /* Returns the size of the copied struct. */ - if (num > (long)sizeof(struct bio_dgram_sctp_sndinfo)) - num = sizeof(struct bio_dgram_sctp_sndinfo); - - memcpy(ptr, &(data->sndinfo), num); - ret = num; - break; - case BIO_CTRL_DGRAM_SCTP_SET_SNDINFO: - /* Returns the size of the copied struct. */ - if (num > (long)sizeof(struct bio_dgram_sctp_sndinfo)) - num = sizeof(struct bio_dgram_sctp_sndinfo); - - memcpy(&(data->sndinfo), ptr, num); - break; - case BIO_CTRL_DGRAM_SCTP_GET_RCVINFO: - /* Returns the size of the copied struct. */ - if (num > (long)sizeof(struct bio_dgram_sctp_rcvinfo)) - num = sizeof(struct bio_dgram_sctp_rcvinfo); - - memcpy(ptr, &data->rcvinfo, num); - - ret = num; - break; - case BIO_CTRL_DGRAM_SCTP_SET_RCVINFO: - /* Returns the size of the copied struct. */ - if (num > (long)sizeof(struct bio_dgram_sctp_rcvinfo)) - num = sizeof(struct bio_dgram_sctp_rcvinfo); - - memcpy(&(data->rcvinfo), ptr, num); - break; - case BIO_CTRL_DGRAM_SCTP_GET_PRINFO: - /* Returns the size of the copied struct. */ - if (num > (long)sizeof(struct bio_dgram_sctp_prinfo)) - num = sizeof(struct bio_dgram_sctp_prinfo); - - memcpy(ptr, &(data->prinfo), num); - ret = num; - break; - case BIO_CTRL_DGRAM_SCTP_SET_PRINFO: - /* Returns the size of the copied struct. */ - if (num > (long)sizeof(struct bio_dgram_sctp_prinfo)) - num = sizeof(struct bio_dgram_sctp_prinfo); - - memcpy(&(data->prinfo), ptr, num); - break; - case BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN: - /* Returns always 1. */ - if (num > 0) - data->save_shutdown = 1; - else - data->save_shutdown = 0; - break; - - default: - /* - * Pass to default ctrl function to process SCTP unspecific commands - */ - ret = dgram_ctrl(b, cmd, num, ptr); - break; - } - return ret; -} - -int BIO_dgram_sctp_notification_cb(BIO *b, - void (*handle_notifications) (BIO *bio, - void - *context, - void *buf), - void *context) -{ - bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr; - - if (handle_notifications != NULL) { - data->handle_notifications = handle_notifications; - data->notification_context = context; - } else - return -1; - - return 0; -} - -/* - * BIO_dgram_sctp_wait_for_dry - Wait for SCTP SENDER_DRY event - * @b: The BIO to check for the dry event - * - * Wait until the peer confirms all packets have been received, and so that - * our kernel doesn't have anything to send anymore. This is only received by - * the peer's kernel, not the application. - * - * Returns: - * -1 on error - * 0 when not dry yet - * 1 when dry - */ -int BIO_dgram_sctp_wait_for_dry(BIO *b) -{ - int is_dry = 0; - int sockflags = 0; - int n, ret; - union sctp_notification snp; - struct msghdr msg; - struct iovec iov; -# ifdef SCTP_EVENT - struct sctp_event event; -# else - struct sctp_event_subscribe event; - socklen_t eventsize; -# endif - bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr; - - /* set sender dry event */ -# ifdef SCTP_EVENT - memset(&event, 0, sizeof(event)); - event.se_assoc_id = 0; - event.se_type = SCTP_SENDER_DRY_EVENT; - event.se_on = 1; - ret = - setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, - sizeof(struct sctp_event)); -# else - eventsize = sizeof(struct sctp_event_subscribe); - ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, &eventsize); - if (ret < 0) - return -1; - - event.sctp_sender_dry_event = 1; - - ret = - setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, - sizeof(struct sctp_event_subscribe)); -# endif - if (ret < 0) - return -1; - - /* peek for notification */ - memset(&snp, 0, sizeof(snp)); - iov.iov_base = (char *)&snp; - iov.iov_len = sizeof(union sctp_notification); - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = NULL; - msg.msg_controllen = 0; - msg.msg_flags = 0; - - n = recvmsg(b->num, &msg, MSG_PEEK); - if (n <= 0) { - if ((n < 0) && (get_last_socket_error() != EAGAIN) - && (get_last_socket_error() != EWOULDBLOCK)) - return -1; - else - return 0; - } - - /* if we find a notification, process it and try again if necessary */ - while (msg.msg_flags & MSG_NOTIFICATION) { - memset(&snp, 0, sizeof(snp)); - iov.iov_base = (char *)&snp; - iov.iov_len = sizeof(union sctp_notification); - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = NULL; - msg.msg_controllen = 0; - msg.msg_flags = 0; - - n = recvmsg(b->num, &msg, 0); - if (n <= 0) { - if ((n < 0) && (get_last_socket_error() != EAGAIN) - && (get_last_socket_error() != EWOULDBLOCK)) - return -1; - else - return is_dry; - } - - if (snp.sn_header.sn_type == SCTP_SENDER_DRY_EVENT) { - is_dry = 1; - - /* disable sender dry event */ -# ifdef SCTP_EVENT - memset(&event, 0, sizeof(event)); - event.se_assoc_id = 0; - event.se_type = SCTP_SENDER_DRY_EVENT; - event.se_on = 0; - ret = - setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, - sizeof(struct sctp_event)); -# else - eventsize = (socklen_t) sizeof(struct sctp_event_subscribe); - ret = - getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, - &eventsize); - if (ret < 0) - return -1; - - event.sctp_sender_dry_event = 0; - - ret = - setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, - sizeof(struct sctp_event_subscribe)); -# endif - if (ret < 0) - return -1; - } -# ifdef SCTP_AUTHENTICATION_EVENT - if (snp.sn_header.sn_type == SCTP_AUTHENTICATION_EVENT) - dgram_sctp_handle_auth_free_key_event(b, &snp); -# endif - - if (data->handle_notifications != NULL) - data->handle_notifications(b, data->notification_context, - (void *)&snp); - - /* found notification, peek again */ - memset(&snp, 0, sizeof(snp)); - iov.iov_base = (char *)&snp; - iov.iov_len = sizeof(union sctp_notification); - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = NULL; - msg.msg_controllen = 0; - msg.msg_flags = 0; - - /* if we have seen the dry already, don't wait */ - if (is_dry) { - sockflags = fcntl(b->num, F_GETFL, 0); - fcntl(b->num, F_SETFL, O_NONBLOCK); - } - - n = recvmsg(b->num, &msg, MSG_PEEK); - - if (is_dry) { - fcntl(b->num, F_SETFL, sockflags); - } - - if (n <= 0) { - if ((n < 0) && (get_last_socket_error() != EAGAIN) - && (get_last_socket_error() != EWOULDBLOCK)) - return -1; - else - return is_dry; - } - } - - /* read anything else */ - return is_dry; -} - -int BIO_dgram_sctp_msg_waiting(BIO *b) -{ - int n, sockflags; - union sctp_notification snp; - struct msghdr msg; - struct iovec iov; - bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr; - - /* Check if there are any messages waiting to be read */ - do { - memset(&snp, 0, sizeof(snp)); - iov.iov_base = (char *)&snp; - iov.iov_len = sizeof(union sctp_notification); - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = NULL; - msg.msg_controllen = 0; - msg.msg_flags = 0; - - sockflags = fcntl(b->num, F_GETFL, 0); - fcntl(b->num, F_SETFL, O_NONBLOCK); - n = recvmsg(b->num, &msg, MSG_PEEK); - fcntl(b->num, F_SETFL, sockflags); - - /* if notification, process and try again */ - if (n > 0 && (msg.msg_flags & MSG_NOTIFICATION)) { -# ifdef SCTP_AUTHENTICATION_EVENT - if (snp.sn_header.sn_type == SCTP_AUTHENTICATION_EVENT) - dgram_sctp_handle_auth_free_key_event(b, &snp); -# endif - - memset(&snp, 0, sizeof(snp)); - iov.iov_base = (char *)&snp; - iov.iov_len = sizeof(union sctp_notification); - msg.msg_name = NULL; - msg.msg_namelen = 0; - msg.msg_iov = &iov; - msg.msg_iovlen = 1; - msg.msg_control = NULL; - msg.msg_controllen = 0; - msg.msg_flags = 0; - n = recvmsg(b->num, &msg, 0); - - if (data->handle_notifications != NULL) - data->handle_notifications(b, data->notification_context, - (void *)&snp); - } - - } while (n > 0 && (msg.msg_flags & MSG_NOTIFICATION)); - - /* Return 1 if there is a message to be read, return 0 otherwise. */ - if (n > 0) - return 1; - else - return 0; -} - -static int dgram_sctp_puts(BIO *bp, const char *str) -{ - int n, ret; - - n = strlen(str); - ret = dgram_sctp_write(bp, str, n); - return ret; -} -# endif - -static int BIO_dgram_should_retry(int i) -{ - int err; - - if ((i == 0) || (i == -1)) { - err = get_last_socket_error(); - -# if defined(OPENSSL_SYS_WINDOWS) - /* - * If the socket return value (i) is -1 and err is unexpectedly 0 at - * this point, the error code was overwritten by another system call - * before this error handling is called. - */ -# endif - - return BIO_dgram_non_fatal_error(err); - } - return 0; -} - -int BIO_dgram_non_fatal_error(int err) -{ - switch (err) { -# if defined(OPENSSL_SYS_WINDOWS) -# if defined(WSAEWOULDBLOCK) - case WSAEWOULDBLOCK: -# endif -# endif - -# ifdef EWOULDBLOCK -# ifdef WSAEWOULDBLOCK -# if WSAEWOULDBLOCK != EWOULDBLOCK - case EWOULDBLOCK: -# endif -# else - case EWOULDBLOCK: -# endif -# endif - -# ifdef EINTR - case EINTR: -# endif - -# ifdef EAGAIN -# if EWOULDBLOCK != EAGAIN - case EAGAIN: -# endif -# endif - -# ifdef EPROTO - case EPROTO: -# endif - -# ifdef EINPROGRESS - case EINPROGRESS: -# endif - -# ifdef EALREADY - case EALREADY: -# endif - - return 1; - default: - break; - } - return 0; -} - -static void get_current_time(struct timeval *t) -{ -# if defined(_WIN32) - SYSTEMTIME st; - union { - unsigned __int64 ul; - FILETIME ft; - } now; - - GetSystemTime(&st); - SystemTimeToFileTime(&st, &now.ft); -# ifdef __MINGW32__ - now.ul -= 116444736000000000ULL; -# else - now.ul -= 116444736000000000UI64; /* re-bias to 1/1/1970 */ -# endif - t->tv_sec = (long)(now.ul / 10000000); - t->tv_usec = ((int)(now.ul % 10000000)) / 10; -# else - gettimeofday(t, NULL); -# endif -} - -#endif + */ + case BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE: + case BIO_CTRL_DGRAM_SET_PEEK_MODE: + data->peekmode = (unsigned int)num; + break; + default: + ret = 0; + break; + } + return ret; +} + +static int dgram_puts(BIO *bp, const char *str) +{ + int n, ret; + + n = strlen(str); + ret = dgram_write(bp, str, n); + return ret; +} + +# ifndef OPENSSL_NO_SCTP +const BIO_METHOD *BIO_s_datagram_sctp(void) +{ + return &methods_dgramp_sctp; +} + +BIO *BIO_new_dgram_sctp(int fd, int close_flag) +{ + BIO *bio; + int ret, optval = 20000; + int auth_data = 0, auth_forward = 0; + unsigned char *p; + struct sctp_authchunk auth; + struct sctp_authchunks *authchunks; + socklen_t sockopt_len; +# ifdef SCTP_AUTHENTICATION_EVENT +# ifdef SCTP_EVENT + struct sctp_event event; +# else + struct sctp_event_subscribe event; +# endif +# endif + + bio = BIO_new(BIO_s_datagram_sctp()); + if (bio == NULL) + return NULL; + BIO_set_fd(bio, fd, close_flag); + + /* Activate SCTP-AUTH for DATA and FORWARD-TSN chunks */ + auth.sauth_chunk = OPENSSL_SCTP_DATA_CHUNK_TYPE; + ret = + setsockopt(fd, IPPROTO_SCTP, SCTP_AUTH_CHUNK, &auth, + sizeof(struct sctp_authchunk)); + if (ret < 0) { + BIO_vfree(bio); + BIOerr(BIO_F_BIO_NEW_DGRAM_SCTP, ERR_R_SYS_LIB); + ERR_add_error_data(1, "Ensure SCTP AUTH chunks are enabled in kernel"); + return NULL; + } + auth.sauth_chunk = OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE; + ret = + setsockopt(fd, IPPROTO_SCTP, SCTP_AUTH_CHUNK, &auth, + sizeof(struct sctp_authchunk)); + if (ret < 0) { + BIO_vfree(bio); + BIOerr(BIO_F_BIO_NEW_DGRAM_SCTP, ERR_R_SYS_LIB); + ERR_add_error_data(1, "Ensure SCTP AUTH chunks are enabled in kernel"); + return NULL; + } + + /* + * Test if activation was successful. When using accept(), SCTP-AUTH has + * to be activated for the listening socket already, otherwise the + * connected socket won't use it. Similarly with connect(): the socket + * prior to connection must be activated for SCTP-AUTH + */ + sockopt_len = (socklen_t) (sizeof(sctp_assoc_t) + 256 * sizeof(uint8_t)); + authchunks = OPENSSL_zalloc(sockopt_len); + if (authchunks == NULL) { + BIO_vfree(bio); + return NULL; + } + ret = getsockopt(fd, IPPROTO_SCTP, SCTP_LOCAL_AUTH_CHUNKS, authchunks, + &sockopt_len); + if (ret < 0) { + OPENSSL_free(authchunks); + BIO_vfree(bio); + return NULL; + } + + for (p = (unsigned char *)authchunks->gauth_chunks; + p < (unsigned char *)authchunks + sockopt_len; + p += sizeof(uint8_t)) { + if (*p == OPENSSL_SCTP_DATA_CHUNK_TYPE) + auth_data = 1; + if (*p == OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE) + auth_forward = 1; + } + + OPENSSL_free(authchunks); + + if (!auth_data || !auth_forward) { + BIO_vfree(bio); + BIOerr(BIO_F_BIO_NEW_DGRAM_SCTP, ERR_R_SYS_LIB); + ERR_add_error_data(1, + "Ensure SCTP AUTH chunks are enabled on the " + "underlying socket"); + return NULL; + } + +# ifdef SCTP_AUTHENTICATION_EVENT +# ifdef SCTP_EVENT + memset(&event, 0, sizeof(event)); + event.se_assoc_id = 0; + event.se_type = SCTP_AUTHENTICATION_EVENT; + event.se_on = 1; + ret = + setsockopt(fd, IPPROTO_SCTP, SCTP_EVENT, &event, + sizeof(struct sctp_event)); + if (ret < 0) { + BIO_vfree(bio); + return NULL; + } +# else + sockopt_len = (socklen_t) sizeof(struct sctp_event_subscribe); + ret = getsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, &sockopt_len); + if (ret < 0) { + BIO_vfree(bio); + return NULL; + } + + event.sctp_authentication_event = 1; + + ret = + setsockopt(fd, IPPROTO_SCTP, SCTP_EVENTS, &event, + sizeof(struct sctp_event_subscribe)); + if (ret < 0) { + BIO_vfree(bio); + return NULL; + } +# endif +# endif + + /* + * Disable partial delivery by setting the min size larger than the max + * record size of 2^14 + 2048 + 13 + */ + ret = + setsockopt(fd, IPPROTO_SCTP, SCTP_PARTIAL_DELIVERY_POINT, &optval, + sizeof(optval)); + if (ret < 0) { + BIO_vfree(bio); + return NULL; + } + + return bio; +} + +int BIO_dgram_is_sctp(BIO *bio) +{ + return (BIO_method_type(bio) == BIO_TYPE_DGRAM_SCTP); +} + +static int dgram_sctp_new(BIO *bi) +{ + bio_dgram_sctp_data *data = NULL; + + bi->init = 0; + bi->num = 0; + if ((data = OPENSSL_zalloc(sizeof(*data))) == NULL) { + BIOerr(BIO_F_DGRAM_SCTP_NEW, ERR_R_MALLOC_FAILURE); + return 0; + } +# ifdef SCTP_PR_SCTP_NONE + data->prinfo.pr_policy = SCTP_PR_SCTP_NONE; +# endif + bi->ptr = data; + + bi->flags = 0; + return 1; +} + +static int dgram_sctp_free(BIO *a) +{ + bio_dgram_sctp_data *data; + + if (a == NULL) + return 0; + if (!dgram_clear(a)) + return 0; + + data = (bio_dgram_sctp_data *) a->ptr; + if (data != NULL) + OPENSSL_free(data); + + return 1; +} + +# ifdef SCTP_AUTHENTICATION_EVENT +void dgram_sctp_handle_auth_free_key_event(BIO *b, + union sctp_notification *snp) +{ + int ret; + struct sctp_authkey_event *authkeyevent = &snp->sn_auth_event; + + if (authkeyevent->auth_indication == SCTP_AUTH_FREE_KEY) { + struct sctp_authkeyid authkeyid; + + /* delete key */ + authkeyid.scact_keynumber = authkeyevent->auth_keynumber; + ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DELETE_KEY, + &authkeyid, sizeof(struct sctp_authkeyid)); + } +} +# endif + +static int dgram_sctp_read(BIO *b, char *out, int outl) +{ + int ret = 0, n = 0, i, optval; + socklen_t optlen; + bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr; + union sctp_notification *snp; + struct msghdr msg; + struct iovec iov; + struct cmsghdr *cmsg; + char cmsgbuf[512]; + + if (out != NULL) { + clear_socket_error(); + + do { + memset(&data->rcvinfo, 0, sizeof(data->rcvinfo)); + iov.iov_base = out; + iov.iov_len = outl; + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = cmsgbuf; + msg.msg_controllen = 512; + msg.msg_flags = 0; + n = recvmsg(b->num, &msg, 0); + + if (n <= 0) { + if (n < 0) + ret = n; + break; + } + + if (msg.msg_controllen > 0) { + for (cmsg = CMSG_FIRSTHDR(&msg); cmsg; + cmsg = CMSG_NXTHDR(&msg, cmsg)) { + if (cmsg->cmsg_level != IPPROTO_SCTP) + continue; +# ifdef SCTP_RCVINFO + if (cmsg->cmsg_type == SCTP_RCVINFO) { + struct sctp_rcvinfo *rcvinfo; + + rcvinfo = (struct sctp_rcvinfo *)CMSG_DATA(cmsg); + data->rcvinfo.rcv_sid = rcvinfo->rcv_sid; + data->rcvinfo.rcv_ssn = rcvinfo->rcv_ssn; + data->rcvinfo.rcv_flags = rcvinfo->rcv_flags; + data->rcvinfo.rcv_ppid = rcvinfo->rcv_ppid; + data->rcvinfo.rcv_tsn = rcvinfo->rcv_tsn; + data->rcvinfo.rcv_cumtsn = rcvinfo->rcv_cumtsn; + data->rcvinfo.rcv_context = rcvinfo->rcv_context; + } +# endif +# ifdef SCTP_SNDRCV + if (cmsg->cmsg_type == SCTP_SNDRCV) { + struct sctp_sndrcvinfo *sndrcvinfo; + + sndrcvinfo = + (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); + data->rcvinfo.rcv_sid = sndrcvinfo->sinfo_stream; + data->rcvinfo.rcv_ssn = sndrcvinfo->sinfo_ssn; + data->rcvinfo.rcv_flags = sndrcvinfo->sinfo_flags; + data->rcvinfo.rcv_ppid = sndrcvinfo->sinfo_ppid; + data->rcvinfo.rcv_tsn = sndrcvinfo->sinfo_tsn; + data->rcvinfo.rcv_cumtsn = sndrcvinfo->sinfo_cumtsn; + data->rcvinfo.rcv_context = sndrcvinfo->sinfo_context; + } +# endif + } + } + + if (msg.msg_flags & MSG_NOTIFICATION) { + snp = (union sctp_notification *)out; + if (snp->sn_header.sn_type == SCTP_SENDER_DRY_EVENT) { +# ifdef SCTP_EVENT + struct sctp_event event; +# else + struct sctp_event_subscribe event; + socklen_t eventsize; +# endif + + /* disable sender dry event */ +# ifdef SCTP_EVENT + memset(&event, 0, sizeof(event)); + event.se_assoc_id = 0; + event.se_type = SCTP_SENDER_DRY_EVENT; + event.se_on = 0; + i = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, + sizeof(struct sctp_event)); + if (i < 0) { + ret = i; + break; + } +# else + eventsize = sizeof(struct sctp_event_subscribe); + i = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, + &eventsize); + if (i < 0) { + ret = i; + break; + } + + event.sctp_sender_dry_event = 0; + + i = setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, + sizeof(struct sctp_event_subscribe)); + if (i < 0) { + ret = i; + break; + } +# endif + } +# ifdef SCTP_AUTHENTICATION_EVENT + if (snp->sn_header.sn_type == SCTP_AUTHENTICATION_EVENT) + dgram_sctp_handle_auth_free_key_event(b, snp); +# endif + + if (data->handle_notifications != NULL) + data->handle_notifications(b, data->notification_context, + (void *)out); + + memset(out, 0, outl); + } else + ret += n; + } + while ((msg.msg_flags & MSG_NOTIFICATION) && (msg.msg_flags & MSG_EOR) + && (ret < outl)); + + if (ret > 0 && !(msg.msg_flags & MSG_EOR)) { + /* Partial message read, this should never happen! */ + + /* + * The buffer was too small, this means the peer sent a message + * that was larger than allowed. + */ + if (ret == outl) + return -1; + + /* + * Test if socket buffer can handle max record size (2^14 + 2048 + * + 13) + */ + optlen = (socklen_t) sizeof(int); + ret = getsockopt(b->num, SOL_SOCKET, SO_RCVBUF, &optval, &optlen); + if (ret >= 0) + OPENSSL_assert(optval >= 18445); + + /* + * Test if SCTP doesn't partially deliver below max record size + * (2^14 + 2048 + 13) + */ + optlen = (socklen_t) sizeof(int); + ret = + getsockopt(b->num, IPPROTO_SCTP, SCTP_PARTIAL_DELIVERY_POINT, + &optval, &optlen); + if (ret >= 0) + OPENSSL_assert(optval >= 18445); + + /* + * Partially delivered notification??? Probably a bug.... + */ + OPENSSL_assert(!(msg.msg_flags & MSG_NOTIFICATION)); + + /* + * Everything seems ok till now, so it's most likely a message + * dropped by PR-SCTP. + */ + memset(out, 0, outl); + BIO_set_retry_read(b); + return -1; + } + + BIO_clear_retry_flags(b); + if (ret < 0) { + if (BIO_dgram_should_retry(ret)) { + BIO_set_retry_read(b); + data->_errno = get_last_socket_error(); + } + } + + /* Test if peer uses SCTP-AUTH before continuing */ + if (!data->peer_auth_tested) { + int ii, auth_data = 0, auth_forward = 0; + unsigned char *p; + struct sctp_authchunks *authchunks; + + optlen = + (socklen_t) (sizeof(sctp_assoc_t) + 256 * sizeof(uint8_t)); + authchunks = OPENSSL_malloc(optlen); + if (authchunks == NULL) { + BIOerr(BIO_F_DGRAM_SCTP_READ, ERR_R_MALLOC_FAILURE); + return -1; + } + memset(authchunks, 0, optlen); + ii = getsockopt(b->num, IPPROTO_SCTP, SCTP_PEER_AUTH_CHUNKS, + authchunks, &optlen); + + if (ii >= 0) + for (p = (unsigned char *)authchunks->gauth_chunks; + p < (unsigned char *)authchunks + optlen; + p += sizeof(uint8_t)) { + if (*p == OPENSSL_SCTP_DATA_CHUNK_TYPE) + auth_data = 1; + if (*p == OPENSSL_SCTP_FORWARD_CUM_TSN_CHUNK_TYPE) + auth_forward = 1; + } + + OPENSSL_free(authchunks); + + if (!auth_data || !auth_forward) { + BIOerr(BIO_F_DGRAM_SCTP_READ, BIO_R_CONNECT_ERROR); + return -1; + } + + data->peer_auth_tested = 1; + } + } + return ret; +} + +/* + * dgram_sctp_write - send message on SCTP socket + * @b: BIO to write to + * @in: data to send + * @inl: amount of bytes in @in to send + * + * Returns -1 on error or the sent amount of bytes on success + */ +static int dgram_sctp_write(BIO *b, const char *in, int inl) +{ + int ret; + bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr; + struct bio_dgram_sctp_sndinfo *sinfo = &(data->sndinfo); + struct bio_dgram_sctp_prinfo *pinfo = &(data->prinfo); + struct bio_dgram_sctp_sndinfo handshake_sinfo; + struct iovec iov[1]; + struct msghdr msg; + struct cmsghdr *cmsg; +# if defined(SCTP_SNDINFO) && defined(SCTP_PRINFO) + char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndinfo)) + + CMSG_SPACE(sizeof(struct sctp_prinfo))]; + struct sctp_sndinfo *sndinfo; + struct sctp_prinfo *prinfo; +# else + char cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndrcvinfo))]; + struct sctp_sndrcvinfo *sndrcvinfo; +# endif + + clear_socket_error(); + + /* + * If we're send anything else than application data, disable all user + * parameters and flags. + */ + if (in[0] != 23) { + memset(&handshake_sinfo, 0, sizeof(handshake_sinfo)); +# ifdef SCTP_SACK_IMMEDIATELY + handshake_sinfo.snd_flags = SCTP_SACK_IMMEDIATELY; +# endif + sinfo = &handshake_sinfo; + } + + /* We can only send a shutdown alert if the socket is dry */ + if (data->save_shutdown) { + ret = BIO_dgram_sctp_wait_for_dry(b); + if (ret < 0) + return -1; + if (ret == 0) { + BIO_clear_retry_flags(b); + BIO_set_retry_write(b); + return -1; + } + } + + iov[0].iov_base = (char *)in; + iov[0].iov_len = inl; + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = iov; + msg.msg_iovlen = 1; + msg.msg_control = (caddr_t) cmsgbuf; + msg.msg_controllen = 0; + msg.msg_flags = 0; +# if defined(SCTP_SNDINFO) && defined(SCTP_PRINFO) + cmsg = (struct cmsghdr *)cmsgbuf; + cmsg->cmsg_level = IPPROTO_SCTP; + cmsg->cmsg_type = SCTP_SNDINFO; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndinfo)); + sndinfo = (struct sctp_sndinfo *)CMSG_DATA(cmsg); + memset(sndinfo, 0, sizeof(*sndinfo)); + sndinfo->snd_sid = sinfo->snd_sid; + sndinfo->snd_flags = sinfo->snd_flags; + sndinfo->snd_ppid = sinfo->snd_ppid; + sndinfo->snd_context = sinfo->snd_context; + msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndinfo)); + + cmsg = + (struct cmsghdr *)&cmsgbuf[CMSG_SPACE(sizeof(struct sctp_sndinfo))]; + cmsg->cmsg_level = IPPROTO_SCTP; + cmsg->cmsg_type = SCTP_PRINFO; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_prinfo)); + prinfo = (struct sctp_prinfo *)CMSG_DATA(cmsg); + memset(prinfo, 0, sizeof(*prinfo)); + prinfo->pr_policy = pinfo->pr_policy; + prinfo->pr_value = pinfo->pr_value; + msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_prinfo)); +# else + cmsg = (struct cmsghdr *)cmsgbuf; + cmsg->cmsg_level = IPPROTO_SCTP; + cmsg->cmsg_type = SCTP_SNDRCV; + cmsg->cmsg_len = CMSG_LEN(sizeof(struct sctp_sndrcvinfo)); + sndrcvinfo = (struct sctp_sndrcvinfo *)CMSG_DATA(cmsg); + memset(sndrcvinfo, 0, sizeof(*sndrcvinfo)); + sndrcvinfo->sinfo_stream = sinfo->snd_sid; + sndrcvinfo->sinfo_flags = sinfo->snd_flags; +# ifdef __FreeBSD__ + sndrcvinfo->sinfo_flags |= pinfo->pr_policy; +# endif + sndrcvinfo->sinfo_ppid = sinfo->snd_ppid; + sndrcvinfo->sinfo_context = sinfo->snd_context; + sndrcvinfo->sinfo_timetolive = pinfo->pr_value; + msg.msg_controllen += CMSG_SPACE(sizeof(struct sctp_sndrcvinfo)); +# endif + + ret = sendmsg(b->num, &msg, 0); + + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (BIO_dgram_should_retry(ret)) { + BIO_set_retry_write(b); + data->_errno = get_last_socket_error(); + } + } + return ret; +} + +static long dgram_sctp_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + long ret = 1; + bio_dgram_sctp_data *data = NULL; + socklen_t sockopt_len = 0; + struct sctp_authkeyid authkeyid; + struct sctp_authkey *authkey = NULL; + + data = (bio_dgram_sctp_data *) b->ptr; + + switch (cmd) { + case BIO_CTRL_DGRAM_QUERY_MTU: + /* + * Set to maximum (2^14) and ignore user input to enable transport + * protocol fragmentation. Returns always 2^14. + */ + data->mtu = 16384; + ret = data->mtu; + break; + case BIO_CTRL_DGRAM_SET_MTU: + /* + * Set to maximum (2^14) and ignore input to enable transport + * protocol fragmentation. Returns always 2^14. + */ + data->mtu = 16384; + ret = data->mtu; + break; + case BIO_CTRL_DGRAM_SET_CONNECTED: + case BIO_CTRL_DGRAM_CONNECT: + /* Returns always -1. */ + ret = -1; + break; + case BIO_CTRL_DGRAM_SET_NEXT_TIMEOUT: + /* + * SCTP doesn't need the DTLS timer Returns always 1. + */ + break; + case BIO_CTRL_DGRAM_GET_MTU_OVERHEAD: + /* + * We allow transport protocol fragmentation so this is irrelevant + */ + ret = 0; + break; + case BIO_CTRL_DGRAM_SCTP_SET_IN_HANDSHAKE: + if (num > 0) + data->in_handshake = 1; + else + data->in_handshake = 0; + + ret = + setsockopt(b->num, IPPROTO_SCTP, SCTP_NODELAY, + &data->in_handshake, sizeof(int)); + break; + case BIO_CTRL_DGRAM_SCTP_ADD_AUTH_KEY: + /* + * New shared key for SCTP AUTH. Returns 0 on success, -1 otherwise. + */ + + /* Get active key */ + sockopt_len = sizeof(struct sctp_authkeyid); + ret = + getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, &authkeyid, + &sockopt_len); + if (ret < 0) + break; + + /* Add new key */ + sockopt_len = sizeof(struct sctp_authkey) + 64 * sizeof(uint8_t); + authkey = OPENSSL_malloc(sockopt_len); + if (authkey == NULL) { + ret = -1; + break; + } + memset(authkey, 0, sockopt_len); + authkey->sca_keynumber = authkeyid.scact_keynumber + 1; +# ifndef __FreeBSD__ + /* + * This field is missing in FreeBSD 8.2 and earlier, and FreeBSD 8.3 + * and higher work without it. + */ + authkey->sca_keylength = 64; +# endif + memcpy(&authkey->sca_key[0], ptr, 64 * sizeof(uint8_t)); + + ret = + setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_KEY, authkey, + sockopt_len); + OPENSSL_free(authkey); + authkey = NULL; + if (ret < 0) + break; + + /* Reset active key */ + ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, + &authkeyid, sizeof(struct sctp_authkeyid)); + if (ret < 0) + break; + + break; + case BIO_CTRL_DGRAM_SCTP_NEXT_AUTH_KEY: + /* Returns 0 on success, -1 otherwise. */ + + /* Get active key */ + sockopt_len = sizeof(struct sctp_authkeyid); + ret = + getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, &authkeyid, + &sockopt_len); + if (ret < 0) + break; + + /* Set active key */ + authkeyid.scact_keynumber = authkeyid.scact_keynumber + 1; + ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, + &authkeyid, sizeof(struct sctp_authkeyid)); + if (ret < 0) + break; + + /* + * CCS has been sent, so remember that and fall through to check if + * we need to deactivate an old key + */ + data->ccs_sent = 1; + /* fall-through */ + + case BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD: + /* Returns 0 on success, -1 otherwise. */ + + /* + * Has this command really been called or is this just a + * fall-through? + */ + if (cmd == BIO_CTRL_DGRAM_SCTP_AUTH_CCS_RCVD) + data->ccs_rcvd = 1; + + /* + * CSS has been both, received and sent, so deactivate an old key + */ + if (data->ccs_rcvd == 1 && data->ccs_sent == 1) { + /* Get active key */ + sockopt_len = sizeof(struct sctp_authkeyid); + ret = + getsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_ACTIVE_KEY, + &authkeyid, &sockopt_len); + if (ret < 0) + break; + + /* + * Deactivate key or delete second last key if + * SCTP_AUTHENTICATION_EVENT is not available. + */ + authkeyid.scact_keynumber = authkeyid.scact_keynumber - 1; +# ifdef SCTP_AUTH_DEACTIVATE_KEY + sockopt_len = sizeof(struct sctp_authkeyid); + ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DEACTIVATE_KEY, + &authkeyid, sockopt_len); + if (ret < 0) + break; +# endif +# ifndef SCTP_AUTHENTICATION_EVENT + if (authkeyid.scact_keynumber > 0) { + authkeyid.scact_keynumber = authkeyid.scact_keynumber - 1; + ret = setsockopt(b->num, IPPROTO_SCTP, SCTP_AUTH_DELETE_KEY, + &authkeyid, sizeof(struct sctp_authkeyid)); + if (ret < 0) + break; + } +# endif + + data->ccs_rcvd = 0; + data->ccs_sent = 0; + } + break; + case BIO_CTRL_DGRAM_SCTP_GET_SNDINFO: + /* Returns the size of the copied struct. */ + if (num > (long)sizeof(struct bio_dgram_sctp_sndinfo)) + num = sizeof(struct bio_dgram_sctp_sndinfo); + + memcpy(ptr, &(data->sndinfo), num); + ret = num; + break; + case BIO_CTRL_DGRAM_SCTP_SET_SNDINFO: + /* Returns the size of the copied struct. */ + if (num > (long)sizeof(struct bio_dgram_sctp_sndinfo)) + num = sizeof(struct bio_dgram_sctp_sndinfo); + + memcpy(&(data->sndinfo), ptr, num); + break; + case BIO_CTRL_DGRAM_SCTP_GET_RCVINFO: + /* Returns the size of the copied struct. */ + if (num > (long)sizeof(struct bio_dgram_sctp_rcvinfo)) + num = sizeof(struct bio_dgram_sctp_rcvinfo); + + memcpy(ptr, &data->rcvinfo, num); + + ret = num; + break; + case BIO_CTRL_DGRAM_SCTP_SET_RCVINFO: + /* Returns the size of the copied struct. */ + if (num > (long)sizeof(struct bio_dgram_sctp_rcvinfo)) + num = sizeof(struct bio_dgram_sctp_rcvinfo); + + memcpy(&(data->rcvinfo), ptr, num); + break; + case BIO_CTRL_DGRAM_SCTP_GET_PRINFO: + /* Returns the size of the copied struct. */ + if (num > (long)sizeof(struct bio_dgram_sctp_prinfo)) + num = sizeof(struct bio_dgram_sctp_prinfo); + + memcpy(ptr, &(data->prinfo), num); + ret = num; + break; + case BIO_CTRL_DGRAM_SCTP_SET_PRINFO: + /* Returns the size of the copied struct. */ + if (num > (long)sizeof(struct bio_dgram_sctp_prinfo)) + num = sizeof(struct bio_dgram_sctp_prinfo); + + memcpy(&(data->prinfo), ptr, num); + break; + case BIO_CTRL_DGRAM_SCTP_SAVE_SHUTDOWN: + /* Returns always 1. */ + if (num > 0) + data->save_shutdown = 1; + else + data->save_shutdown = 0; + break; + + default: + /* + * Pass to default ctrl function to process SCTP unspecific commands + */ + ret = dgram_ctrl(b, cmd, num, ptr); + break; + } + return ret; +} + +int BIO_dgram_sctp_notification_cb(BIO *b, + void (*handle_notifications) (BIO *bio, + void + *context, + void *buf), + void *context) +{ + bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr; + + if (handle_notifications != NULL) { + data->handle_notifications = handle_notifications; + data->notification_context = context; + } else + return -1; + + return 0; +} + +/* + * BIO_dgram_sctp_wait_for_dry - Wait for SCTP SENDER_DRY event + * @b: The BIO to check for the dry event + * + * Wait until the peer confirms all packets have been received, and so that + * our kernel doesn't have anything to send anymore. This is only received by + * the peer's kernel, not the application. + * + * Returns: + * -1 on error + * 0 when not dry yet + * 1 when dry + */ +int BIO_dgram_sctp_wait_for_dry(BIO *b) +{ + int is_dry = 0; + int sockflags = 0; + int n, ret; + union sctp_notification snp; + struct msghdr msg; + struct iovec iov; +# ifdef SCTP_EVENT + struct sctp_event event; +# else + struct sctp_event_subscribe event; + socklen_t eventsize; +# endif + bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr; + + /* set sender dry event */ +# ifdef SCTP_EVENT + memset(&event, 0, sizeof(event)); + event.se_assoc_id = 0; + event.se_type = SCTP_SENDER_DRY_EVENT; + event.se_on = 1; + ret = + setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, + sizeof(struct sctp_event)); +# else + eventsize = sizeof(struct sctp_event_subscribe); + ret = getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, &eventsize); + if (ret < 0) + return -1; + + event.sctp_sender_dry_event = 1; + + ret = + setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, + sizeof(struct sctp_event_subscribe)); +# endif + if (ret < 0) + return -1; + + /* peek for notification */ + memset(&snp, 0, sizeof(snp)); + iov.iov_base = (char *)&snp; + iov.iov_len = sizeof(union sctp_notification); + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + + n = recvmsg(b->num, &msg, MSG_PEEK); + if (n <= 0) { + if ((n < 0) && (get_last_socket_error() != EAGAIN) + && (get_last_socket_error() != EWOULDBLOCK)) + return -1; + else + return 0; + } + + /* if we find a notification, process it and try again if necessary */ + while (msg.msg_flags & MSG_NOTIFICATION) { + memset(&snp, 0, sizeof(snp)); + iov.iov_base = (char *)&snp; + iov.iov_len = sizeof(union sctp_notification); + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + + n = recvmsg(b->num, &msg, 0); + if (n <= 0) { + if ((n < 0) && (get_last_socket_error() != EAGAIN) + && (get_last_socket_error() != EWOULDBLOCK)) + return -1; + else + return is_dry; + } + + if (snp.sn_header.sn_type == SCTP_SENDER_DRY_EVENT) { + is_dry = 1; + + /* disable sender dry event */ +# ifdef SCTP_EVENT + memset(&event, 0, sizeof(event)); + event.se_assoc_id = 0; + event.se_type = SCTP_SENDER_DRY_EVENT; + event.se_on = 0; + ret = + setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENT, &event, + sizeof(struct sctp_event)); +# else + eventsize = (socklen_t) sizeof(struct sctp_event_subscribe); + ret = + getsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, + &eventsize); + if (ret < 0) + return -1; + + event.sctp_sender_dry_event = 0; + + ret = + setsockopt(b->num, IPPROTO_SCTP, SCTP_EVENTS, &event, + sizeof(struct sctp_event_subscribe)); +# endif + if (ret < 0) + return -1; + } +# ifdef SCTP_AUTHENTICATION_EVENT + if (snp.sn_header.sn_type == SCTP_AUTHENTICATION_EVENT) + dgram_sctp_handle_auth_free_key_event(b, &snp); +# endif + + if (data->handle_notifications != NULL) + data->handle_notifications(b, data->notification_context, + (void *)&snp); + + /* found notification, peek again */ + memset(&snp, 0, sizeof(snp)); + iov.iov_base = (char *)&snp; + iov.iov_len = sizeof(union sctp_notification); + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + + /* if we have seen the dry already, don't wait */ + if (is_dry) { + sockflags = fcntl(b->num, F_GETFL, 0); + fcntl(b->num, F_SETFL, O_NONBLOCK); + } + + n = recvmsg(b->num, &msg, MSG_PEEK); + + if (is_dry) { + fcntl(b->num, F_SETFL, sockflags); + } + + if (n <= 0) { + if ((n < 0) && (get_last_socket_error() != EAGAIN) + && (get_last_socket_error() != EWOULDBLOCK)) + return -1; + else + return is_dry; + } + } + + /* read anything else */ + return is_dry; +} + +int BIO_dgram_sctp_msg_waiting(BIO *b) +{ + int n, sockflags; + union sctp_notification snp; + struct msghdr msg; + struct iovec iov; + bio_dgram_sctp_data *data = (bio_dgram_sctp_data *) b->ptr; + + /* Check if there are any messages waiting to be read */ + do { + memset(&snp, 0, sizeof(snp)); + iov.iov_base = (char *)&snp; + iov.iov_len = sizeof(union sctp_notification); + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + + sockflags = fcntl(b->num, F_GETFL, 0); + fcntl(b->num, F_SETFL, O_NONBLOCK); + n = recvmsg(b->num, &msg, MSG_PEEK); + fcntl(b->num, F_SETFL, sockflags); + + /* if notification, process and try again */ + if (n > 0 && (msg.msg_flags & MSG_NOTIFICATION)) { +# ifdef SCTP_AUTHENTICATION_EVENT + if (snp.sn_header.sn_type == SCTP_AUTHENTICATION_EVENT) + dgram_sctp_handle_auth_free_key_event(b, &snp); +# endif + + memset(&snp, 0, sizeof(snp)); + iov.iov_base = (char *)&snp; + iov.iov_len = sizeof(union sctp_notification); + msg.msg_name = NULL; + msg.msg_namelen = 0; + msg.msg_iov = &iov; + msg.msg_iovlen = 1; + msg.msg_control = NULL; + msg.msg_controllen = 0; + msg.msg_flags = 0; + n = recvmsg(b->num, &msg, 0); + + if (data->handle_notifications != NULL) + data->handle_notifications(b, data->notification_context, + (void *)&snp); + } + + } while (n > 0 && (msg.msg_flags & MSG_NOTIFICATION)); + + /* Return 1 if there is a message to be read, return 0 otherwise. */ + if (n > 0) + return 1; + else + return 0; +} + +static int dgram_sctp_puts(BIO *bp, const char *str) +{ + int n, ret; + + n = strlen(str); + ret = dgram_sctp_write(bp, str, n); + return ret; +} +# endif + +static int BIO_dgram_should_retry(int i) +{ + int err; + + if ((i == 0) || (i == -1)) { + err = get_last_socket_error(); + +# if defined(OPENSSL_SYS_WINDOWS) + /* + * If the socket return value (i) is -1 and err is unexpectedly 0 at + * this point, the error code was overwritten by another system call + * before this error handling is called. + */ +# endif + + return BIO_dgram_non_fatal_error(err); + } + return 0; +} + +int BIO_dgram_non_fatal_error(int err) +{ + switch (err) { +# if defined(OPENSSL_SYS_WINDOWS) +# if defined(WSAEWOULDBLOCK) + case WSAEWOULDBLOCK: +# endif +# endif + +# ifdef EWOULDBLOCK +# ifdef WSAEWOULDBLOCK +# if WSAEWOULDBLOCK != EWOULDBLOCK + case EWOULDBLOCK: +# endif +# else + case EWOULDBLOCK: +# endif +# endif + +# ifdef EINTR + case EINTR: +# endif + +# ifdef EAGAIN +# if EWOULDBLOCK != EAGAIN + case EAGAIN: +# endif +# endif + +# ifdef EPROTO + case EPROTO: +# endif + +# ifdef EINPROGRESS + case EINPROGRESS: +# endif + +# ifdef EALREADY + case EALREADY: +# endif + + return 1; + default: + break; + } + return 0; +} + +static void get_current_time(struct timeval *t) +{ +# if defined(_WIN32) + SYSTEMTIME st; + union { + unsigned __int64 ul; + FILETIME ft; + } now; + + GetSystemTime(&st); + SystemTimeToFileTime(&st, &now.ft); +# ifdef __MINGW32__ + now.ul -= 116444736000000000ULL; +# else + now.ul -= 116444736000000000UI64; /* re-bias to 1/1/1970 */ +# endif + t->tv_sec = (long)(now.ul / 10000000); + t->tv_usec = ((int)(now.ul % 10000000)) / 10; +# else + gettimeofday(t, NULL); +# endif +} + +#endif diff --git a/contrib/libs/openssl/crypto/bio/bss_fd.c b/contrib/libs/openssl/crypto/bio/bss_fd.c index 37702b778a..ccbe1626ba 100644 --- a/contrib/libs/openssl/crypto/bio/bss_fd.c +++ b/contrib/libs/openssl/crypto/bio/bss_fd.c @@ -1,285 +1,285 @@ -/* +/* * Copyright 1995-2020 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 - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -#include <stdio.h> -#include <errno.h> - + * + * Licensed under the OpenSSL license (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 <stdio.h> +#include <errno.h> + #include "bio_local.h" - -#if defined(OPENSSL_NO_POSIX_IO) -/* - * Dummy placeholder for BIO_s_fd... - */ -BIO *BIO_new_fd(int fd, int close_flag) -{ - return NULL; -} - -int BIO_fd_non_fatal_error(int err) -{ - return 0; -} - -int BIO_fd_should_retry(int i) -{ - return 0; -} - -const BIO_METHOD *BIO_s_fd(void) -{ - return NULL; -} -#else -/* - * As for unconditional usage of "UPLINK" interface in this module. - * Trouble is that unlike Unix file descriptors [which are indexes - * in kernel-side per-process table], corresponding descriptors on - * platforms which require "UPLINK" interface seem to be indexes - * in a user-land, non-global table. Well, in fact they are indexes - * in stdio _iob[], and recall that _iob[] was the very reason why - * "UPLINK" interface was introduced in first place. But one way on - * another. Neither libcrypto or libssl use this BIO meaning that - * file descriptors can only be provided by application. Therefore - * "UPLINK" calls are due... - */ -static int fd_write(BIO *h, const char *buf, int num); -static int fd_read(BIO *h, char *buf, int size); -static int fd_puts(BIO *h, const char *str); -static int fd_gets(BIO *h, char *buf, int size); -static long fd_ctrl(BIO *h, int cmd, long arg1, void *arg2); -static int fd_new(BIO *h); -static int fd_free(BIO *data); -int BIO_fd_should_retry(int s); - -static const BIO_METHOD methods_fdp = { - BIO_TYPE_FD, - "file descriptor", - /* TODO: Convert to new style write function */ - bwrite_conv, - fd_write, - /* TODO: Convert to new style read function */ - bread_conv, - fd_read, - fd_puts, - fd_gets, - fd_ctrl, - fd_new, - fd_free, - NULL, /* fd_callback_ctrl */ -}; - -const BIO_METHOD *BIO_s_fd(void) -{ - return &methods_fdp; -} - -BIO *BIO_new_fd(int fd, int close_flag) -{ - BIO *ret; - ret = BIO_new(BIO_s_fd()); - if (ret == NULL) - return NULL; - BIO_set_fd(ret, fd, close_flag); - return ret; -} - -static int fd_new(BIO *bi) -{ - bi->init = 0; - bi->num = -1; - bi->ptr = NULL; - bi->flags = BIO_FLAGS_UPLINK; /* essentially redundant */ - return 1; -} - -static int fd_free(BIO *a) -{ - if (a == NULL) - return 0; - if (a->shutdown) { - if (a->init) { - UP_close(a->num); - } - a->init = 0; - a->flags = BIO_FLAGS_UPLINK; - } - return 1; -} - -static int fd_read(BIO *b, char *out, int outl) -{ - int ret = 0; - - if (out != NULL) { - clear_sys_error(); - ret = UP_read(b->num, out, outl); - BIO_clear_retry_flags(b); - if (ret <= 0) { - if (BIO_fd_should_retry(ret)) - BIO_set_retry_read(b); + +#if defined(OPENSSL_NO_POSIX_IO) +/* + * Dummy placeholder for BIO_s_fd... + */ +BIO *BIO_new_fd(int fd, int close_flag) +{ + return NULL; +} + +int BIO_fd_non_fatal_error(int err) +{ + return 0; +} + +int BIO_fd_should_retry(int i) +{ + return 0; +} + +const BIO_METHOD *BIO_s_fd(void) +{ + return NULL; +} +#else +/* + * As for unconditional usage of "UPLINK" interface in this module. + * Trouble is that unlike Unix file descriptors [which are indexes + * in kernel-side per-process table], corresponding descriptors on + * platforms which require "UPLINK" interface seem to be indexes + * in a user-land, non-global table. Well, in fact they are indexes + * in stdio _iob[], and recall that _iob[] was the very reason why + * "UPLINK" interface was introduced in first place. But one way on + * another. Neither libcrypto or libssl use this BIO meaning that + * file descriptors can only be provided by application. Therefore + * "UPLINK" calls are due... + */ +static int fd_write(BIO *h, const char *buf, int num); +static int fd_read(BIO *h, char *buf, int size); +static int fd_puts(BIO *h, const char *str); +static int fd_gets(BIO *h, char *buf, int size); +static long fd_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int fd_new(BIO *h); +static int fd_free(BIO *data); +int BIO_fd_should_retry(int s); + +static const BIO_METHOD methods_fdp = { + BIO_TYPE_FD, + "file descriptor", + /* TODO: Convert to new style write function */ + bwrite_conv, + fd_write, + /* TODO: Convert to new style read function */ + bread_conv, + fd_read, + fd_puts, + fd_gets, + fd_ctrl, + fd_new, + fd_free, + NULL, /* fd_callback_ctrl */ +}; + +const BIO_METHOD *BIO_s_fd(void) +{ + return &methods_fdp; +} + +BIO *BIO_new_fd(int fd, int close_flag) +{ + BIO *ret; + ret = BIO_new(BIO_s_fd()); + if (ret == NULL) + return NULL; + BIO_set_fd(ret, fd, close_flag); + return ret; +} + +static int fd_new(BIO *bi) +{ + bi->init = 0; + bi->num = -1; + bi->ptr = NULL; + bi->flags = BIO_FLAGS_UPLINK; /* essentially redundant */ + return 1; +} + +static int fd_free(BIO *a) +{ + if (a == NULL) + return 0; + if (a->shutdown) { + if (a->init) { + UP_close(a->num); + } + a->init = 0; + a->flags = BIO_FLAGS_UPLINK; + } + return 1; +} + +static int fd_read(BIO *b, char *out, int outl) +{ + int ret = 0; + + if (out != NULL) { + clear_sys_error(); + ret = UP_read(b->num, out, outl); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (BIO_fd_should_retry(ret)) + BIO_set_retry_read(b); else if (ret == 0) b->flags |= BIO_FLAGS_IN_EOF; - } - } - return ret; -} - -static int fd_write(BIO *b, const char *in, int inl) -{ - int ret; - clear_sys_error(); - ret = UP_write(b->num, in, inl); - BIO_clear_retry_flags(b); - if (ret <= 0) { - if (BIO_fd_should_retry(ret)) - BIO_set_retry_write(b); - } - return ret; -} - -static long fd_ctrl(BIO *b, int cmd, long num, void *ptr) -{ - long ret = 1; - int *ip; - - switch (cmd) { - case BIO_CTRL_RESET: - num = 0; - /* fall thru */ - case BIO_C_FILE_SEEK: - ret = (long)UP_lseek(b->num, num, 0); - break; - case BIO_C_FILE_TELL: - case BIO_CTRL_INFO: - ret = (long)UP_lseek(b->num, 0, 1); - break; - case BIO_C_SET_FD: - fd_free(b); - b->num = *((int *)ptr); - b->shutdown = (int)num; - b->init = 1; - break; - case BIO_C_GET_FD: - if (b->init) { - ip = (int *)ptr; - if (ip != NULL) - *ip = b->num; - ret = b->num; - } else - ret = -1; - break; - case BIO_CTRL_GET_CLOSE: - ret = b->shutdown; - break; - case BIO_CTRL_SET_CLOSE: - b->shutdown = (int)num; - break; - case BIO_CTRL_PENDING: - case BIO_CTRL_WPENDING: - ret = 0; - break; - case BIO_CTRL_DUP: - case BIO_CTRL_FLUSH: - ret = 1; - break; + } + } + return ret; +} + +static int fd_write(BIO *b, const char *in, int inl) +{ + int ret; + clear_sys_error(); + ret = UP_write(b->num, in, inl); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (BIO_fd_should_retry(ret)) + BIO_set_retry_write(b); + } + return ret; +} + +static long fd_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + long ret = 1; + int *ip; + + switch (cmd) { + case BIO_CTRL_RESET: + num = 0; + /* fall thru */ + case BIO_C_FILE_SEEK: + ret = (long)UP_lseek(b->num, num, 0); + break; + case BIO_C_FILE_TELL: + case BIO_CTRL_INFO: + ret = (long)UP_lseek(b->num, 0, 1); + break; + case BIO_C_SET_FD: + fd_free(b); + b->num = *((int *)ptr); + b->shutdown = (int)num; + b->init = 1; + break; + case BIO_C_GET_FD: + if (b->init) { + ip = (int *)ptr; + if (ip != NULL) + *ip = b->num; + ret = b->num; + } else + ret = -1; + break; + case BIO_CTRL_GET_CLOSE: + ret = b->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + b->shutdown = (int)num; + break; + case BIO_CTRL_PENDING: + case BIO_CTRL_WPENDING: + ret = 0; + break; + case BIO_CTRL_DUP: + case BIO_CTRL_FLUSH: + ret = 1; + break; case BIO_CTRL_EOF: ret = (b->flags & BIO_FLAGS_IN_EOF) != 0 ? 1 : 0; break; - default: - ret = 0; - break; - } - return ret; -} - -static int fd_puts(BIO *bp, const char *str) -{ - int n, ret; - - n = strlen(str); - ret = fd_write(bp, str, n); - return ret; -} - -static int fd_gets(BIO *bp, char *buf, int size) -{ - int ret = 0; - char *ptr = buf; - char *end = buf + size - 1; - - while (ptr < end && fd_read(bp, ptr, 1) > 0) { - if (*ptr++ == '\n') - break; - } - - ptr[0] = '\0'; - - if (buf[0] != '\0') - ret = strlen(buf); - return ret; -} - -int BIO_fd_should_retry(int i) -{ - int err; - - if ((i == 0) || (i == -1)) { - err = get_last_sys_error(); - - return BIO_fd_non_fatal_error(err); - } - return 0; -} - -int BIO_fd_non_fatal_error(int err) -{ - switch (err) { - -# ifdef EWOULDBLOCK -# ifdef WSAEWOULDBLOCK -# if WSAEWOULDBLOCK != EWOULDBLOCK - case EWOULDBLOCK: -# endif -# else - case EWOULDBLOCK: -# endif -# endif - -# if defined(ENOTCONN) - case ENOTCONN: -# endif - -# ifdef EINTR - case EINTR: -# endif - -# ifdef EAGAIN -# if EWOULDBLOCK != EAGAIN - case EAGAIN: -# endif -# endif - -# ifdef EPROTO - case EPROTO: -# endif - -# ifdef EINPROGRESS - case EINPROGRESS: -# endif - -# ifdef EALREADY - case EALREADY: -# endif - return 1; - default: - break; - } - return 0; -} -#endif + default: + ret = 0; + break; + } + return ret; +} + +static int fd_puts(BIO *bp, const char *str) +{ + int n, ret; + + n = strlen(str); + ret = fd_write(bp, str, n); + return ret; +} + +static int fd_gets(BIO *bp, char *buf, int size) +{ + int ret = 0; + char *ptr = buf; + char *end = buf + size - 1; + + while (ptr < end && fd_read(bp, ptr, 1) > 0) { + if (*ptr++ == '\n') + break; + } + + ptr[0] = '\0'; + + if (buf[0] != '\0') + ret = strlen(buf); + return ret; +} + +int BIO_fd_should_retry(int i) +{ + int err; + + if ((i == 0) || (i == -1)) { + err = get_last_sys_error(); + + return BIO_fd_non_fatal_error(err); + } + return 0; +} + +int BIO_fd_non_fatal_error(int err) +{ + switch (err) { + +# ifdef EWOULDBLOCK +# ifdef WSAEWOULDBLOCK +# if WSAEWOULDBLOCK != EWOULDBLOCK + case EWOULDBLOCK: +# endif +# else + case EWOULDBLOCK: +# endif +# endif + +# if defined(ENOTCONN) + case ENOTCONN: +# endif + +# ifdef EINTR + case EINTR: +# endif + +# ifdef EAGAIN +# if EWOULDBLOCK != EAGAIN + case EAGAIN: +# endif +# endif + +# ifdef EPROTO + case EPROTO: +# endif + +# ifdef EINPROGRESS + case EINPROGRESS: +# endif + +# ifdef EALREADY + case EALREADY: +# endif + return 1; + default: + break; + } + return 0; +} +#endif diff --git a/contrib/libs/openssl/crypto/bio/bss_file.c b/contrib/libs/openssl/crypto/bio/bss_file.c index 1af8222f9a..1a70ce7994 100644 --- a/contrib/libs/openssl/crypto/bio/bss_file.c +++ b/contrib/libs/openssl/crypto/bio/bss_file.c @@ -1,422 +1,422 @@ -/* - * Copyright 1995-2019 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 - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - +/* + * Copyright 1995-2019 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 + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + #if defined(__linux) || defined(__sun) || defined(__hpux) -/* - * Following definition aliases fopen to fopen64 on above mentioned - * platforms. This makes it possible to open and sequentially access files - * larger than 2GB from 32-bit application. It does not allow to traverse - * them beyond 2GB with fseek/ftell, but on the other hand *no* 32-bit - * platform permits that, not with fseek/ftell. Not to mention that breaking - * 2GB limit for seeking would require surgery to *our* API. But sequential - * access suffices for practical cases when you can run into large files, - * such as fingerprinting, so we can let API alone. For reference, the list - * of 32-bit platforms which allow for sequential access of large files - * without extra "magic" comprise *BSD, Darwin, IRIX... - */ +/* + * Following definition aliases fopen to fopen64 on above mentioned + * platforms. This makes it possible to open and sequentially access files + * larger than 2GB from 32-bit application. It does not allow to traverse + * them beyond 2GB with fseek/ftell, but on the other hand *no* 32-bit + * platform permits that, not with fseek/ftell. Not to mention that breaking + * 2GB limit for seeking would require surgery to *our* API. But sequential + * access suffices for practical cases when you can run into large files, + * such as fingerprinting, so we can let API alone. For reference, the list + * of 32-bit platforms which allow for sequential access of large files + * without extra "magic" comprise *BSD, Darwin, IRIX... + */ # ifndef _FILE_OFFSET_BITS # define _FILE_OFFSET_BITS 64 -# endif +# endif #endif - + #include <stdio.h> #include <errno.h> #include "bio_local.h" #include <openssl/err.h> - + #if !defined(OPENSSL_NO_STDIO) - -static int file_write(BIO *h, const char *buf, int num); -static int file_read(BIO *h, char *buf, int size); -static int file_puts(BIO *h, const char *str); -static int file_gets(BIO *h, char *str, int size); -static long file_ctrl(BIO *h, int cmd, long arg1, void *arg2); -static int file_new(BIO *h); -static int file_free(BIO *data); -static const BIO_METHOD methods_filep = { - BIO_TYPE_FILE, - "FILE pointer", - /* TODO: Convert to new style write function */ - bwrite_conv, - file_write, - /* TODO: Convert to new style read function */ - bread_conv, - file_read, - file_puts, - file_gets, - file_ctrl, - file_new, - file_free, - NULL, /* file_callback_ctrl */ -}; - -BIO *BIO_new_file(const char *filename, const char *mode) -{ - BIO *ret; - FILE *file = openssl_fopen(filename, mode); - int fp_flags = BIO_CLOSE; - - if (strchr(mode, 'b') == NULL) - fp_flags |= BIO_FP_TEXT; - - if (file == NULL) { - SYSerr(SYS_F_FOPEN, get_last_sys_error()); - ERR_add_error_data(5, "fopen('", filename, "','", mode, "')"); - if (errno == ENOENT + +static int file_write(BIO *h, const char *buf, int num); +static int file_read(BIO *h, char *buf, int size); +static int file_puts(BIO *h, const char *str); +static int file_gets(BIO *h, char *str, int size); +static long file_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int file_new(BIO *h); +static int file_free(BIO *data); +static const BIO_METHOD methods_filep = { + BIO_TYPE_FILE, + "FILE pointer", + /* TODO: Convert to new style write function */ + bwrite_conv, + file_write, + /* TODO: Convert to new style read function */ + bread_conv, + file_read, + file_puts, + file_gets, + file_ctrl, + file_new, + file_free, + NULL, /* file_callback_ctrl */ +}; + +BIO *BIO_new_file(const char *filename, const char *mode) +{ + BIO *ret; + FILE *file = openssl_fopen(filename, mode); + int fp_flags = BIO_CLOSE; + + if (strchr(mode, 'b') == NULL) + fp_flags |= BIO_FP_TEXT; + + if (file == NULL) { + SYSerr(SYS_F_FOPEN, get_last_sys_error()); + ERR_add_error_data(5, "fopen('", filename, "','", mode, "')"); + if (errno == ENOENT #ifdef ENXIO - || errno == ENXIO + || errno == ENXIO #endif - ) - BIOerr(BIO_F_BIO_NEW_FILE, BIO_R_NO_SUCH_FILE); - else - BIOerr(BIO_F_BIO_NEW_FILE, ERR_R_SYS_LIB); - return NULL; - } - if ((ret = BIO_new(BIO_s_file())) == NULL) { - fclose(file); - return NULL; - } - - BIO_clear_flags(ret, BIO_FLAGS_UPLINK); /* we did fopen -> we disengage - * UPLINK */ - BIO_set_fp(ret, file, fp_flags); - return ret; -} - -BIO *BIO_new_fp(FILE *stream, int close_flag) -{ - BIO *ret; - - if ((ret = BIO_new(BIO_s_file())) == NULL) - return NULL; - - /* redundant flag, left for documentation purposes */ - BIO_set_flags(ret, BIO_FLAGS_UPLINK); - BIO_set_fp(ret, stream, close_flag); - return ret; -} - -const BIO_METHOD *BIO_s_file(void) -{ - return &methods_filep; -} - -static int file_new(BIO *bi) -{ - bi->init = 0; - bi->num = 0; - bi->ptr = NULL; - bi->flags = BIO_FLAGS_UPLINK; /* default to UPLINK */ - return 1; -} - -static int file_free(BIO *a) -{ - if (a == NULL) - return 0; - if (a->shutdown) { - if ((a->init) && (a->ptr != NULL)) { - if (a->flags & BIO_FLAGS_UPLINK) - UP_fclose(a->ptr); - else - fclose(a->ptr); - a->ptr = NULL; - a->flags = BIO_FLAGS_UPLINK; - } - a->init = 0; - } - return 1; -} - -static int file_read(BIO *b, char *out, int outl) -{ - int ret = 0; - - if (b->init && (out != NULL)) { - if (b->flags & BIO_FLAGS_UPLINK) - ret = UP_fread(out, 1, (int)outl, b->ptr); - else - ret = fread(out, 1, (int)outl, (FILE *)b->ptr); - if (ret == 0 - && (b->flags & BIO_FLAGS_UPLINK) ? UP_ferror((FILE *)b->ptr) : - ferror((FILE *)b->ptr)) { - SYSerr(SYS_F_FREAD, get_last_sys_error()); - BIOerr(BIO_F_FILE_READ, ERR_R_SYS_LIB); - ret = -1; - } - } - return ret; -} - -static int file_write(BIO *b, const char *in, int inl) -{ - int ret = 0; - - if (b->init && (in != NULL)) { - if (b->flags & BIO_FLAGS_UPLINK) - ret = UP_fwrite(in, (int)inl, 1, b->ptr); - else - ret = fwrite(in, (int)inl, 1, (FILE *)b->ptr); - if (ret) - ret = inl; - /* ret=fwrite(in,1,(int)inl,(FILE *)b->ptr); */ - /* - * according to Tim Hudson <tjh@openssl.org>, the commented out - * version above can cause 'inl' write calls under some stupid stdio - * implementations (VMS) - */ - } - return ret; -} - -static long file_ctrl(BIO *b, int cmd, long num, void *ptr) -{ - long ret = 1; - FILE *fp = (FILE *)b->ptr; - FILE **fpp; - char p[4]; - int st; - - switch (cmd) { - case BIO_C_FILE_SEEK: - case BIO_CTRL_RESET: - if (b->flags & BIO_FLAGS_UPLINK) - ret = (long)UP_fseek(b->ptr, num, 0); - else - ret = (long)fseek(fp, num, 0); - break; - case BIO_CTRL_EOF: - if (b->flags & BIO_FLAGS_UPLINK) - ret = (long)UP_feof(fp); - else - ret = (long)feof(fp); - break; - case BIO_C_FILE_TELL: - case BIO_CTRL_INFO: - if (b->flags & BIO_FLAGS_UPLINK) - ret = UP_ftell(b->ptr); - else - ret = ftell(fp); - break; - case BIO_C_SET_FILE_PTR: - file_free(b); - b->shutdown = (int)num & BIO_CLOSE; - b->ptr = ptr; - b->init = 1; + ) + BIOerr(BIO_F_BIO_NEW_FILE, BIO_R_NO_SUCH_FILE); + else + BIOerr(BIO_F_BIO_NEW_FILE, ERR_R_SYS_LIB); + return NULL; + } + if ((ret = BIO_new(BIO_s_file())) == NULL) { + fclose(file); + return NULL; + } + + BIO_clear_flags(ret, BIO_FLAGS_UPLINK); /* we did fopen -> we disengage + * UPLINK */ + BIO_set_fp(ret, file, fp_flags); + return ret; +} + +BIO *BIO_new_fp(FILE *stream, int close_flag) +{ + BIO *ret; + + if ((ret = BIO_new(BIO_s_file())) == NULL) + return NULL; + + /* redundant flag, left for documentation purposes */ + BIO_set_flags(ret, BIO_FLAGS_UPLINK); + BIO_set_fp(ret, stream, close_flag); + return ret; +} + +const BIO_METHOD *BIO_s_file(void) +{ + return &methods_filep; +} + +static int file_new(BIO *bi) +{ + bi->init = 0; + bi->num = 0; + bi->ptr = NULL; + bi->flags = BIO_FLAGS_UPLINK; /* default to UPLINK */ + return 1; +} + +static int file_free(BIO *a) +{ + if (a == NULL) + return 0; + if (a->shutdown) { + if ((a->init) && (a->ptr != NULL)) { + if (a->flags & BIO_FLAGS_UPLINK) + UP_fclose(a->ptr); + else + fclose(a->ptr); + a->ptr = NULL; + a->flags = BIO_FLAGS_UPLINK; + } + a->init = 0; + } + return 1; +} + +static int file_read(BIO *b, char *out, int outl) +{ + int ret = 0; + + if (b->init && (out != NULL)) { + if (b->flags & BIO_FLAGS_UPLINK) + ret = UP_fread(out, 1, (int)outl, b->ptr); + else + ret = fread(out, 1, (int)outl, (FILE *)b->ptr); + if (ret == 0 + && (b->flags & BIO_FLAGS_UPLINK) ? UP_ferror((FILE *)b->ptr) : + ferror((FILE *)b->ptr)) { + SYSerr(SYS_F_FREAD, get_last_sys_error()); + BIOerr(BIO_F_FILE_READ, ERR_R_SYS_LIB); + ret = -1; + } + } + return ret; +} + +static int file_write(BIO *b, const char *in, int inl) +{ + int ret = 0; + + if (b->init && (in != NULL)) { + if (b->flags & BIO_FLAGS_UPLINK) + ret = UP_fwrite(in, (int)inl, 1, b->ptr); + else + ret = fwrite(in, (int)inl, 1, (FILE *)b->ptr); + if (ret) + ret = inl; + /* ret=fwrite(in,1,(int)inl,(FILE *)b->ptr); */ + /* + * according to Tim Hudson <tjh@openssl.org>, the commented out + * version above can cause 'inl' write calls under some stupid stdio + * implementations (VMS) + */ + } + return ret; +} + +static long file_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + long ret = 1; + FILE *fp = (FILE *)b->ptr; + FILE **fpp; + char p[4]; + int st; + + switch (cmd) { + case BIO_C_FILE_SEEK: + case BIO_CTRL_RESET: + if (b->flags & BIO_FLAGS_UPLINK) + ret = (long)UP_fseek(b->ptr, num, 0); + else + ret = (long)fseek(fp, num, 0); + break; + case BIO_CTRL_EOF: + if (b->flags & BIO_FLAGS_UPLINK) + ret = (long)UP_feof(fp); + else + ret = (long)feof(fp); + break; + case BIO_C_FILE_TELL: + case BIO_CTRL_INFO: + if (b->flags & BIO_FLAGS_UPLINK) + ret = UP_ftell(b->ptr); + else + ret = ftell(fp); + break; + case BIO_C_SET_FILE_PTR: + file_free(b); + b->shutdown = (int)num & BIO_CLOSE; + b->ptr = ptr; + b->init = 1; # if BIO_FLAGS_UPLINK!=0 # if defined(__MINGW32__) && defined(__MSVCRT__) && !defined(_IOB_ENTRIES) # define _IOB_ENTRIES 20 # endif - /* Safety net to catch purely internal BIO_set_fp calls */ + /* Safety net to catch purely internal BIO_set_fp calls */ # if defined(_MSC_VER) && _MSC_VER>=1900 - if (ptr == stdin || ptr == stdout || ptr == stderr) - BIO_clear_flags(b, BIO_FLAGS_UPLINK); + if (ptr == stdin || ptr == stdout || ptr == stderr) + BIO_clear_flags(b, BIO_FLAGS_UPLINK); # elif defined(_IOB_ENTRIES) - if ((size_t)ptr >= (size_t)stdin && - (size_t)ptr < (size_t)(stdin + _IOB_ENTRIES)) - BIO_clear_flags(b, BIO_FLAGS_UPLINK); -# endif + if ((size_t)ptr >= (size_t)stdin && + (size_t)ptr < (size_t)(stdin + _IOB_ENTRIES)) + BIO_clear_flags(b, BIO_FLAGS_UPLINK); +# endif # endif # ifdef UP_fsetmod - if (b->flags & BIO_FLAGS_UPLINK) - UP_fsetmod(b->ptr, (char)((num & BIO_FP_TEXT) ? 't' : 'b')); - else + if (b->flags & BIO_FLAGS_UPLINK) + UP_fsetmod(b->ptr, (char)((num & BIO_FP_TEXT) ? 't' : 'b')); + else # endif - { + { # if defined(OPENSSL_SYS_WINDOWS) - int fd = _fileno((FILE *)ptr); - if (num & BIO_FP_TEXT) - _setmode(fd, _O_TEXT); - else - _setmode(fd, _O_BINARY); + int fd = _fileno((FILE *)ptr); + if (num & BIO_FP_TEXT) + _setmode(fd, _O_TEXT); + else + _setmode(fd, _O_BINARY); # elif defined(OPENSSL_SYS_MSDOS) - int fd = fileno((FILE *)ptr); - /* Set correct text/binary mode */ - if (num & BIO_FP_TEXT) - _setmode(fd, _O_TEXT); - /* Dangerous to set stdin/stdout to raw (unless redirected) */ - else { - if (fd == STDIN_FILENO || fd == STDOUT_FILENO) { - if (isatty(fd) <= 0) - _setmode(fd, _O_BINARY); - } else - _setmode(fd, _O_BINARY); - } + int fd = fileno((FILE *)ptr); + /* Set correct text/binary mode */ + if (num & BIO_FP_TEXT) + _setmode(fd, _O_TEXT); + /* Dangerous to set stdin/stdout to raw (unless redirected) */ + else { + if (fd == STDIN_FILENO || fd == STDOUT_FILENO) { + if (isatty(fd) <= 0) + _setmode(fd, _O_BINARY); + } else + _setmode(fd, _O_BINARY); + } # elif defined(OPENSSL_SYS_WIN32_CYGWIN) - int fd = fileno((FILE *)ptr); - if (!(num & BIO_FP_TEXT)) - setmode(fd, O_BINARY); + int fd = fileno((FILE *)ptr); + if (!(num & BIO_FP_TEXT)) + setmode(fd, O_BINARY); # endif - } - break; - case BIO_C_SET_FILENAME: - file_free(b); - b->shutdown = (int)num & BIO_CLOSE; - if (num & BIO_FP_APPEND) { - if (num & BIO_FP_READ) - OPENSSL_strlcpy(p, "a+", sizeof(p)); - else - OPENSSL_strlcpy(p, "a", sizeof(p)); - } else if ((num & BIO_FP_READ) && (num & BIO_FP_WRITE)) - OPENSSL_strlcpy(p, "r+", sizeof(p)); - else if (num & BIO_FP_WRITE) - OPENSSL_strlcpy(p, "w", sizeof(p)); - else if (num & BIO_FP_READ) - OPENSSL_strlcpy(p, "r", sizeof(p)); - else { - BIOerr(BIO_F_FILE_CTRL, BIO_R_BAD_FOPEN_MODE); - ret = 0; - break; - } + } + break; + case BIO_C_SET_FILENAME: + file_free(b); + b->shutdown = (int)num & BIO_CLOSE; + if (num & BIO_FP_APPEND) { + if (num & BIO_FP_READ) + OPENSSL_strlcpy(p, "a+", sizeof(p)); + else + OPENSSL_strlcpy(p, "a", sizeof(p)); + } else if ((num & BIO_FP_READ) && (num & BIO_FP_WRITE)) + OPENSSL_strlcpy(p, "r+", sizeof(p)); + else if (num & BIO_FP_WRITE) + OPENSSL_strlcpy(p, "w", sizeof(p)); + else if (num & BIO_FP_READ) + OPENSSL_strlcpy(p, "r", sizeof(p)); + else { + BIOerr(BIO_F_FILE_CTRL, BIO_R_BAD_FOPEN_MODE); + ret = 0; + break; + } # if defined(OPENSSL_SYS_MSDOS) || defined(OPENSSL_SYS_WINDOWS) - if (!(num & BIO_FP_TEXT)) - OPENSSL_strlcat(p, "b", sizeof(p)); - else - OPENSSL_strlcat(p, "t", sizeof(p)); + if (!(num & BIO_FP_TEXT)) + OPENSSL_strlcat(p, "b", sizeof(p)); + else + OPENSSL_strlcat(p, "t", sizeof(p)); # elif defined(OPENSSL_SYS_WIN32_CYGWIN) - if (!(num & BIO_FP_TEXT)) - OPENSSL_strlcat(p, "b", sizeof(p)); + if (!(num & BIO_FP_TEXT)) + OPENSSL_strlcat(p, "b", sizeof(p)); # endif - fp = openssl_fopen(ptr, p); - if (fp == NULL) { - SYSerr(SYS_F_FOPEN, get_last_sys_error()); - ERR_add_error_data(5, "fopen('", ptr, "','", p, "')"); - BIOerr(BIO_F_FILE_CTRL, ERR_R_SYS_LIB); - ret = 0; - break; - } - b->ptr = fp; - b->init = 1; - BIO_clear_flags(b, BIO_FLAGS_UPLINK); /* we did fopen -> we disengage - * UPLINK */ - break; - case BIO_C_GET_FILE_PTR: - /* the ptr parameter is actually a FILE ** in this case. */ - if (ptr != NULL) { - fpp = (FILE **)ptr; - *fpp = (FILE *)b->ptr; - } - break; - case BIO_CTRL_GET_CLOSE: - ret = (long)b->shutdown; - break; - case BIO_CTRL_SET_CLOSE: - b->shutdown = (int)num; - break; - case BIO_CTRL_FLUSH: - st = b->flags & BIO_FLAGS_UPLINK - ? UP_fflush(b->ptr) : fflush((FILE *)b->ptr); - if (st == EOF) { - SYSerr(SYS_F_FFLUSH, get_last_sys_error()); - ERR_add_error_data(1, "fflush()"); - BIOerr(BIO_F_FILE_CTRL, ERR_R_SYS_LIB); - ret = 0; - } - break; - case BIO_CTRL_DUP: - ret = 1; - break; - - case BIO_CTRL_WPENDING: - case BIO_CTRL_PENDING: - case BIO_CTRL_PUSH: - case BIO_CTRL_POP: - default: - ret = 0; - break; - } - return ret; -} - -static int file_gets(BIO *bp, char *buf, int size) -{ - int ret = 0; - - buf[0] = '\0'; - if (bp->flags & BIO_FLAGS_UPLINK) { - if (!UP_fgets(buf, size, bp->ptr)) - goto err; - } else { - if (!fgets(buf, size, (FILE *)bp->ptr)) - goto err; - } - if (buf[0] != '\0') - ret = strlen(buf); - err: - return ret; -} - -static int file_puts(BIO *bp, const char *str) -{ - int n, ret; - - n = strlen(str); - ret = file_write(bp, str, n); - return ret; -} - -#else - -static int file_write(BIO *b, const char *in, int inl) -{ - return -1; -} -static int file_read(BIO *b, char *out, int outl) -{ - return -1; -} -static int file_puts(BIO *bp, const char *str) -{ - return -1; -} -static int file_gets(BIO *bp, char *buf, int size) -{ - return 0; -} -static long file_ctrl(BIO *b, int cmd, long num, void *ptr) -{ - return 0; -} -static int file_new(BIO *bi) -{ - return 0; -} -static int file_free(BIO *a) -{ - return 0; -} - -static const BIO_METHOD methods_filep = { - BIO_TYPE_FILE, - "FILE pointer", - /* TODO: Convert to new style write function */ - bwrite_conv, - file_write, - /* TODO: Convert to new style read function */ - bread_conv, - file_read, - file_puts, - file_gets, - file_ctrl, - file_new, - file_free, - NULL, /* file_callback_ctrl */ -}; - -const BIO_METHOD *BIO_s_file(void) -{ - return &methods_filep; -} - -BIO *BIO_new_file(const char *filename, const char *mode) -{ - return NULL; -} - + fp = openssl_fopen(ptr, p); + if (fp == NULL) { + SYSerr(SYS_F_FOPEN, get_last_sys_error()); + ERR_add_error_data(5, "fopen('", ptr, "','", p, "')"); + BIOerr(BIO_F_FILE_CTRL, ERR_R_SYS_LIB); + ret = 0; + break; + } + b->ptr = fp; + b->init = 1; + BIO_clear_flags(b, BIO_FLAGS_UPLINK); /* we did fopen -> we disengage + * UPLINK */ + break; + case BIO_C_GET_FILE_PTR: + /* the ptr parameter is actually a FILE ** in this case. */ + if (ptr != NULL) { + fpp = (FILE **)ptr; + *fpp = (FILE *)b->ptr; + } + break; + case BIO_CTRL_GET_CLOSE: + ret = (long)b->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + b->shutdown = (int)num; + break; + case BIO_CTRL_FLUSH: + st = b->flags & BIO_FLAGS_UPLINK + ? UP_fflush(b->ptr) : fflush((FILE *)b->ptr); + if (st == EOF) { + SYSerr(SYS_F_FFLUSH, get_last_sys_error()); + ERR_add_error_data(1, "fflush()"); + BIOerr(BIO_F_FILE_CTRL, ERR_R_SYS_LIB); + ret = 0; + } + break; + case BIO_CTRL_DUP: + ret = 1; + break; + + case BIO_CTRL_WPENDING: + case BIO_CTRL_PENDING: + case BIO_CTRL_PUSH: + case BIO_CTRL_POP: + default: + ret = 0; + break; + } + return ret; +} + +static int file_gets(BIO *bp, char *buf, int size) +{ + int ret = 0; + + buf[0] = '\0'; + if (bp->flags & BIO_FLAGS_UPLINK) { + if (!UP_fgets(buf, size, bp->ptr)) + goto err; + } else { + if (!fgets(buf, size, (FILE *)bp->ptr)) + goto err; + } + if (buf[0] != '\0') + ret = strlen(buf); + err: + return ret; +} + +static int file_puts(BIO *bp, const char *str) +{ + int n, ret; + + n = strlen(str); + ret = file_write(bp, str, n); + return ret; +} + +#else + +static int file_write(BIO *b, const char *in, int inl) +{ + return -1; +} +static int file_read(BIO *b, char *out, int outl) +{ + return -1; +} +static int file_puts(BIO *bp, const char *str) +{ + return -1; +} +static int file_gets(BIO *bp, char *buf, int size) +{ + return 0; +} +static long file_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + return 0; +} +static int file_new(BIO *bi) +{ + return 0; +} +static int file_free(BIO *a) +{ + return 0; +} + +static const BIO_METHOD methods_filep = { + BIO_TYPE_FILE, + "FILE pointer", + /* TODO: Convert to new style write function */ + bwrite_conv, + file_write, + /* TODO: Convert to new style read function */ + bread_conv, + file_read, + file_puts, + file_gets, + file_ctrl, + file_new, + file_free, + NULL, /* file_callback_ctrl */ +}; + +const BIO_METHOD *BIO_s_file(void) +{ + return &methods_filep; +} + +BIO *BIO_new_file(const char *filename, const char *mode) +{ + return NULL; +} + #endif /* OPENSSL_NO_STDIO */ diff --git a/contrib/libs/openssl/crypto/bio/bss_log.c b/contrib/libs/openssl/crypto/bio/bss_log.c index 879745a00c..b9579faaa2 100644 --- a/contrib/libs/openssl/crypto/bio/bss_log.c +++ b/contrib/libs/openssl/crypto/bio/bss_log.c @@ -1,416 +1,416 @@ -/* - * Copyright 1999-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 - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -/* - * Why BIO_s_log? - * - * BIO_s_log is useful for system daemons (or services under NT). It is - * one-way BIO, it sends all stuff to syslogd (on system that commonly use - * that), or event log (on NT), or OPCOM (on OpenVMS). - * - */ - -#include <stdio.h> -#include <errno.h> - +/* + * Copyright 1999-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 + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +/* + * Why BIO_s_log? + * + * BIO_s_log is useful for system daemons (or services under NT). It is + * one-way BIO, it sends all stuff to syslogd (on system that commonly use + * that), or event log (on NT), or OPCOM (on OpenVMS). + * + */ + +#include <stdio.h> +#include <errno.h> + #include "bio_local.h" -#include "internal/cryptlib.h" - -#if defined(OPENSSL_SYS_WINCE) -#elif defined(OPENSSL_SYS_WIN32) -#elif defined(OPENSSL_SYS_VMS) -# include <opcdef.h> -# include <descrip.h> -# include <lib$routines.h> -# include <starlet.h> -/* Some compiler options may mask the declaration of "_malloc32". */ -# if __INITIAL_POINTER_SIZE && defined _ANSI_C_SOURCE -# if __INITIAL_POINTER_SIZE == 64 -# pragma pointer_size save -# pragma pointer_size 32 -void *_malloc32(__size_t); -# pragma pointer_size restore -# endif /* __INITIAL_POINTER_SIZE == 64 */ -# endif /* __INITIAL_POINTER_SIZE && defined - * _ANSI_C_SOURCE */ -#elif defined(__DJGPP__) && defined(OPENSSL_NO_SOCK) -# define NO_SYSLOG -#elif (!defined(MSDOS) || defined(WATT32)) && !defined(OPENSSL_SYS_VXWORKS) && !defined(NO_SYSLOG) -# include <syslog.h> -#endif - -#include <openssl/buffer.h> -#include <openssl/err.h> - -#ifndef NO_SYSLOG - -# if defined(OPENSSL_SYS_WIN32) -# define LOG_EMERG 0 -# define LOG_ALERT 1 -# define LOG_CRIT 2 -# define LOG_ERR 3 -# define LOG_WARNING 4 -# define LOG_NOTICE 5 -# define LOG_INFO 6 -# define LOG_DEBUG 7 - -# define LOG_DAEMON (3<<3) -# elif defined(OPENSSL_SYS_VMS) -/* On VMS, we don't really care about these, but we need them to compile */ -# define LOG_EMERG 0 -# define LOG_ALERT 1 -# define LOG_CRIT 2 -# define LOG_ERR 3 -# define LOG_WARNING 4 -# define LOG_NOTICE 5 -# define LOG_INFO 6 -# define LOG_DEBUG 7 - -# define LOG_DAEMON OPC$M_NM_NTWORK -# endif - -static int slg_write(BIO *h, const char *buf, int num); -static int slg_puts(BIO *h, const char *str); -static long slg_ctrl(BIO *h, int cmd, long arg1, void *arg2); -static int slg_new(BIO *h); -static int slg_free(BIO *data); -static void xopenlog(BIO *bp, char *name, int level); -static void xsyslog(BIO *bp, int priority, const char *string); -static void xcloselog(BIO *bp); - -static const BIO_METHOD methods_slg = { - BIO_TYPE_MEM, - "syslog", - /* TODO: Convert to new style write function */ - bwrite_conv, - slg_write, - NULL, /* slg_write_old, */ - NULL, /* slg_read, */ - slg_puts, - NULL, - slg_ctrl, - slg_new, - slg_free, - NULL, /* slg_callback_ctrl */ -}; - -const BIO_METHOD *BIO_s_log(void) -{ - return &methods_slg; -} - -static int slg_new(BIO *bi) -{ - bi->init = 1; - bi->num = 0; - bi->ptr = NULL; - xopenlog(bi, "application", LOG_DAEMON); - return 1; -} - -static int slg_free(BIO *a) -{ - if (a == NULL) - return 0; - xcloselog(a); - return 1; -} - -static int slg_write(BIO *b, const char *in, int inl) -{ - int ret = inl; - char *buf; - char *pp; - int priority, i; - static const struct { - int strl; - char str[10]; - int log_level; - } mapping[] = { - { - 6, "PANIC ", LOG_EMERG - }, - { - 6, "EMERG ", LOG_EMERG - }, - { - 4, "EMR ", LOG_EMERG - }, - { - 6, "ALERT ", LOG_ALERT - }, - { - 4, "ALR ", LOG_ALERT - }, - { - 5, "CRIT ", LOG_CRIT - }, - { - 4, "CRI ", LOG_CRIT - }, - { - 6, "ERROR ", LOG_ERR - }, - { - 4, "ERR ", LOG_ERR - }, - { - 8, "WARNING ", LOG_WARNING - }, - { - 5, "WARN ", LOG_WARNING - }, - { - 4, "WAR ", LOG_WARNING - }, - { - 7, "NOTICE ", LOG_NOTICE - }, - { - 5, "NOTE ", LOG_NOTICE - }, - { - 4, "NOT ", LOG_NOTICE - }, - { - 5, "INFO ", LOG_INFO - }, - { - 4, "INF ", LOG_INFO - }, - { - 6, "DEBUG ", LOG_DEBUG - }, - { - 4, "DBG ", LOG_DEBUG - }, - { - 0, "", LOG_ERR - } - /* The default */ - }; - - if ((buf = OPENSSL_malloc(inl + 1)) == NULL) { - BIOerr(BIO_F_SLG_WRITE, ERR_R_MALLOC_FAILURE); - return 0; - } - memcpy(buf, in, inl); - buf[inl] = '\0'; - - i = 0; - while (strncmp(buf, mapping[i].str, mapping[i].strl) != 0) - i++; - priority = mapping[i].log_level; - pp = buf + mapping[i].strl; - - xsyslog(b, priority, pp); - - OPENSSL_free(buf); - return ret; -} - -static long slg_ctrl(BIO *b, int cmd, long num, void *ptr) -{ - switch (cmd) { - case BIO_CTRL_SET: - xcloselog(b); - xopenlog(b, ptr, num); - break; - default: - break; - } - return 0; -} - -static int slg_puts(BIO *bp, const char *str) -{ - int n, ret; - - n = strlen(str); - ret = slg_write(bp, str, n); - return ret; -} - -# if defined(OPENSSL_SYS_WIN32) - -static void xopenlog(BIO *bp, char *name, int level) -{ - if (check_winnt()) - bp->ptr = RegisterEventSourceA(NULL, name); - else - bp->ptr = NULL; -} - -static void xsyslog(BIO *bp, int priority, const char *string) -{ - LPCSTR lpszStrings[2]; - WORD evtype = EVENTLOG_ERROR_TYPE; - char pidbuf[DECIMAL_SIZE(DWORD) + 4]; - - if (bp->ptr == NULL) - return; - - switch (priority) { - case LOG_EMERG: - case LOG_ALERT: - case LOG_CRIT: - case LOG_ERR: - evtype = EVENTLOG_ERROR_TYPE; - break; - case LOG_WARNING: - evtype = EVENTLOG_WARNING_TYPE; - break; - case LOG_NOTICE: - case LOG_INFO: - case LOG_DEBUG: - evtype = EVENTLOG_INFORMATION_TYPE; - break; - default: - /* - * Should never happen, but set it - * as error anyway. - */ - evtype = EVENTLOG_ERROR_TYPE; - break; - } - - sprintf(pidbuf, "[%lu] ", GetCurrentProcessId()); - lpszStrings[0] = pidbuf; - lpszStrings[1] = string; - - ReportEventA(bp->ptr, evtype, 0, 1024, NULL, 2, 0, lpszStrings, NULL); -} - -static void xcloselog(BIO *bp) -{ - if (bp->ptr) - DeregisterEventSource((HANDLE) (bp->ptr)); - bp->ptr = NULL; -} - -# elif defined(OPENSSL_SYS_VMS) - -static int VMS_OPC_target = LOG_DAEMON; - -static void xopenlog(BIO *bp, char *name, int level) -{ - VMS_OPC_target = level; -} - -static void xsyslog(BIO *bp, int priority, const char *string) -{ - struct dsc$descriptor_s opc_dsc; - -/* Arrange 32-bit pointer to opcdef buffer and malloc(), if needed. */ -# if __INITIAL_POINTER_SIZE == 64 -# pragma pointer_size save -# pragma pointer_size 32 -# define OPCDEF_TYPE __char_ptr32 -# define OPCDEF_MALLOC _malloc32 -# else /* __INITIAL_POINTER_SIZE == 64 */ -# define OPCDEF_TYPE char * -# define OPCDEF_MALLOC OPENSSL_malloc -# endif /* __INITIAL_POINTER_SIZE == 64 [else] */ - - struct opcdef *opcdef_p; - -# if __INITIAL_POINTER_SIZE == 64 -# pragma pointer_size restore -# endif /* __INITIAL_POINTER_SIZE == 64 */ - - char buf[10240]; - unsigned int len; - struct dsc$descriptor_s buf_dsc; - $DESCRIPTOR(fao_cmd, "!AZ: !AZ"); - char *priority_tag; - - switch (priority) { - case LOG_EMERG: - priority_tag = "Emergency"; - break; - case LOG_ALERT: - priority_tag = "Alert"; - break; - case LOG_CRIT: - priority_tag = "Critical"; - break; - case LOG_ERR: - priority_tag = "Error"; - break; - case LOG_WARNING: - priority_tag = "Warning"; - break; - case LOG_NOTICE: - priority_tag = "Notice"; - break; - case LOG_INFO: - priority_tag = "Info"; - break; - case LOG_DEBUG: - priority_tag = "DEBUG"; - break; - } - - buf_dsc.dsc$b_dtype = DSC$K_DTYPE_T; - buf_dsc.dsc$b_class = DSC$K_CLASS_S; - buf_dsc.dsc$a_pointer = buf; - buf_dsc.dsc$w_length = sizeof(buf) - 1; - - lib$sys_fao(&fao_cmd, &len, &buf_dsc, priority_tag, string); - - /* We know there's an 8-byte header. That's documented. */ - opcdef_p = OPCDEF_MALLOC(8 + len); - opcdef_p->opc$b_ms_type = OPC$_RQ_RQST; - memcpy(opcdef_p->opc$z_ms_target_classes, &VMS_OPC_target, 3); - opcdef_p->opc$l_ms_rqstid = 0; - memcpy(&opcdef_p->opc$l_ms_text, buf, len); - - opc_dsc.dsc$b_dtype = DSC$K_DTYPE_T; - opc_dsc.dsc$b_class = DSC$K_CLASS_S; - opc_dsc.dsc$a_pointer = (OPCDEF_TYPE) opcdef_p; - opc_dsc.dsc$w_length = len + 8; - - sys$sndopr(opc_dsc, 0); - - OPENSSL_free(opcdef_p); -} - -static void xcloselog(BIO *bp) -{ -} - -# else /* Unix/Watt32 */ - -static void xopenlog(BIO *bp, char *name, int level) -{ -# ifdef WATT32 /* djgpp/DOS */ - openlog(name, LOG_PID | LOG_CONS | LOG_NDELAY, level); -# else - openlog(name, LOG_PID | LOG_CONS, level); -# endif -} - -static void xsyslog(BIO *bp, int priority, const char *string) -{ - syslog(priority, "%s", string); -} - -static void xcloselog(BIO *bp) -{ - closelog(); -} - -# endif /* Unix */ - -#else /* NO_SYSLOG */ -const BIO_METHOD *BIO_s_log(void) -{ - return NULL; -} -#endif /* NO_SYSLOG */ +#include "internal/cryptlib.h" + +#if defined(OPENSSL_SYS_WINCE) +#elif defined(OPENSSL_SYS_WIN32) +#elif defined(OPENSSL_SYS_VMS) +# include <opcdef.h> +# include <descrip.h> +# include <lib$routines.h> +# include <starlet.h> +/* Some compiler options may mask the declaration of "_malloc32". */ +# if __INITIAL_POINTER_SIZE && defined _ANSI_C_SOURCE +# if __INITIAL_POINTER_SIZE == 64 +# pragma pointer_size save +# pragma pointer_size 32 +void *_malloc32(__size_t); +# pragma pointer_size restore +# endif /* __INITIAL_POINTER_SIZE == 64 */ +# endif /* __INITIAL_POINTER_SIZE && defined + * _ANSI_C_SOURCE */ +#elif defined(__DJGPP__) && defined(OPENSSL_NO_SOCK) +# define NO_SYSLOG +#elif (!defined(MSDOS) || defined(WATT32)) && !defined(OPENSSL_SYS_VXWORKS) && !defined(NO_SYSLOG) +# include <syslog.h> +#endif + +#include <openssl/buffer.h> +#include <openssl/err.h> + +#ifndef NO_SYSLOG + +# if defined(OPENSSL_SYS_WIN32) +# define LOG_EMERG 0 +# define LOG_ALERT 1 +# define LOG_CRIT 2 +# define LOG_ERR 3 +# define LOG_WARNING 4 +# define LOG_NOTICE 5 +# define LOG_INFO 6 +# define LOG_DEBUG 7 + +# define LOG_DAEMON (3<<3) +# elif defined(OPENSSL_SYS_VMS) +/* On VMS, we don't really care about these, but we need them to compile */ +# define LOG_EMERG 0 +# define LOG_ALERT 1 +# define LOG_CRIT 2 +# define LOG_ERR 3 +# define LOG_WARNING 4 +# define LOG_NOTICE 5 +# define LOG_INFO 6 +# define LOG_DEBUG 7 + +# define LOG_DAEMON OPC$M_NM_NTWORK +# endif + +static int slg_write(BIO *h, const char *buf, int num); +static int slg_puts(BIO *h, const char *str); +static long slg_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int slg_new(BIO *h); +static int slg_free(BIO *data); +static void xopenlog(BIO *bp, char *name, int level); +static void xsyslog(BIO *bp, int priority, const char *string); +static void xcloselog(BIO *bp); + +static const BIO_METHOD methods_slg = { + BIO_TYPE_MEM, + "syslog", + /* TODO: Convert to new style write function */ + bwrite_conv, + slg_write, + NULL, /* slg_write_old, */ + NULL, /* slg_read, */ + slg_puts, + NULL, + slg_ctrl, + slg_new, + slg_free, + NULL, /* slg_callback_ctrl */ +}; + +const BIO_METHOD *BIO_s_log(void) +{ + return &methods_slg; +} + +static int slg_new(BIO *bi) +{ + bi->init = 1; + bi->num = 0; + bi->ptr = NULL; + xopenlog(bi, "application", LOG_DAEMON); + return 1; +} + +static int slg_free(BIO *a) +{ + if (a == NULL) + return 0; + xcloselog(a); + return 1; +} + +static int slg_write(BIO *b, const char *in, int inl) +{ + int ret = inl; + char *buf; + char *pp; + int priority, i; + static const struct { + int strl; + char str[10]; + int log_level; + } mapping[] = { + { + 6, "PANIC ", LOG_EMERG + }, + { + 6, "EMERG ", LOG_EMERG + }, + { + 4, "EMR ", LOG_EMERG + }, + { + 6, "ALERT ", LOG_ALERT + }, + { + 4, "ALR ", LOG_ALERT + }, + { + 5, "CRIT ", LOG_CRIT + }, + { + 4, "CRI ", LOG_CRIT + }, + { + 6, "ERROR ", LOG_ERR + }, + { + 4, "ERR ", LOG_ERR + }, + { + 8, "WARNING ", LOG_WARNING + }, + { + 5, "WARN ", LOG_WARNING + }, + { + 4, "WAR ", LOG_WARNING + }, + { + 7, "NOTICE ", LOG_NOTICE + }, + { + 5, "NOTE ", LOG_NOTICE + }, + { + 4, "NOT ", LOG_NOTICE + }, + { + 5, "INFO ", LOG_INFO + }, + { + 4, "INF ", LOG_INFO + }, + { + 6, "DEBUG ", LOG_DEBUG + }, + { + 4, "DBG ", LOG_DEBUG + }, + { + 0, "", LOG_ERR + } + /* The default */ + }; + + if ((buf = OPENSSL_malloc(inl + 1)) == NULL) { + BIOerr(BIO_F_SLG_WRITE, ERR_R_MALLOC_FAILURE); + return 0; + } + memcpy(buf, in, inl); + buf[inl] = '\0'; + + i = 0; + while (strncmp(buf, mapping[i].str, mapping[i].strl) != 0) + i++; + priority = mapping[i].log_level; + pp = buf + mapping[i].strl; + + xsyslog(b, priority, pp); + + OPENSSL_free(buf); + return ret; +} + +static long slg_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + switch (cmd) { + case BIO_CTRL_SET: + xcloselog(b); + xopenlog(b, ptr, num); + break; + default: + break; + } + return 0; +} + +static int slg_puts(BIO *bp, const char *str) +{ + int n, ret; + + n = strlen(str); + ret = slg_write(bp, str, n); + return ret; +} + +# if defined(OPENSSL_SYS_WIN32) + +static void xopenlog(BIO *bp, char *name, int level) +{ + if (check_winnt()) + bp->ptr = RegisterEventSourceA(NULL, name); + else + bp->ptr = NULL; +} + +static void xsyslog(BIO *bp, int priority, const char *string) +{ + LPCSTR lpszStrings[2]; + WORD evtype = EVENTLOG_ERROR_TYPE; + char pidbuf[DECIMAL_SIZE(DWORD) + 4]; + + if (bp->ptr == NULL) + return; + + switch (priority) { + case LOG_EMERG: + case LOG_ALERT: + case LOG_CRIT: + case LOG_ERR: + evtype = EVENTLOG_ERROR_TYPE; + break; + case LOG_WARNING: + evtype = EVENTLOG_WARNING_TYPE; + break; + case LOG_NOTICE: + case LOG_INFO: + case LOG_DEBUG: + evtype = EVENTLOG_INFORMATION_TYPE; + break; + default: + /* + * Should never happen, but set it + * as error anyway. + */ + evtype = EVENTLOG_ERROR_TYPE; + break; + } + + sprintf(pidbuf, "[%lu] ", GetCurrentProcessId()); + lpszStrings[0] = pidbuf; + lpszStrings[1] = string; + + ReportEventA(bp->ptr, evtype, 0, 1024, NULL, 2, 0, lpszStrings, NULL); +} + +static void xcloselog(BIO *bp) +{ + if (bp->ptr) + DeregisterEventSource((HANDLE) (bp->ptr)); + bp->ptr = NULL; +} + +# elif defined(OPENSSL_SYS_VMS) + +static int VMS_OPC_target = LOG_DAEMON; + +static void xopenlog(BIO *bp, char *name, int level) +{ + VMS_OPC_target = level; +} + +static void xsyslog(BIO *bp, int priority, const char *string) +{ + struct dsc$descriptor_s opc_dsc; + +/* Arrange 32-bit pointer to opcdef buffer and malloc(), if needed. */ +# if __INITIAL_POINTER_SIZE == 64 +# pragma pointer_size save +# pragma pointer_size 32 +# define OPCDEF_TYPE __char_ptr32 +# define OPCDEF_MALLOC _malloc32 +# else /* __INITIAL_POINTER_SIZE == 64 */ +# define OPCDEF_TYPE char * +# define OPCDEF_MALLOC OPENSSL_malloc +# endif /* __INITIAL_POINTER_SIZE == 64 [else] */ + + struct opcdef *opcdef_p; + +# if __INITIAL_POINTER_SIZE == 64 +# pragma pointer_size restore +# endif /* __INITIAL_POINTER_SIZE == 64 */ + + char buf[10240]; + unsigned int len; + struct dsc$descriptor_s buf_dsc; + $DESCRIPTOR(fao_cmd, "!AZ: !AZ"); + char *priority_tag; + + switch (priority) { + case LOG_EMERG: + priority_tag = "Emergency"; + break; + case LOG_ALERT: + priority_tag = "Alert"; + break; + case LOG_CRIT: + priority_tag = "Critical"; + break; + case LOG_ERR: + priority_tag = "Error"; + break; + case LOG_WARNING: + priority_tag = "Warning"; + break; + case LOG_NOTICE: + priority_tag = "Notice"; + break; + case LOG_INFO: + priority_tag = "Info"; + break; + case LOG_DEBUG: + priority_tag = "DEBUG"; + break; + } + + buf_dsc.dsc$b_dtype = DSC$K_DTYPE_T; + buf_dsc.dsc$b_class = DSC$K_CLASS_S; + buf_dsc.dsc$a_pointer = buf; + buf_dsc.dsc$w_length = sizeof(buf) - 1; + + lib$sys_fao(&fao_cmd, &len, &buf_dsc, priority_tag, string); + + /* We know there's an 8-byte header. That's documented. */ + opcdef_p = OPCDEF_MALLOC(8 + len); + opcdef_p->opc$b_ms_type = OPC$_RQ_RQST; + memcpy(opcdef_p->opc$z_ms_target_classes, &VMS_OPC_target, 3); + opcdef_p->opc$l_ms_rqstid = 0; + memcpy(&opcdef_p->opc$l_ms_text, buf, len); + + opc_dsc.dsc$b_dtype = DSC$K_DTYPE_T; + opc_dsc.dsc$b_class = DSC$K_CLASS_S; + opc_dsc.dsc$a_pointer = (OPCDEF_TYPE) opcdef_p; + opc_dsc.dsc$w_length = len + 8; + + sys$sndopr(opc_dsc, 0); + + OPENSSL_free(opcdef_p); +} + +static void xcloselog(BIO *bp) +{ +} + +# else /* Unix/Watt32 */ + +static void xopenlog(BIO *bp, char *name, int level) +{ +# ifdef WATT32 /* djgpp/DOS */ + openlog(name, LOG_PID | LOG_CONS | LOG_NDELAY, level); +# else + openlog(name, LOG_PID | LOG_CONS, level); +# endif +} + +static void xsyslog(BIO *bp, int priority, const char *string) +{ + syslog(priority, "%s", string); +} + +static void xcloselog(BIO *bp) +{ + closelog(); +} + +# endif /* Unix */ + +#else /* NO_SYSLOG */ +const BIO_METHOD *BIO_s_log(void) +{ + return NULL; +} +#endif /* NO_SYSLOG */ diff --git a/contrib/libs/openssl/crypto/bio/bss_mem.c b/contrib/libs/openssl/crypto/bio/bss_mem.c index 16bec42fd1..7cb4a57813 100644 --- a/contrib/libs/openssl/crypto/bio/bss_mem.c +++ b/contrib/libs/openssl/crypto/bio/bss_mem.c @@ -1,372 +1,372 @@ -/* - * Copyright 1995-2019 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 - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -#include <stdio.h> -#include <errno.h> +/* + * Copyright 1995-2019 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 + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include <errno.h> #include "bio_local.h" -#include "internal/cryptlib.h" - -static int mem_write(BIO *h, const char *buf, int num); -static int mem_read(BIO *h, char *buf, int size); -static int mem_puts(BIO *h, const char *str); -static int mem_gets(BIO *h, char *str, int size); -static long mem_ctrl(BIO *h, int cmd, long arg1, void *arg2); -static int mem_new(BIO *h); -static int secmem_new(BIO *h); -static int mem_free(BIO *data); -static int mem_buf_free(BIO *data); -static int mem_buf_sync(BIO *h); - -static const BIO_METHOD mem_method = { - BIO_TYPE_MEM, - "memory buffer", - /* TODO: Convert to new style write function */ - bwrite_conv, - mem_write, - /* TODO: Convert to new style read function */ - bread_conv, - mem_read, - mem_puts, - mem_gets, - mem_ctrl, - mem_new, - mem_free, - NULL, /* mem_callback_ctrl */ -}; - -static const BIO_METHOD secmem_method = { - BIO_TYPE_MEM, - "secure memory buffer", - /* TODO: Convert to new style write function */ - bwrite_conv, - mem_write, - /* TODO: Convert to new style read function */ - bread_conv, - mem_read, - mem_puts, - mem_gets, - mem_ctrl, - secmem_new, - mem_free, - NULL, /* mem_callback_ctrl */ -}; - +#include "internal/cryptlib.h" + +static int mem_write(BIO *h, const char *buf, int num); +static int mem_read(BIO *h, char *buf, int size); +static int mem_puts(BIO *h, const char *str); +static int mem_gets(BIO *h, char *str, int size); +static long mem_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int mem_new(BIO *h); +static int secmem_new(BIO *h); +static int mem_free(BIO *data); +static int mem_buf_free(BIO *data); +static int mem_buf_sync(BIO *h); + +static const BIO_METHOD mem_method = { + BIO_TYPE_MEM, + "memory buffer", + /* TODO: Convert to new style write function */ + bwrite_conv, + mem_write, + /* TODO: Convert to new style read function */ + bread_conv, + mem_read, + mem_puts, + mem_gets, + mem_ctrl, + mem_new, + mem_free, + NULL, /* mem_callback_ctrl */ +}; + +static const BIO_METHOD secmem_method = { + BIO_TYPE_MEM, + "secure memory buffer", + /* TODO: Convert to new style write function */ + bwrite_conv, + mem_write, + /* TODO: Convert to new style read function */ + bread_conv, + mem_read, + mem_puts, + mem_gets, + mem_ctrl, + secmem_new, + mem_free, + NULL, /* mem_callback_ctrl */ +}; + /* * BIO memory stores buffer and read pointer * however the roles are different for read only BIOs. * In that case the readp just stores the original state * to be used for reset. */ -typedef struct bio_buf_mem_st { - struct buf_mem_st *buf; /* allocated buffer */ - struct buf_mem_st *readp; /* read pointer */ -} BIO_BUF_MEM; - -/* - * bio->num is used to hold the value to return on 'empty', if it is 0, - * should_retry is not set - */ - -const BIO_METHOD *BIO_s_mem(void) -{ - return &mem_method; -} - -const BIO_METHOD *BIO_s_secmem(void) -{ - return(&secmem_method); -} - -BIO *BIO_new_mem_buf(const void *buf, int len) -{ - BIO *ret; - BUF_MEM *b; - BIO_BUF_MEM *bb; - size_t sz; - - if (buf == NULL) { - BIOerr(BIO_F_BIO_NEW_MEM_BUF, BIO_R_NULL_PARAMETER); - return NULL; - } - sz = (len < 0) ? strlen(buf) : (size_t)len; - if ((ret = BIO_new(BIO_s_mem())) == NULL) - return NULL; - bb = (BIO_BUF_MEM *)ret->ptr; - b = bb->buf; - /* Cast away const and trust in the MEM_RDONLY flag. */ - b->data = (void *)buf; - b->length = sz; - b->max = sz; - *bb->readp = *bb->buf; - ret->flags |= BIO_FLAGS_MEM_RDONLY; - /* Since this is static data retrying won't help */ - ret->num = 0; - return ret; -} - -static int mem_init(BIO *bi, unsigned long flags) -{ - BIO_BUF_MEM *bb = OPENSSL_zalloc(sizeof(*bb)); - - if (bb == NULL) - return 0; - if ((bb->buf = BUF_MEM_new_ex(flags)) == NULL) { - OPENSSL_free(bb); - return 0; - } - if ((bb->readp = OPENSSL_zalloc(sizeof(*bb->readp))) == NULL) { - BUF_MEM_free(bb->buf); - OPENSSL_free(bb); - return 0; - } - *bb->readp = *bb->buf; - bi->shutdown = 1; - bi->init = 1; - bi->num = -1; - bi->ptr = (char *)bb; - return 1; -} - -static int mem_new(BIO *bi) -{ - return mem_init(bi, 0L); -} - -static int secmem_new(BIO *bi) -{ - return mem_init(bi, BUF_MEM_FLAG_SECURE); -} - -static int mem_free(BIO *a) -{ - BIO_BUF_MEM *bb; - - if (a == NULL) - return 0; - - bb = (BIO_BUF_MEM *)a->ptr; - if (!mem_buf_free(a)) - return 0; - OPENSSL_free(bb->readp); - OPENSSL_free(bb); - return 1; -} - -static int mem_buf_free(BIO *a) -{ - if (a == NULL) - return 0; - - if (a->shutdown && a->init && a->ptr != NULL) { - BIO_BUF_MEM *bb = (BIO_BUF_MEM *)a->ptr; - BUF_MEM *b = bb->buf; - - if (a->flags & BIO_FLAGS_MEM_RDONLY) - b->data = NULL; - BUF_MEM_free(b); - } - return 1; -} - -/* - * Reallocate memory buffer if read pointer differs - */ -static int mem_buf_sync(BIO *b) -{ - if (b != NULL && b->init != 0 && b->ptr != NULL) { - BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr; - - if (bbm->readp->data != bbm->buf->data) { - memmove(bbm->buf->data, bbm->readp->data, bbm->readp->length); - bbm->buf->length = bbm->readp->length; - bbm->readp->data = bbm->buf->data; - } - } - return 0; -} - -static int mem_read(BIO *b, char *out, int outl) -{ - int ret = -1; - BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr; - BUF_MEM *bm = bbm->readp; - +typedef struct bio_buf_mem_st { + struct buf_mem_st *buf; /* allocated buffer */ + struct buf_mem_st *readp; /* read pointer */ +} BIO_BUF_MEM; + +/* + * bio->num is used to hold the value to return on 'empty', if it is 0, + * should_retry is not set + */ + +const BIO_METHOD *BIO_s_mem(void) +{ + return &mem_method; +} + +const BIO_METHOD *BIO_s_secmem(void) +{ + return(&secmem_method); +} + +BIO *BIO_new_mem_buf(const void *buf, int len) +{ + BIO *ret; + BUF_MEM *b; + BIO_BUF_MEM *bb; + size_t sz; + + if (buf == NULL) { + BIOerr(BIO_F_BIO_NEW_MEM_BUF, BIO_R_NULL_PARAMETER); + return NULL; + } + sz = (len < 0) ? strlen(buf) : (size_t)len; + if ((ret = BIO_new(BIO_s_mem())) == NULL) + return NULL; + bb = (BIO_BUF_MEM *)ret->ptr; + b = bb->buf; + /* Cast away const and trust in the MEM_RDONLY flag. */ + b->data = (void *)buf; + b->length = sz; + b->max = sz; + *bb->readp = *bb->buf; + ret->flags |= BIO_FLAGS_MEM_RDONLY; + /* Since this is static data retrying won't help */ + ret->num = 0; + return ret; +} + +static int mem_init(BIO *bi, unsigned long flags) +{ + BIO_BUF_MEM *bb = OPENSSL_zalloc(sizeof(*bb)); + + if (bb == NULL) + return 0; + if ((bb->buf = BUF_MEM_new_ex(flags)) == NULL) { + OPENSSL_free(bb); + return 0; + } + if ((bb->readp = OPENSSL_zalloc(sizeof(*bb->readp))) == NULL) { + BUF_MEM_free(bb->buf); + OPENSSL_free(bb); + return 0; + } + *bb->readp = *bb->buf; + bi->shutdown = 1; + bi->init = 1; + bi->num = -1; + bi->ptr = (char *)bb; + return 1; +} + +static int mem_new(BIO *bi) +{ + return mem_init(bi, 0L); +} + +static int secmem_new(BIO *bi) +{ + return mem_init(bi, BUF_MEM_FLAG_SECURE); +} + +static int mem_free(BIO *a) +{ + BIO_BUF_MEM *bb; + + if (a == NULL) + return 0; + + bb = (BIO_BUF_MEM *)a->ptr; + if (!mem_buf_free(a)) + return 0; + OPENSSL_free(bb->readp); + OPENSSL_free(bb); + return 1; +} + +static int mem_buf_free(BIO *a) +{ + if (a == NULL) + return 0; + + if (a->shutdown && a->init && a->ptr != NULL) { + BIO_BUF_MEM *bb = (BIO_BUF_MEM *)a->ptr; + BUF_MEM *b = bb->buf; + + if (a->flags & BIO_FLAGS_MEM_RDONLY) + b->data = NULL; + BUF_MEM_free(b); + } + return 1; +} + +/* + * Reallocate memory buffer if read pointer differs + */ +static int mem_buf_sync(BIO *b) +{ + if (b != NULL && b->init != 0 && b->ptr != NULL) { + BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr; + + if (bbm->readp->data != bbm->buf->data) { + memmove(bbm->buf->data, bbm->readp->data, bbm->readp->length); + bbm->buf->length = bbm->readp->length; + bbm->readp->data = bbm->buf->data; + } + } + return 0; +} + +static int mem_read(BIO *b, char *out, int outl) +{ + int ret = -1; + BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr; + BUF_MEM *bm = bbm->readp; + if (b->flags & BIO_FLAGS_MEM_RDONLY) bm = bbm->buf; - BIO_clear_retry_flags(b); - ret = (outl >= 0 && (size_t)outl > bm->length) ? (int)bm->length : outl; - if ((out != NULL) && (ret > 0)) { - memcpy(out, bm->data, ret); - bm->length -= ret; + BIO_clear_retry_flags(b); + ret = (outl >= 0 && (size_t)outl > bm->length) ? (int)bm->length : outl; + if ((out != NULL) && (ret > 0)) { + memcpy(out, bm->data, ret); + bm->length -= ret; bm->max -= ret; - bm->data += ret; - } else if (bm->length == 0) { - ret = b->num; - if (ret != 0) - BIO_set_retry_read(b); - } - return ret; -} - -static int mem_write(BIO *b, const char *in, int inl) -{ - int ret = -1; - int blen; - BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr; - - if (in == NULL) { - BIOerr(BIO_F_MEM_WRITE, BIO_R_NULL_PARAMETER); - goto end; - } - if (b->flags & BIO_FLAGS_MEM_RDONLY) { - BIOerr(BIO_F_MEM_WRITE, BIO_R_WRITE_TO_READ_ONLY_BIO); - goto end; - } - BIO_clear_retry_flags(b); - if (inl == 0) - return 0; - blen = bbm->readp->length; - mem_buf_sync(b); - if (BUF_MEM_grow_clean(bbm->buf, blen + inl) == 0) - goto end; - memcpy(bbm->buf->data + blen, in, inl); - *bbm->readp = *bbm->buf; - ret = inl; - end: - return ret; -} - -static long mem_ctrl(BIO *b, int cmd, long num, void *ptr) -{ - long ret = 1; - char **pptr; - BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr; - BUF_MEM *bm; - + bm->data += ret; + } else if (bm->length == 0) { + ret = b->num; + if (ret != 0) + BIO_set_retry_read(b); + } + return ret; +} + +static int mem_write(BIO *b, const char *in, int inl) +{ + int ret = -1; + int blen; + BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr; + + if (in == NULL) { + BIOerr(BIO_F_MEM_WRITE, BIO_R_NULL_PARAMETER); + goto end; + } + if (b->flags & BIO_FLAGS_MEM_RDONLY) { + BIOerr(BIO_F_MEM_WRITE, BIO_R_WRITE_TO_READ_ONLY_BIO); + goto end; + } + BIO_clear_retry_flags(b); + if (inl == 0) + return 0; + blen = bbm->readp->length; + mem_buf_sync(b); + if (BUF_MEM_grow_clean(bbm->buf, blen + inl) == 0) + goto end; + memcpy(bbm->buf->data + blen, in, inl); + *bbm->readp = *bbm->buf; + ret = inl; + end: + return ret; +} + +static long mem_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + long ret = 1; + char **pptr; + BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)b->ptr; + BUF_MEM *bm; + if (b->flags & BIO_FLAGS_MEM_RDONLY) bm = bbm->buf; else bm = bbm->readp; - switch (cmd) { - case BIO_CTRL_RESET: - bm = bbm->buf; - if (bm->data != NULL) { + switch (cmd) { + case BIO_CTRL_RESET: + bm = bbm->buf; + if (bm->data != NULL) { if (!(b->flags & BIO_FLAGS_MEM_RDONLY)) { if (!(b->flags & BIO_FLAGS_NONCLEAR_RST)) { memset(bm->data, 0, bm->max); bm->length = 0; } *bbm->readp = *bbm->buf; - } else { + } else { /* For read only case just reset to the start again */ *bbm->buf = *bbm->readp; - } - } - break; - case BIO_CTRL_EOF: - ret = (long)(bm->length == 0); - break; - case BIO_C_SET_BUF_MEM_EOF_RETURN: - b->num = (int)num; - break; - case BIO_CTRL_INFO: - ret = (long)bm->length; - if (ptr != NULL) { - pptr = (char **)ptr; - *pptr = (char *)&(bm->data[0]); - } - break; - case BIO_C_SET_BUF_MEM: - mem_buf_free(b); - b->shutdown = (int)num; - bbm->buf = ptr; - *bbm->readp = *bbm->buf; - break; - case BIO_C_GET_BUF_MEM_PTR: - if (ptr != NULL) { + } + } + break; + case BIO_CTRL_EOF: + ret = (long)(bm->length == 0); + break; + case BIO_C_SET_BUF_MEM_EOF_RETURN: + b->num = (int)num; + break; + case BIO_CTRL_INFO: + ret = (long)bm->length; + if (ptr != NULL) { + pptr = (char **)ptr; + *pptr = (char *)&(bm->data[0]); + } + break; + case BIO_C_SET_BUF_MEM: + mem_buf_free(b); + b->shutdown = (int)num; + bbm->buf = ptr; + *bbm->readp = *bbm->buf; + break; + case BIO_C_GET_BUF_MEM_PTR: + if (ptr != NULL) { if (!(b->flags & BIO_FLAGS_MEM_RDONLY)) mem_buf_sync(b); bm = bbm->buf; - pptr = (char **)ptr; - *pptr = (char *)bm; - } - break; - case BIO_CTRL_GET_CLOSE: - ret = (long)b->shutdown; - break; - case BIO_CTRL_SET_CLOSE: - b->shutdown = (int)num; - break; - case BIO_CTRL_WPENDING: - ret = 0L; - break; - case BIO_CTRL_PENDING: - ret = (long)bm->length; - break; - case BIO_CTRL_DUP: - case BIO_CTRL_FLUSH: - ret = 1; - break; - case BIO_CTRL_PUSH: - case BIO_CTRL_POP: - default: - ret = 0; - break; - } - return ret; -} - -static int mem_gets(BIO *bp, char *buf, int size) -{ - int i, j; - int ret = -1; - char *p; - BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)bp->ptr; - BUF_MEM *bm = bbm->readp; - + pptr = (char **)ptr; + *pptr = (char *)bm; + } + break; + case BIO_CTRL_GET_CLOSE: + ret = (long)b->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + b->shutdown = (int)num; + break; + case BIO_CTRL_WPENDING: + ret = 0L; + break; + case BIO_CTRL_PENDING: + ret = (long)bm->length; + break; + case BIO_CTRL_DUP: + case BIO_CTRL_FLUSH: + ret = 1; + break; + case BIO_CTRL_PUSH: + case BIO_CTRL_POP: + default: + ret = 0; + break; + } + return ret; +} + +static int mem_gets(BIO *bp, char *buf, int size) +{ + int i, j; + int ret = -1; + char *p; + BIO_BUF_MEM *bbm = (BIO_BUF_MEM *)bp->ptr; + BUF_MEM *bm = bbm->readp; + if (bp->flags & BIO_FLAGS_MEM_RDONLY) bm = bbm->buf; - BIO_clear_retry_flags(bp); - j = bm->length; - if ((size - 1) < j) - j = size - 1; - if (j <= 0) { - *buf = '\0'; - return 0; - } - p = bm->data; - for (i = 0; i < j; i++) { - if (p[i] == '\n') { - i++; - break; - } - } - - /* - * i is now the max num of bytes to copy, either j or up to - * and including the first newline - */ - - i = mem_read(bp, buf, i); - if (i > 0) - buf[i] = '\0'; - ret = i; - return ret; -} - -static int mem_puts(BIO *bp, const char *str) -{ - int n, ret; - - n = strlen(str); - ret = mem_write(bp, str, n); - /* memory semantics is that it will always work */ - return ret; -} + BIO_clear_retry_flags(bp); + j = bm->length; + if ((size - 1) < j) + j = size - 1; + if (j <= 0) { + *buf = '\0'; + return 0; + } + p = bm->data; + for (i = 0; i < j; i++) { + if (p[i] == '\n') { + i++; + break; + } + } + + /* + * i is now the max num of bytes to copy, either j or up to + * and including the first newline + */ + + i = mem_read(bp, buf, i); + if (i > 0) + buf[i] = '\0'; + ret = i; + return ret; +} + +static int mem_puts(BIO *bp, const char *str) +{ + int n, ret; + + n = strlen(str); + ret = mem_write(bp, str, n); + /* memory semantics is that it will always work */ + return ret; +} diff --git a/contrib/libs/openssl/crypto/bio/bss_null.c b/contrib/libs/openssl/crypto/bio/bss_null.c index 4ebff60e20..e73ce7841d 100644 --- a/contrib/libs/openssl/crypto/bio/bss_null.c +++ b/contrib/libs/openssl/crypto/bio/bss_null.c @@ -1,87 +1,87 @@ -/* - * Copyright 1995-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 - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -#include <stdio.h> -#include <errno.h> +/* + * Copyright 1995-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 + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html + */ + +#include <stdio.h> +#include <errno.h> #include "bio_local.h" -#include "internal/cryptlib.h" - -static int null_write(BIO *h, const char *buf, int num); -static int null_read(BIO *h, char *buf, int size); -static int null_puts(BIO *h, const char *str); -static int null_gets(BIO *h, char *str, int size); -static long null_ctrl(BIO *h, int cmd, long arg1, void *arg2); -static const BIO_METHOD null_method = { - BIO_TYPE_NULL, - "NULL", - /* TODO: Convert to new style write function */ - bwrite_conv, - null_write, - /* TODO: Convert to new style read function */ - bread_conv, - null_read, - null_puts, - null_gets, - null_ctrl, - NULL, - NULL, - NULL, /* null_callback_ctrl */ -}; - -const BIO_METHOD *BIO_s_null(void) -{ - return &null_method; -} - -static int null_read(BIO *b, char *out, int outl) -{ - return 0; -} - -static int null_write(BIO *b, const char *in, int inl) -{ - return inl; -} - -static long null_ctrl(BIO *b, int cmd, long num, void *ptr) -{ - long ret = 1; - - switch (cmd) { - case BIO_CTRL_RESET: - case BIO_CTRL_EOF: - case BIO_CTRL_SET: - case BIO_CTRL_SET_CLOSE: - case BIO_CTRL_FLUSH: - case BIO_CTRL_DUP: - ret = 1; - break; - case BIO_CTRL_GET_CLOSE: - case BIO_CTRL_INFO: - case BIO_CTRL_GET: - case BIO_CTRL_PENDING: - case BIO_CTRL_WPENDING: - default: - ret = 0; - break; - } - return ret; -} - -static int null_gets(BIO *bp, char *buf, int size) -{ - return 0; -} - -static int null_puts(BIO *bp, const char *str) -{ - if (str == NULL) - return 0; - return strlen(str); -} +#include "internal/cryptlib.h" + +static int null_write(BIO *h, const char *buf, int num); +static int null_read(BIO *h, char *buf, int size); +static int null_puts(BIO *h, const char *str); +static int null_gets(BIO *h, char *str, int size); +static long null_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static const BIO_METHOD null_method = { + BIO_TYPE_NULL, + "NULL", + /* TODO: Convert to new style write function */ + bwrite_conv, + null_write, + /* TODO: Convert to new style read function */ + bread_conv, + null_read, + null_puts, + null_gets, + null_ctrl, + NULL, + NULL, + NULL, /* null_callback_ctrl */ +}; + +const BIO_METHOD *BIO_s_null(void) +{ + return &null_method; +} + +static int null_read(BIO *b, char *out, int outl) +{ + return 0; +} + +static int null_write(BIO *b, const char *in, int inl) +{ + return inl; +} + +static long null_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + long ret = 1; + + switch (cmd) { + case BIO_CTRL_RESET: + case BIO_CTRL_EOF: + case BIO_CTRL_SET: + case BIO_CTRL_SET_CLOSE: + case BIO_CTRL_FLUSH: + case BIO_CTRL_DUP: + ret = 1; + break; + case BIO_CTRL_GET_CLOSE: + case BIO_CTRL_INFO: + case BIO_CTRL_GET: + case BIO_CTRL_PENDING: + case BIO_CTRL_WPENDING: + default: + ret = 0; + break; + } + return ret; +} + +static int null_gets(BIO *bp, char *buf, int size) +{ + return 0; +} + +static int null_puts(BIO *bp, const char *str) +{ + if (str == NULL) + return 0; + return strlen(str); +} diff --git a/contrib/libs/openssl/crypto/bio/bss_sock.c b/contrib/libs/openssl/crypto/bio/bss_sock.c index 63ede6bbf7..6251f3d46a 100644 --- a/contrib/libs/openssl/crypto/bio/bss_sock.c +++ b/contrib/libs/openssl/crypto/bio/bss_sock.c @@ -1,238 +1,238 @@ -/* +/* * Copyright 1995-2020 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 - * in the file LICENSE in the source distribution or at - * https://www.openssl.org/source/license.html - */ - -#include <stdio.h> -#include <errno.h> + * + * Licensed under the OpenSSL license (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 <stdio.h> +#include <errno.h> #include "bio_local.h" -#include "internal/cryptlib.h" - -#ifndef OPENSSL_NO_SOCK - -# include <openssl/bio.h> - -# ifdef WATT32 -/* Watt-32 uses same names */ -# undef sock_write -# undef sock_read -# undef sock_puts -# define sock_write SockWrite -# define sock_read SockRead -# define sock_puts SockPuts -# endif - -static int sock_write(BIO *h, const char *buf, int num); -static int sock_read(BIO *h, char *buf, int size); -static int sock_puts(BIO *h, const char *str); -static long sock_ctrl(BIO *h, int cmd, long arg1, void *arg2); -static int sock_new(BIO *h); -static int sock_free(BIO *data); -int BIO_sock_should_retry(int s); - -static const BIO_METHOD methods_sockp = { - BIO_TYPE_SOCKET, - "socket", - /* TODO: Convert to new style write function */ - bwrite_conv, - sock_write, - /* TODO: Convert to new style read function */ - bread_conv, - sock_read, - sock_puts, - NULL, /* sock_gets, */ - sock_ctrl, - sock_new, - sock_free, - NULL, /* sock_callback_ctrl */ -}; - -const BIO_METHOD *BIO_s_socket(void) -{ - return &methods_sockp; -} - -BIO *BIO_new_socket(int fd, int close_flag) -{ - BIO *ret; - - ret = BIO_new(BIO_s_socket()); - if (ret == NULL) - return NULL; - BIO_set_fd(ret, fd, close_flag); - return ret; -} - -static int sock_new(BIO *bi) -{ - bi->init = 0; - bi->num = 0; - bi->ptr = NULL; - bi->flags = 0; - return 1; -} - -static int sock_free(BIO *a) -{ - if (a == NULL) - return 0; - if (a->shutdown) { - if (a->init) { - BIO_closesocket(a->num); - } - a->init = 0; - a->flags = 0; - } - return 1; -} - -static int sock_read(BIO *b, char *out, int outl) -{ - int ret = 0; - - if (out != NULL) { - clear_socket_error(); - ret = readsocket(b->num, out, outl); - BIO_clear_retry_flags(b); - if (ret <= 0) { - if (BIO_sock_should_retry(ret)) - BIO_set_retry_read(b); +#include "internal/cryptlib.h" + +#ifndef OPENSSL_NO_SOCK + +# include <openssl/bio.h> + +# ifdef WATT32 +/* Watt-32 uses same names */ +# undef sock_write +# undef sock_read +# undef sock_puts +# define sock_write SockWrite +# define sock_read SockRead +# define sock_puts SockPuts +# endif + +static int sock_write(BIO *h, const char *buf, int num); +static int sock_read(BIO *h, char *buf, int size); +static int sock_puts(BIO *h, const char *str); +static long sock_ctrl(BIO *h, int cmd, long arg1, void *arg2); +static int sock_new(BIO *h); +static int sock_free(BIO *data); +int BIO_sock_should_retry(int s); + +static const BIO_METHOD methods_sockp = { + BIO_TYPE_SOCKET, + "socket", + /* TODO: Convert to new style write function */ + bwrite_conv, + sock_write, + /* TODO: Convert to new style read function */ + bread_conv, + sock_read, + sock_puts, + NULL, /* sock_gets, */ + sock_ctrl, + sock_new, + sock_free, + NULL, /* sock_callback_ctrl */ +}; + +const BIO_METHOD *BIO_s_socket(void) +{ + return &methods_sockp; +} + +BIO *BIO_new_socket(int fd, int close_flag) +{ + BIO *ret; + + ret = BIO_new(BIO_s_socket()); + if (ret == NULL) + return NULL; + BIO_set_fd(ret, fd, close_flag); + return ret; +} + +static int sock_new(BIO *bi) +{ + bi->init = 0; + bi->num = 0; + bi->ptr = NULL; + bi->flags = 0; + return 1; +} + +static int sock_free(BIO *a) +{ + if (a == NULL) + return 0; + if (a->shutdown) { + if (a->init) { + BIO_closesocket(a->num); + } + a->init = 0; + a->flags = 0; + } + return 1; +} + +static int sock_read(BIO *b, char *out, int outl) +{ + int ret = 0; + + if (out != NULL) { + clear_socket_error(); + ret = readsocket(b->num, out, outl); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (BIO_sock_should_retry(ret)) + BIO_set_retry_read(b); else if (ret == 0) b->flags |= BIO_FLAGS_IN_EOF; - } - } - return ret; -} - -static int sock_write(BIO *b, const char *in, int inl) -{ - int ret; - - clear_socket_error(); - ret = writesocket(b->num, in, inl); - BIO_clear_retry_flags(b); - if (ret <= 0) { - if (BIO_sock_should_retry(ret)) - BIO_set_retry_write(b); - } - return ret; -} - -static long sock_ctrl(BIO *b, int cmd, long num, void *ptr) -{ - long ret = 1; - int *ip; - - switch (cmd) { - case BIO_C_SET_FD: - sock_free(b); - b->num = *((int *)ptr); - b->shutdown = (int)num; - b->init = 1; - break; - case BIO_C_GET_FD: - if (b->init) { - ip = (int *)ptr; - if (ip != NULL) - *ip = b->num; - ret = b->num; - } else - ret = -1; - break; - case BIO_CTRL_GET_CLOSE: - ret = b->shutdown; - break; - case BIO_CTRL_SET_CLOSE: - b->shutdown = (int)num; - break; - case BIO_CTRL_DUP: - case BIO_CTRL_FLUSH: - ret = 1; - break; + } + } + return ret; +} + +static int sock_write(BIO *b, const char *in, int inl) +{ + int ret; + + clear_socket_error(); + ret = writesocket(b->num, in, inl); + BIO_clear_retry_flags(b); + if (ret <= 0) { + if (BIO_sock_should_retry(ret)) + BIO_set_retry_write(b); + } + return ret; +} + +static long sock_ctrl(BIO *b, int cmd, long num, void *ptr) +{ + long ret = 1; + int *ip; + + switch (cmd) { + case BIO_C_SET_FD: + sock_free(b); + b->num = *((int *)ptr); + b->shutdown = (int)num; + b->init = 1; + break; + case BIO_C_GET_FD: + if (b->init) { + ip = (int *)ptr; + if (ip != NULL) + *ip = b->num; + ret = b->num; + } else + ret = -1; + break; + case BIO_CTRL_GET_CLOSE: + ret = b->shutdown; + break; + case BIO_CTRL_SET_CLOSE: + b->shutdown = (int)num; + break; + case BIO_CTRL_DUP: + case BIO_CTRL_FLUSH: + ret = 1; + break; case BIO_CTRL_EOF: ret = (b->flags & BIO_FLAGS_IN_EOF) != 0 ? 1 : 0; break; - default: - ret = 0; - break; - } - return ret; -} - -static int sock_puts(BIO *bp, const char *str) -{ - int n, ret; - - n = strlen(str); - ret = sock_write(bp, str, n); - return ret; -} - -int BIO_sock_should_retry(int i) -{ - int err; - - if ((i == 0) || (i == -1)) { - err = get_last_socket_error(); - - return BIO_sock_non_fatal_error(err); - } - return 0; -} - -int BIO_sock_non_fatal_error(int err) -{ - switch (err) { -# if defined(OPENSSL_SYS_WINDOWS) -# if defined(WSAEWOULDBLOCK) - case WSAEWOULDBLOCK: -# endif -# endif - -# ifdef EWOULDBLOCK -# ifdef WSAEWOULDBLOCK -# if WSAEWOULDBLOCK != EWOULDBLOCK - case EWOULDBLOCK: -# endif -# else - case EWOULDBLOCK: -# endif -# endif - -# if defined(ENOTCONN) - case ENOTCONN: -# endif - -# ifdef EINTR - case EINTR: -# endif - -# ifdef EAGAIN -# if EWOULDBLOCK != EAGAIN - case EAGAIN: -# endif -# endif - -# ifdef EPROTO - case EPROTO: -# endif - -# ifdef EINPROGRESS - case EINPROGRESS: -# endif - -# ifdef EALREADY - case EALREADY: -# endif - return 1; - default: - break; - } - return 0; -} - -#endif /* #ifndef OPENSSL_NO_SOCK */ + default: + ret = 0; + break; + } + return ret; +} + +static int sock_puts(BIO *bp, const char *str) +{ + int n, ret; + + n = strlen(str); + ret = sock_write(bp, str, n); + return ret; +} + +int BIO_sock_should_retry(int i) +{ + int err; + + if ((i == 0) || (i == -1)) { + err = get_last_socket_error(); + + return BIO_sock_non_fatal_error(err); + } + return 0; +} + +int BIO_sock_non_fatal_error(int err) +{ + switch (err) { +# if defined(OPENSSL_SYS_WINDOWS) +# if defined(WSAEWOULDBLOCK) + case WSAEWOULDBLOCK: +# endif +# endif + +# ifdef EWOULDBLOCK +# ifdef WSAEWOULDBLOCK +# if WSAEWOULDBLOCK != EWOULDBLOCK + case EWOULDBLOCK: +# endif +# else + case EWOULDBLOCK: +# endif +# endif + +# if defined(ENOTCONN) + case ENOTCONN: +# endif + +# ifdef EINTR + case EINTR: +# endif + +# ifdef EAGAIN +# if EWOULDBLOCK != EAGAIN + case EAGAIN: +# endif +# endif + +# ifdef EPROTO + case EPROTO: +# endif + +# ifdef EINPROGRESS + case EINPROGRESS: +# endif + +# ifdef EALREADY + case EALREADY: +# endif + return 1; + default: + break; + } + return 0; +} + +#endif /* #ifndef OPENSSL_NO_SOCK */ |