common.c revision 253680
140939Sdes/*- 2226537Sdes * Copyright (c) 1998-2011 Dag-Erling Sm��rgrav 3253680Sdes * Copyright (c) 2013 Michael Gmelin <freebsd@grem.de> 440939Sdes * All rights reserved. 540939Sdes * 640939Sdes * Redistribution and use in source and binary forms, with or without 740939Sdes * modification, are permitted provided that the following conditions 840939Sdes * are met: 940939Sdes * 1. Redistributions of source code must retain the above copyright 1040939Sdes * notice, this list of conditions and the following disclaimer 1140939Sdes * in this position and unchanged. 1240939Sdes * 2. Redistributions in binary form must reproduce the above copyright 1340939Sdes * notice, this list of conditions and the following disclaimer in the 1440939Sdes * documentation and/or other materials provided with the distribution. 1540939Sdes * 3. The name of the author may not be used to endorse or promote products 1640939Sdes * derived from this software without specific prior written permission 1740939Sdes * 1840939Sdes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1940939Sdes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 2040939Sdes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 2140939Sdes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 2240939Sdes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2340939Sdes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2440939Sdes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2540939Sdes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2640939Sdes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2740939Sdes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2840939Sdes */ 2940939Sdes 3084203Sdillon#include <sys/cdefs.h> 3184203Sdillon__FBSDID("$FreeBSD: head/lib/libfetch/common.c 253680 2013-07-26 15:53:43Z des $"); 3284203Sdillon 3341862Sdes#include <sys/param.h> 3440939Sdes#include <sys/socket.h> 3555557Sdes#include <sys/time.h> 3662981Sdes#include <sys/uio.h> 37174752Sdes 3840939Sdes#include <netinet/in.h> 3940939Sdes 40174752Sdes#include <ctype.h> 4140939Sdes#include <errno.h> 42210568Sdes#include <fcntl.h> 4340939Sdes#include <netdb.h> 44109695Sdes#include <pwd.h> 4560924Sdes#include <stdarg.h> 4641862Sdes#include <stdlib.h> 4741862Sdes#include <stdio.h> 4840939Sdes#include <string.h> 4940939Sdes#include <unistd.h> 5040939Sdes 51253680Sdes#ifdef WITH_SSL 52253680Sdes#include <openssl/x509v3.h> 53253680Sdes#endif 54253680Sdes 5540939Sdes#include "fetch.h" 5640939Sdes#include "common.h" 5740939Sdes 5840975Sdes 5940939Sdes/*** Local data **************************************************************/ 6040939Sdes 6140939Sdes/* 6240939Sdes * Error messages for resolver errors 6340939Sdes */ 64174588Sdesstatic struct fetcherr netdb_errlist[] = { 65121423Sume#ifdef EAI_NODATA 6690267Sdes { EAI_NODATA, FETCH_RESOLV, "Host not found" }, 67121423Sume#endif 6890267Sdes { EAI_AGAIN, FETCH_TEMP, "Transient resolver failure" }, 6990267Sdes { EAI_FAIL, FETCH_RESOLV, "Non-recoverable resolver failure" }, 7090267Sdes { EAI_NONAME, FETCH_RESOLV, "No address record" }, 7190267Sdes { -1, FETCH_UNKNOWN, "Unknown resolver error" } 7240939Sdes}; 7340939Sdes 7462981Sdes/* End-of-Line */ 7575891Sarchiestatic const char ENDL[2] = "\r\n"; 7640939Sdes 7762981Sdes 7840939Sdes/*** Error-reporting functions ***********************************************/ 7940939Sdes 8040939Sdes/* 8140939Sdes * Map error code to string 8240939Sdes */ 8360924Sdesstatic struct fetcherr * 84174588Sdesfetch_finderr(struct fetcherr *p, int e) 8540939Sdes{ 8690267Sdes while (p->num != -1 && p->num != e) 8790267Sdes p++; 8890267Sdes return (p); 8940939Sdes} 9040939Sdes 9140939Sdes/* 9240939Sdes * Set error code 9340939Sdes */ 9440939Sdesvoid 95174588Sdesfetch_seterr(struct fetcherr *p, int e) 9640939Sdes{ 97174588Sdes p = fetch_finderr(p, e); 9890267Sdes fetchLastErrCode = p->cat; 9990267Sdes snprintf(fetchLastErrString, MAXERRSTRING, "%s", p->string); 10040939Sdes} 10140939Sdes 10240939Sdes/* 10340939Sdes * Set error code according to errno 10440939Sdes */ 10540939Sdesvoid 106174588Sdesfetch_syserr(void) 10740939Sdes{ 10890267Sdes switch (errno) { 10990267Sdes case 0: 11090267Sdes fetchLastErrCode = FETCH_OK; 11190267Sdes break; 11290267Sdes case EPERM: 11390267Sdes case EACCES: 11490267Sdes case EROFS: 11590267Sdes case EAUTH: 11690267Sdes case ENEEDAUTH: 11790267Sdes fetchLastErrCode = FETCH_AUTH; 11890267Sdes break; 11990267Sdes case ENOENT: 12090267Sdes case EISDIR: /* XXX */ 12190267Sdes fetchLastErrCode = FETCH_UNAVAIL; 12290267Sdes break; 12390267Sdes case ENOMEM: 12490267Sdes fetchLastErrCode = FETCH_MEMORY; 12590267Sdes break; 12690267Sdes case EBUSY: 12790267Sdes case EAGAIN: 12890267Sdes fetchLastErrCode = FETCH_TEMP; 12990267Sdes break; 13090267Sdes case EEXIST: 13190267Sdes fetchLastErrCode = FETCH_EXISTS; 13290267Sdes break; 13390267Sdes case ENOSPC: 13490267Sdes fetchLastErrCode = FETCH_FULL; 13590267Sdes break; 13690267Sdes case EADDRINUSE: 13790267Sdes case EADDRNOTAVAIL: 13890267Sdes case ENETDOWN: 13990267Sdes case ENETUNREACH: 14090267Sdes case ENETRESET: 14190267Sdes case EHOSTUNREACH: 14290267Sdes fetchLastErrCode = FETCH_NETWORK; 14390267Sdes break; 14490267Sdes case ECONNABORTED: 14590267Sdes case ECONNRESET: 14690267Sdes fetchLastErrCode = FETCH_ABORT; 14790267Sdes break; 14890267Sdes case ETIMEDOUT: 14990267Sdes fetchLastErrCode = FETCH_TIMEOUT; 15090267Sdes break; 15190267Sdes case ECONNREFUSED: 15290267Sdes case EHOSTDOWN: 15390267Sdes fetchLastErrCode = FETCH_DOWN; 15490267Sdes break; 15590267Sdesdefault: 15690267Sdes fetchLastErrCode = FETCH_UNKNOWN; 15790267Sdes } 15890267Sdes snprintf(fetchLastErrString, MAXERRSTRING, "%s", strerror(errno)); 15940939Sdes} 16040939Sdes 16140939Sdes 16241862Sdes/* 16341862Sdes * Emit status message 16441862Sdes */ 16560924Sdesvoid 166174588Sdesfetch_info(const char *fmt, ...) 16741862Sdes{ 16890267Sdes va_list ap; 16990267Sdes 17090267Sdes va_start(ap, fmt); 17190267Sdes vfprintf(stderr, fmt, ap); 17290267Sdes va_end(ap); 17390267Sdes fputc('\n', stderr); 17441862Sdes} 17541862Sdes 17641862Sdes 17740939Sdes/*** Network-related utility functions ***************************************/ 17840939Sdes 17940939Sdes/* 18068551Sdes * Return the default port for a scheme 18168551Sdes */ 18268551Sdesint 183174588Sdesfetch_default_port(const char *scheme) 18468551Sdes{ 18590267Sdes struct servent *se; 18668551Sdes 18790267Sdes if ((se = getservbyname(scheme, "tcp")) != NULL) 18890267Sdes return (ntohs(se->s_port)); 18990267Sdes if (strcasecmp(scheme, SCHEME_FTP) == 0) 19090267Sdes return (FTP_DEFAULT_PORT); 19190267Sdes if (strcasecmp(scheme, SCHEME_HTTP) == 0) 19290267Sdes return (HTTP_DEFAULT_PORT); 19390267Sdes return (0); 19468551Sdes} 19568551Sdes 19668551Sdes/* 19768551Sdes * Return the default proxy port for a scheme 19868551Sdes */ 19968551Sdesint 200174588Sdesfetch_default_proxy_port(const char *scheme) 20168551Sdes{ 20290267Sdes if (strcasecmp(scheme, SCHEME_FTP) == 0) 20390267Sdes return (FTP_DEFAULT_PROXY_PORT); 20490267Sdes if (strcasecmp(scheme, SCHEME_HTTP) == 0) 20590267Sdes return (HTTP_DEFAULT_PROXY_PORT); 20690267Sdes return (0); 20768551Sdes} 20868551Sdes 20998117Sdes 21068551Sdes/* 21197866Sdes * Create a connection for an existing descriptor. 21297866Sdes */ 21397866Sdesconn_t * 214174588Sdesfetch_reopen(int sd) 21597866Sdes{ 21697866Sdes conn_t *conn; 217236193Sjilles int opt = 1; 21897866Sdes 21997866Sdes /* allocate and fill connection structure */ 220109967Sdes if ((conn = calloc(1, sizeof(*conn))) == NULL) 22197866Sdes return (NULL); 222221830Sdes fcntl(sd, F_SETFD, FD_CLOEXEC); 223236193Sjilles setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof opt); 22497866Sdes conn->sd = sd; 22598117Sdes ++conn->ref; 22697866Sdes return (conn); 22797866Sdes} 22897866Sdes 22997866Sdes 23097866Sdes/* 23198117Sdes * Bump a connection's reference count. 23298117Sdes */ 23398117Sdesconn_t * 234174588Sdesfetch_ref(conn_t *conn) 23598117Sdes{ 23698117Sdes 23798117Sdes ++conn->ref; 23898117Sdes return (conn); 23998117Sdes} 24098117Sdes 24198117Sdes 24298117Sdes/* 243111816Sdes * Bind a socket to a specific local address 244111816Sdes */ 245111816Sdesint 246174588Sdesfetch_bind(int sd, int af, const char *addr) 247111816Sdes{ 248111816Sdes struct addrinfo hints, *res, *res0; 249111816Sdes int err; 250111816Sdes 251111816Sdes memset(&hints, 0, sizeof(hints)); 252111816Sdes hints.ai_family = af; 253111816Sdes hints.ai_socktype = SOCK_STREAM; 254111816Sdes hints.ai_protocol = 0; 255111816Sdes if ((err = getaddrinfo(addr, NULL, &hints, &res0)) != 0) 256111816Sdes return (-1); 257111816Sdes for (res = res0; res; res = res->ai_next) 258111816Sdes if (bind(sd, res->ai_addr, res->ai_addrlen) == 0) 259111816Sdes return (0); 260111816Sdes return (-1); 261111816Sdes} 262111816Sdes 263111816Sdes 264111816Sdes/* 26540939Sdes * Establish a TCP connection to the specified port on the specified host. 26640939Sdes */ 26797856Sdesconn_t * 268174588Sdesfetch_connect(const char *host, int port, int af, int verbose) 26940939Sdes{ 27097856Sdes conn_t *conn; 27190267Sdes char pbuf[10]; 272111816Sdes const char *bindaddr; 27390267Sdes struct addrinfo hints, *res, *res0; 27490267Sdes int sd, err; 27540939Sdes 27690267Sdes DEBUG(fprintf(stderr, "---> %s:%d\n", host, port)); 27741862Sdes 27890267Sdes if (verbose) 279174588Sdes fetch_info("looking up %s", host); 28040939Sdes 28190267Sdes /* look up host name and set up socket address structure */ 28290267Sdes snprintf(pbuf, sizeof(pbuf), "%d", port); 28390267Sdes memset(&hints, 0, sizeof(hints)); 28490267Sdes hints.ai_family = af; 28590267Sdes hints.ai_socktype = SOCK_STREAM; 28690267Sdes hints.ai_protocol = 0; 28790267Sdes if ((err = getaddrinfo(host, pbuf, &hints, &res0)) != 0) { 288174588Sdes netdb_seterr(err); 28997856Sdes return (NULL); 29090267Sdes } 291111816Sdes bindaddr = getenv("FETCH_BIND_ADDRESS"); 29290267Sdes 29390267Sdes if (verbose) 294174588Sdes fetch_info("connecting to %s:%d", host, port); 29590267Sdes 29690267Sdes /* try to connect */ 297111816Sdes for (sd = -1, res = res0; res; sd = -1, res = res->ai_next) { 29890267Sdes if ((sd = socket(res->ai_family, res->ai_socktype, 29962981Sdes res->ai_protocol)) == -1) 30090267Sdes continue; 301111816Sdes if (bindaddr != NULL && *bindaddr != '\0' && 302174588Sdes fetch_bind(sd, res->ai_family, bindaddr) != 0) { 303174588Sdes fetch_info("failed to bind to '%s'", bindaddr); 304111816Sdes close(sd); 305111816Sdes continue; 306111816Sdes } 307210568Sdes if (connect(sd, res->ai_addr, res->ai_addrlen) == 0 && 308210568Sdes fcntl(sd, F_SETFL, O_NONBLOCK) == 0) 30990267Sdes break; 31090267Sdes close(sd); 31190267Sdes } 31290267Sdes freeaddrinfo(res0); 31390267Sdes if (sd == -1) { 314174588Sdes fetch_syserr(); 31597856Sdes return (NULL); 31690267Sdes } 31740939Sdes 318174588Sdes if ((conn = fetch_reopen(sd)) == NULL) { 319174588Sdes fetch_syserr(); 32097856Sdes close(sd); 321103459Sfenner } 32297856Sdes return (conn); 32340939Sdes} 32441989Sdes 325253680Sdes#ifdef WITH_SSL 326253680Sdes/* 327253680Sdes * Convert characters A-Z to lowercase (intentionally avoid any locale 328253680Sdes * specific conversions). 329253680Sdes */ 330253680Sdesstatic char 331253680Sdesfetch_ssl_tolower(char in) 332253680Sdes{ 333253680Sdes if (in >= 'A' && in <= 'Z') 334253680Sdes return (in + 32); 335253680Sdes else 336253680Sdes return (in); 337253680Sdes} 33841989Sdes 33955557Sdes/* 340253680Sdes * isalpha implementation that intentionally avoids any locale specific 341253680Sdes * conversions. 342253680Sdes */ 343253680Sdesstatic int 344253680Sdesfetch_ssl_isalpha(char in) 345253680Sdes{ 346253680Sdes return ((in >= 'A' && in <= 'Z') || (in >= 'a' && in <= 'z')); 347253680Sdes} 348253680Sdes 349253680Sdes/* 350253680Sdes * Check if passed hostnames a and b are equal. 351253680Sdes */ 352253680Sdesstatic int 353253680Sdesfetch_ssl_hname_equal(const char *a, size_t alen, const char *b, 354253680Sdes size_t blen) 355253680Sdes{ 356253680Sdes size_t i; 357253680Sdes 358253680Sdes if (alen != blen) 359253680Sdes return (0); 360253680Sdes for (i = 0; i < alen; ++i) { 361253680Sdes if (fetch_ssl_tolower(a[i]) != fetch_ssl_tolower(b[i])) 362253680Sdes return (0); 363253680Sdes } 364253680Sdes return (1); 365253680Sdes} 366253680Sdes 367253680Sdes/* 368253680Sdes * Check if domain label is traditional, meaning that only A-Z, a-z, 0-9 369253680Sdes * and '-' (hyphen) are allowed. Hyphens have to be surrounded by alpha- 370253680Sdes * numeric characters. Double hyphens (like they're found in IDN a-labels 371253680Sdes * 'xn--') are not allowed. Empty labels are invalid. 372253680Sdes */ 373253680Sdesstatic int 374253680Sdesfetch_ssl_is_trad_domain_label(const char *l, size_t len, int wcok) 375253680Sdes{ 376253680Sdes size_t i; 377253680Sdes 378253680Sdes if (!len || l[0] == '-' || l[len-1] == '-') 379253680Sdes return (0); 380253680Sdes for (i = 0; i < len; ++i) { 381253680Sdes if (!isdigit(l[i]) && 382253680Sdes !fetch_ssl_isalpha(l[i]) && 383253680Sdes !(l[i] == '*' && wcok) && 384253680Sdes !(l[i] == '-' && l[i - 1] != '-')) 385253680Sdes return (0); 386253680Sdes } 387253680Sdes return (1); 388253680Sdes} 389253680Sdes 390253680Sdes/* 391253680Sdes * Check if host name consists only of numbers. This might indicate an IP 392253680Sdes * address, which is not a good idea for CN wildcard comparison. 393253680Sdes */ 394253680Sdesstatic int 395253680Sdesfetch_ssl_hname_is_only_numbers(const char *hostname, size_t len) 396253680Sdes{ 397253680Sdes size_t i; 398253680Sdes 399253680Sdes for (i = 0; i < len; ++i) { 400253680Sdes if (!((hostname[i] >= '0' && hostname[i] <= '9') || 401253680Sdes hostname[i] == '.')) 402253680Sdes return (0); 403253680Sdes } 404253680Sdes return (1); 405253680Sdes} 406253680Sdes 407253680Sdes/* 408253680Sdes * Check if the host name h passed matches the pattern passed in m which 409253680Sdes * is usually part of subjectAltName or CN of a certificate presented to 410253680Sdes * the client. This includes wildcard matching. The algorithm is based on 411253680Sdes * RFC6125, sections 6.4.3 and 7.2, which clarifies RFC2818 and RFC3280. 412253680Sdes */ 413253680Sdesstatic int 414253680Sdesfetch_ssl_hname_match(const char *h, size_t hlen, const char *m, 415253680Sdes size_t mlen) 416253680Sdes{ 417253680Sdes int delta, hdotidx, mdot1idx, wcidx; 418253680Sdes const char *hdot, *mdot1, *mdot2; 419253680Sdes const char *wc; /* wildcard */ 420253680Sdes 421253680Sdes if (!(h && *h && m && *m)) 422253680Sdes return (0); 423253680Sdes if ((wc = strnstr(m, "*", mlen)) == NULL) 424253680Sdes return (fetch_ssl_hname_equal(h, hlen, m, mlen)); 425253680Sdes wcidx = wc - m; 426253680Sdes /* hostname should not be just dots and numbers */ 427253680Sdes if (fetch_ssl_hname_is_only_numbers(h, hlen)) 428253680Sdes return (0); 429253680Sdes /* only one wildcard allowed in pattern */ 430253680Sdes if (strnstr(wc + 1, "*", mlen - wcidx - 1) != NULL) 431253680Sdes return (0); 432253680Sdes /* 433253680Sdes * there must be at least two more domain labels and 434253680Sdes * wildcard has to be in the leftmost label (RFC6125) 435253680Sdes */ 436253680Sdes mdot1 = strnstr(m, ".", mlen); 437253680Sdes if (mdot1 == NULL || mdot1 < wc || (mlen - (mdot1 - m)) < 4) 438253680Sdes return (0); 439253680Sdes mdot1idx = mdot1 - m; 440253680Sdes mdot2 = strnstr(mdot1 + 1, ".", mlen - mdot1idx - 1); 441253680Sdes if (mdot2 == NULL || (mlen - (mdot2 - m)) < 2) 442253680Sdes return (0); 443253680Sdes /* hostname must contain a dot and not be the 1st char */ 444253680Sdes hdot = strnstr(h, ".", hlen); 445253680Sdes if (hdot == NULL || hdot == h) 446253680Sdes return (0); 447253680Sdes hdotidx = hdot - h; 448253680Sdes /* 449253680Sdes * host part of hostname must be at least as long as 450253680Sdes * pattern it's supposed to match 451253680Sdes */ 452253680Sdes if (hdotidx < mdot1idx) 453253680Sdes return (0); 454253680Sdes /* 455253680Sdes * don't allow wildcards in non-traditional domain names 456253680Sdes * (IDN, A-label, U-label...) 457253680Sdes */ 458253680Sdes if (!fetch_ssl_is_trad_domain_label(h, hdotidx, 0) || 459253680Sdes !fetch_ssl_is_trad_domain_label(m, mdot1idx, 1)) 460253680Sdes return (0); 461253680Sdes /* match domain part (part after first dot) */ 462253680Sdes if (!fetch_ssl_hname_equal(hdot, hlen - hdotidx, mdot1, 463253680Sdes mlen - mdot1idx)) 464253680Sdes return (0); 465253680Sdes /* match part left of wildcard */ 466253680Sdes if (!fetch_ssl_hname_equal(h, wcidx, m, wcidx)) 467253680Sdes return (0); 468253680Sdes /* match part right of wildcard */ 469253680Sdes delta = mdot1idx - wcidx - 1; 470253680Sdes if (!fetch_ssl_hname_equal(hdot - delta, delta, 471253680Sdes mdot1 - delta, delta)) 472253680Sdes return (0); 473253680Sdes /* all tests succeded, it's a match */ 474253680Sdes return (1); 475253680Sdes} 476253680Sdes 477253680Sdes/* 478253680Sdes * Get numeric host address info - returns NULL if host was not an IP 479253680Sdes * address. The caller is responsible for deallocation using 480253680Sdes * freeaddrinfo(3). 481253680Sdes */ 482253680Sdesstatic struct addrinfo * 483253680Sdesfetch_ssl_get_numeric_addrinfo(const char *hostname, size_t len) 484253680Sdes{ 485253680Sdes struct addrinfo hints, *res; 486253680Sdes char *host; 487253680Sdes 488253680Sdes host = (char *)malloc(len + 1); 489253680Sdes memcpy(host, hostname, len); 490253680Sdes host[len] = '\0'; 491253680Sdes memset(&hints, 0, sizeof(hints)); 492253680Sdes hints.ai_family = PF_UNSPEC; 493253680Sdes hints.ai_socktype = SOCK_STREAM; 494253680Sdes hints.ai_protocol = 0; 495253680Sdes hints.ai_flags = AI_NUMERICHOST; 496253680Sdes /* port is not relevant for this purpose */ 497253680Sdes getaddrinfo(host, "443", &hints, &res); 498253680Sdes free(host); 499253680Sdes return res; 500253680Sdes} 501253680Sdes 502253680Sdes/* 503253680Sdes * Compare ip address in addrinfo with address passes. 504253680Sdes */ 505253680Sdesstatic int 506253680Sdesfetch_ssl_ipaddr_match_bin(const struct addrinfo *lhost, const char *rhost, 507253680Sdes size_t rhostlen) 508253680Sdes{ 509253680Sdes const void *left; 510253680Sdes 511253680Sdes if (lhost->ai_family == AF_INET && rhostlen == 4) { 512253680Sdes left = (void *)&((struct sockaddr_in*)(void *) 513253680Sdes lhost->ai_addr)->sin_addr.s_addr; 514253680Sdes#ifdef INET6 515253680Sdes } else if (lhost->ai_family == AF_INET6 && rhostlen == 16) { 516253680Sdes left = (void *)&((struct sockaddr_in6 *)(void *) 517253680Sdes lhost->ai_addr)->sin6_addr; 518253680Sdes#endif 519253680Sdes } else 520253680Sdes return (0); 521253680Sdes return (!memcmp(left, (const void *)rhost, rhostlen) ? 1 : 0); 522253680Sdes} 523253680Sdes 524253680Sdes/* 525253680Sdes * Compare ip address in addrinfo with host passed. If host is not an IP 526253680Sdes * address, comparison will fail. 527253680Sdes */ 528253680Sdesstatic int 529253680Sdesfetch_ssl_ipaddr_match(const struct addrinfo *laddr, const char *r, 530253680Sdes size_t rlen) 531253680Sdes{ 532253680Sdes struct addrinfo *raddr; 533253680Sdes int ret; 534253680Sdes char *rip; 535253680Sdes 536253680Sdes ret = 0; 537253680Sdes if ((raddr = fetch_ssl_get_numeric_addrinfo(r, rlen)) == NULL) 538253680Sdes return 0; /* not a numeric host */ 539253680Sdes 540253680Sdes if (laddr->ai_family == raddr->ai_family) { 541253680Sdes if (laddr->ai_family == AF_INET) { 542253680Sdes rip = (char *)&((struct sockaddr_in *)(void *) 543253680Sdes raddr->ai_addr)->sin_addr.s_addr; 544253680Sdes ret = fetch_ssl_ipaddr_match_bin(laddr, rip, 4); 545253680Sdes#ifdef INET6 546253680Sdes } else if (laddr->ai_family == AF_INET6) { 547253680Sdes rip = (char *)&((struct sockaddr_in6 *)(void *) 548253680Sdes raddr->ai_addr)->sin6_addr; 549253680Sdes ret = fetch_ssl_ipaddr_match_bin(laddr, rip, 16); 550253680Sdes#endif 551253680Sdes } 552253680Sdes 553253680Sdes } 554253680Sdes freeaddrinfo(raddr); 555253680Sdes return (ret); 556253680Sdes} 557253680Sdes 558253680Sdes/* 559253680Sdes * Verify server certificate by subjectAltName. 560253680Sdes */ 561253680Sdesstatic int 562253680Sdesfetch_ssl_verify_altname(STACK_OF(GENERAL_NAME) *altnames, 563253680Sdes const char *host, struct addrinfo *ip) 564253680Sdes{ 565253680Sdes const GENERAL_NAME *name; 566253680Sdes size_t nslen; 567253680Sdes int i; 568253680Sdes const char *ns; 569253680Sdes 570253680Sdes for (i = 0; i < sk_GENERAL_NAME_num(altnames); ++i) { 571253680Sdes#if OPENSSL_VERSION_NUMBER < 0x10000000L 572253680Sdes /* 573253680Sdes * This is a workaround, since the following line causes 574253680Sdes * alignment issues in clang: 575253680Sdes * name = sk_GENERAL_NAME_value(altnames, i); 576253680Sdes * OpenSSL explicitly warns not to use those macros 577253680Sdes * directly, but there isn't much choice (and there 578253680Sdes * shouldn't be any ill side effects) 579253680Sdes */ 580253680Sdes name = (GENERAL_NAME *)SKM_sk_value(void, altnames, i); 581253680Sdes#else 582253680Sdes name = sk_GENERAL_NAME_value(altnames, i); 583253680Sdes#endif 584253680Sdes ns = (const char *)ASN1_STRING_data(name->d.ia5); 585253680Sdes nslen = (size_t)ASN1_STRING_length(name->d.ia5); 586253680Sdes 587253680Sdes if (name->type == GEN_DNS && ip == NULL && 588253680Sdes fetch_ssl_hname_match(host, strlen(host), ns, nslen)) 589253680Sdes return (1); 590253680Sdes else if (name->type == GEN_IPADD && ip != NULL && 591253680Sdes fetch_ssl_ipaddr_match_bin(ip, ns, nslen)) 592253680Sdes return (1); 593253680Sdes } 594253680Sdes return (0); 595253680Sdes} 596253680Sdes 597253680Sdes/* 598253680Sdes * Verify server certificate by CN. 599253680Sdes */ 600253680Sdesstatic int 601253680Sdesfetch_ssl_verify_cn(X509_NAME *subject, const char *host, 602253680Sdes struct addrinfo *ip) 603253680Sdes{ 604253680Sdes ASN1_STRING *namedata; 605253680Sdes X509_NAME_ENTRY *nameentry; 606253680Sdes int cnlen, lastpos, loc, ret; 607253680Sdes unsigned char *cn; 608253680Sdes 609253680Sdes ret = 0; 610253680Sdes lastpos = -1; 611253680Sdes loc = -1; 612253680Sdes cn = NULL; 613253680Sdes /* get most specific CN (last entry in list) and compare */ 614253680Sdes while ((lastpos = X509_NAME_get_index_by_NID(subject, 615253680Sdes NID_commonName, lastpos)) != -1) 616253680Sdes loc = lastpos; 617253680Sdes 618253680Sdes if (loc > -1) { 619253680Sdes nameentry = X509_NAME_get_entry(subject, loc); 620253680Sdes namedata = X509_NAME_ENTRY_get_data(nameentry); 621253680Sdes cnlen = ASN1_STRING_to_UTF8(&cn, namedata); 622253680Sdes if (ip == NULL && 623253680Sdes fetch_ssl_hname_match(host, strlen(host), cn, cnlen)) 624253680Sdes ret = 1; 625253680Sdes else if (ip != NULL && fetch_ssl_ipaddr_match(ip, cn, cnlen)) 626253680Sdes ret = 1; 627253680Sdes OPENSSL_free(cn); 628253680Sdes } 629253680Sdes return (ret); 630253680Sdes} 631253680Sdes 632253680Sdes/* 633253680Sdes * Verify that server certificate subjectAltName/CN matches 634253680Sdes * hostname. First check, if there are alternative subject names. If yes, 635253680Sdes * those have to match. Only if those don't exist it falls back to 636253680Sdes * checking the subject's CN. 637253680Sdes */ 638253680Sdesstatic int 639253680Sdesfetch_ssl_verify_hname(X509 *cert, const char *host) 640253680Sdes{ 641253680Sdes struct addrinfo *ip; 642253680Sdes STACK_OF(GENERAL_NAME) *altnames; 643253680Sdes X509_NAME *subject; 644253680Sdes int ret; 645253680Sdes 646253680Sdes ret = 0; 647253680Sdes ip = fetch_ssl_get_numeric_addrinfo(host, strlen(host)); 648253680Sdes altnames = X509_get_ext_d2i(cert, NID_subject_alt_name, 649253680Sdes NULL, NULL); 650253680Sdes 651253680Sdes if (altnames != NULL) { 652253680Sdes ret = fetch_ssl_verify_altname(altnames, host, ip); 653253680Sdes } else { 654253680Sdes subject = X509_get_subject_name(cert); 655253680Sdes if (subject != NULL) 656253680Sdes ret = fetch_ssl_verify_cn(subject, host, ip); 657253680Sdes } 658253680Sdes 659253680Sdes if (ip != NULL) 660253680Sdes freeaddrinfo(ip); 661253680Sdes if (altnames != NULL) 662253680Sdes GENERAL_NAMES_free(altnames); 663253680Sdes return (ret); 664253680Sdes} 665253680Sdes 666253680Sdes/* 667253680Sdes * Configure transport security layer based on environment. 668253680Sdes */ 669253680Sdesstatic void 670253680Sdesfetch_ssl_setup_transport_layer(SSL_CTX *ctx, int verbose) 671253680Sdes{ 672253680Sdes long ssl_ctx_options; 673253680Sdes 674253680Sdes ssl_ctx_options = SSL_OP_ALL | SSL_OP_NO_TICKET; 675253680Sdes if (getenv("SSL_ALLOW_SSL2") == NULL) 676253680Sdes ssl_ctx_options |= SSL_OP_NO_SSLv2; 677253680Sdes if (getenv("SSL_NO_SSL3") != NULL) 678253680Sdes ssl_ctx_options |= SSL_OP_NO_SSLv3; 679253680Sdes if (getenv("SSL_NO_TLS1") != NULL) 680253680Sdes ssl_ctx_options |= SSL_OP_NO_TLSv1; 681253680Sdes if (verbose) 682253680Sdes fetch_info("SSL options: %x", ssl_ctx_options); 683253680Sdes SSL_CTX_set_options(ctx, ssl_ctx_options); 684253680Sdes} 685253680Sdes 686253680Sdes 687253680Sdes/* 688253680Sdes * Configure peer verification based on environment. 689253680Sdes */ 690253680Sdesstatic int 691253680Sdesfetch_ssl_setup_peer_verification(SSL_CTX *ctx, int verbose) 692253680Sdes{ 693253680Sdes X509_LOOKUP *crl_lookup; 694253680Sdes X509_STORE *crl_store; 695253680Sdes const char *ca_cert_file, *ca_cert_path, *crl_file; 696253680Sdes 697253680Sdes if (getenv("SSL_NO_VERIFY_PEER") == NULL) { 698253680Sdes ca_cert_file = getenv("SSL_CA_CERT_FILE") != NULL ? 699253680Sdes getenv("SSL_CA_CERT_FILE") : "/etc/ssl/cert.pem"; 700253680Sdes ca_cert_path = getenv("SSL_CA_CERT_PATH"); 701253680Sdes if (verbose) { 702253680Sdes fetch_info("Peer verification enabled"); 703253680Sdes if (ca_cert_file != NULL) 704253680Sdes fetch_info("Using CA cert file: %s", 705253680Sdes ca_cert_file); 706253680Sdes if (ca_cert_path != NULL) 707253680Sdes fetch_info("Using CA cert path: %s", 708253680Sdes ca_cert_path); 709253680Sdes } 710253680Sdes SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, 711253680Sdes fetch_ssl_cb_verify_crt); 712253680Sdes SSL_CTX_load_verify_locations(ctx, ca_cert_file, 713253680Sdes ca_cert_path); 714253680Sdes if ((crl_file = getenv("SSL_CRL_FILE")) != NULL) { 715253680Sdes if (verbose) 716253680Sdes fetch_info("Using CRL file: %s", crl_file); 717253680Sdes crl_store = SSL_CTX_get_cert_store(ctx); 718253680Sdes crl_lookup = X509_STORE_add_lookup(crl_store, 719253680Sdes X509_LOOKUP_file()); 720253680Sdes if (crl_lookup == NULL || 721253680Sdes !X509_load_crl_file(crl_lookup, crl_file, 722253680Sdes X509_FILETYPE_PEM)) { 723253680Sdes fprintf(stderr, 724253680Sdes "Could not load CRL file %s\n", 725253680Sdes crl_file); 726253680Sdes return (0); 727253680Sdes } 728253680Sdes X509_STORE_set_flags(crl_store, 729253680Sdes X509_V_FLAG_CRL_CHECK | 730253680Sdes X509_V_FLAG_CRL_CHECK_ALL); 731253680Sdes } 732253680Sdes } 733253680Sdes return (1); 734253680Sdes} 735253680Sdes 736253680Sdes/* 737253680Sdes * Configure client certificate based on environment. 738253680Sdes */ 739253680Sdesstatic int 740253680Sdesfetch_ssl_setup_client_certificate(SSL_CTX *ctx, int verbose) 741253680Sdes{ 742253680Sdes const char *client_cert_file, *client_key_file; 743253680Sdes 744253680Sdes if ((client_cert_file = getenv("SSL_CLIENT_CERT_FILE")) != NULL) { 745253680Sdes client_key_file = getenv("SSL_CLIENT_KEY_FILE") != NULL ? 746253680Sdes getenv("SSL_CLIENT_KEY_FILE") : client_cert_file; 747253680Sdes if (verbose) { 748253680Sdes fetch_info("Using client cert file: %s", 749253680Sdes client_cert_file); 750253680Sdes fetch_info("Using client key file: %s", 751253680Sdes client_key_file); 752253680Sdes } 753253680Sdes if (SSL_CTX_use_certificate_chain_file(ctx, 754253680Sdes client_cert_file) != 1) { 755253680Sdes fprintf(stderr, 756253680Sdes "Could not load client certificate %s\n", 757253680Sdes client_cert_file); 758253680Sdes return (0); 759253680Sdes } 760253680Sdes if (SSL_CTX_use_PrivateKey_file(ctx, client_key_file, 761253680Sdes SSL_FILETYPE_PEM) != 1) { 762253680Sdes fprintf(stderr, 763253680Sdes "Could not load client key %s\n", 764253680Sdes client_key_file); 765253680Sdes return (0); 766253680Sdes } 767253680Sdes } 768253680Sdes return (1); 769253680Sdes} 770253680Sdes 771253680Sdes/* 772253680Sdes * Callback for SSL certificate verification, this is called on server 773253680Sdes * cert verification. It takes no decision, but informs the user in case 774253680Sdes * verification failed. 775253680Sdes */ 776253680Sdesint 777253680Sdesfetch_ssl_cb_verify_crt(int verified, X509_STORE_CTX *ctx) 778253680Sdes{ 779253680Sdes X509 *crt; 780253680Sdes X509_NAME *name; 781253680Sdes char *str; 782253680Sdes 783253680Sdes str = NULL; 784253680Sdes if (!verified) { 785253680Sdes if ((crt = X509_STORE_CTX_get_current_cert(ctx)) != NULL && 786253680Sdes (name = X509_get_subject_name(crt)) != NULL) 787253680Sdes str = X509_NAME_oneline(name, 0, 0); 788253680Sdes fprintf(stderr, "Certificate verification failed for %s\n", 789253680Sdes str != NULL ? str : "no relevant certificate"); 790253680Sdes OPENSSL_free(str); 791253680Sdes } 792253680Sdes return (verified); 793253680Sdes} 794253680Sdes 795253680Sdes#endif 796253680Sdes 797253680Sdes/* 79897868Sdes * Enable SSL on a connection. 79997868Sdes */ 80097868Sdesint 801253680Sdesfetch_ssl(conn_t *conn, const struct url *URL, int verbose) 80297868Sdes{ 803214256Semaste#ifdef WITH_SSL 804210568Sdes int ret, ssl_err; 805253680Sdes X509_NAME *name; 806253680Sdes char *str; 80797868Sdes 80897868Sdes /* Init the SSL library and context */ 80997868Sdes if (!SSL_library_init()){ 81097868Sdes fprintf(stderr, "SSL library init failed\n"); 81197868Sdes return (-1); 81297868Sdes } 81397868Sdes 81497868Sdes SSL_load_error_strings(); 81597868Sdes 81697868Sdes conn->ssl_meth = SSLv23_client_method(); 81797868Sdes conn->ssl_ctx = SSL_CTX_new(conn->ssl_meth); 818108579Sdes SSL_CTX_set_mode(conn->ssl_ctx, SSL_MODE_AUTO_RETRY); 81997868Sdes 820253680Sdes fetch_ssl_setup_transport_layer(conn->ssl_ctx, verbose); 821253680Sdes if (!fetch_ssl_setup_peer_verification(conn->ssl_ctx, verbose)) 822253680Sdes return (-1); 823253680Sdes if (!fetch_ssl_setup_client_certificate(conn->ssl_ctx, verbose)) 824253680Sdes return (-1); 825253680Sdes 82697868Sdes conn->ssl = SSL_new(conn->ssl_ctx); 827253680Sdes if (conn->ssl == NULL) { 82897868Sdes fprintf(stderr, "SSL context creation failed\n"); 82997868Sdes return (-1); 83097868Sdes } 83197868Sdes SSL_set_fd(conn->ssl, conn->sd); 832210568Sdes while ((ret = SSL_connect(conn->ssl)) == -1) { 833210568Sdes ssl_err = SSL_get_error(conn->ssl, ret); 834210568Sdes if (ssl_err != SSL_ERROR_WANT_READ && 835210568Sdes ssl_err != SSL_ERROR_WANT_WRITE) { 836210568Sdes ERR_print_errors_fp(stderr); 837210568Sdes return (-1); 838210568Sdes } 83997868Sdes } 840253680Sdes conn->ssl_cert = SSL_get_peer_certificate(conn->ssl); 84197868Sdes 842253680Sdes if (conn->ssl_cert == NULL) { 843253680Sdes fprintf(stderr, "No server SSL certificate\n"); 844253680Sdes return (-1); 845253680Sdes } 846253680Sdes 847253680Sdes if (getenv("SSL_NO_VERIFY_HOSTNAME") == NULL) { 848253680Sdes if (verbose) 849253680Sdes fetch_info("Verify hostname"); 850253680Sdes if (!fetch_ssl_verify_hname(conn->ssl_cert, URL->host)) { 851253680Sdes fprintf(stderr, 852253680Sdes "SSL certificate subject doesn't match host %s\n", 853253680Sdes URL->host); 854253680Sdes return (-1); 855253680Sdes } 856253680Sdes } 857253680Sdes 85897868Sdes if (verbose) { 859253680Sdes fetch_info("SSL connection established using %s", 86097868Sdes SSL_get_cipher(conn->ssl)); 86197868Sdes name = X509_get_subject_name(conn->ssl_cert); 86297868Sdes str = X509_NAME_oneline(name, 0, 0); 863253680Sdes fetch_info("Certificate subject: %s", str); 864253680Sdes OPENSSL_free(str); 86597868Sdes name = X509_get_issuer_name(conn->ssl_cert); 86697868Sdes str = X509_NAME_oneline(name, 0, 0); 867253680Sdes fetch_info("Certificate issuer: %s", str); 868253680Sdes OPENSSL_free(str); 86997868Sdes } 87097868Sdes 87197868Sdes return (0); 87297891Sdes#else 87397891Sdes (void)conn; 87497891Sdes (void)verbose; 87597891Sdes fprintf(stderr, "SSL support disabled\n"); 87697891Sdes return (-1); 87797891Sdes#endif 87897868Sdes} 87997868Sdes 880210568Sdes#define FETCH_READ_WAIT -2 881210568Sdes#define FETCH_READ_ERROR -1 882210568Sdes#define FETCH_READ_DONE 0 88398117Sdes 884210568Sdes#ifdef WITH_SSL 885210568Sdesstatic ssize_t 886210568Sdesfetch_ssl_read(SSL *ssl, char *buf, size_t len) 887210568Sdes{ 888210568Sdes ssize_t rlen; 889210568Sdes int ssl_err; 890210568Sdes 891210568Sdes rlen = SSL_read(ssl, buf, len); 892210568Sdes if (rlen < 0) { 893210568Sdes ssl_err = SSL_get_error(ssl, rlen); 894210568Sdes if (ssl_err == SSL_ERROR_WANT_READ || 895210568Sdes ssl_err == SSL_ERROR_WANT_WRITE) { 896210568Sdes return (FETCH_READ_WAIT); 897210568Sdes } else { 898210568Sdes ERR_print_errors_fp(stderr); 899210568Sdes return (FETCH_READ_ERROR); 900210568Sdes } 901210568Sdes } 902210568Sdes return (rlen); 903210568Sdes} 904210568Sdes#endif 905210568Sdes 906230307Sdes/* 907230307Sdes * Cache some data that was read from a socket but cannot be immediately 908230307Sdes * returned because of an interrupted system call. 909230307Sdes */ 910230307Sdesstatic int 911230307Sdesfetch_cache_data(conn_t *conn, char *src, size_t nbytes) 912230307Sdes{ 913230307Sdes char *tmp; 914230307Sdes 915230307Sdes if (conn->cache.size < nbytes) { 916230307Sdes tmp = realloc(conn->cache.buf, nbytes); 917230307Sdes if (tmp == NULL) { 918230307Sdes fetch_syserr(); 919230307Sdes return (-1); 920230307Sdes } 921230307Sdes conn->cache.buf = tmp; 922230307Sdes conn->cache.size = nbytes; 923230307Sdes } 924230307Sdes 925230307Sdes memcpy(conn->cache.buf, src, nbytes); 926230307Sdes conn->cache.len = nbytes; 927230307Sdes conn->cache.pos = 0; 928230307Sdes 929230307Sdes return (0); 930230307Sdes} 931230307Sdes 932230307Sdes 933210568Sdesstatic ssize_t 934210568Sdesfetch_socket_read(int sd, char *buf, size_t len) 935210568Sdes{ 936210568Sdes ssize_t rlen; 937210568Sdes 938210568Sdes rlen = read(sd, buf, len); 939210568Sdes if (rlen < 0) { 940210568Sdes if (errno == EAGAIN || (errno == EINTR && fetchRestartCalls)) 941210568Sdes return (FETCH_READ_WAIT); 942210568Sdes else 943210568Sdes return (FETCH_READ_ERROR); 944210568Sdes } 945210568Sdes return (rlen); 946210568Sdes} 947210568Sdes 94897868Sdes/* 94997866Sdes * Read a character from a connection w/ timeout 95055557Sdes */ 95197866Sdesssize_t 952174588Sdesfetch_read(conn_t *conn, char *buf, size_t len) 95355557Sdes{ 954177447Sdes struct timeval now, timeout, delta; 95590267Sdes fd_set readfds; 95697866Sdes ssize_t rlen, total; 957230307Sdes char *start; 95890267Sdes 959234837Sdes if (fetchTimeout > 0) { 96090267Sdes gettimeofday(&timeout, NULL); 96190267Sdes timeout.tv_sec += fetchTimeout; 96255557Sdes } 96390267Sdes 96497866Sdes total = 0; 965230307Sdes start = buf; 966230307Sdes 967230307Sdes if (conn->cache.len > 0) { 968230307Sdes /* 969230307Sdes * The last invocation of fetch_read was interrupted by a 970230307Sdes * signal after some data had been read from the socket. Copy 971230307Sdes * the cached data into the supplied buffer before trying to 972230307Sdes * read from the socket again. 973230307Sdes */ 974230307Sdes total = (conn->cache.len < len) ? conn->cache.len : len; 975230307Sdes memcpy(buf, conn->cache.buf, total); 976230307Sdes 977230307Sdes conn->cache.len -= total; 978230307Sdes conn->cache.pos += total; 979230307Sdes len -= total; 980230478Sdes buf += total; 981230307Sdes } 982230307Sdes 98397866Sdes while (len > 0) { 984210568Sdes /* 985210568Sdes * The socket is non-blocking. Instead of the canonical 986210568Sdes * select() -> read(), we do the following: 987210568Sdes * 988210568Sdes * 1) call read() or SSL_read(). 989210568Sdes * 2) if an error occurred, return -1. 990210568Sdes * 3) if we received data but we still expect more, 991210568Sdes * update our counters and loop. 992210568Sdes * 4) if read() or SSL_read() signaled EOF, return. 993210568Sdes * 5) if we did not receive any data but we're not at EOF, 994210568Sdes * call select(). 995210568Sdes * 996210568Sdes * In the SSL case, this is necessary because if we 997210568Sdes * receive a close notification, we have to call 998210568Sdes * SSL_read() one additional time after we've read 999210568Sdes * everything we received. 1000210568Sdes * 1001210568Sdes * In the non-SSL case, it may improve performance (very 1002210568Sdes * slightly) when reading small amounts of data. 1003210568Sdes */ 1004210568Sdes#ifdef WITH_SSL 1005210568Sdes if (conn->ssl != NULL) 1006210568Sdes rlen = fetch_ssl_read(conn->ssl, buf, len); 1007210568Sdes else 1008210568Sdes#endif 1009210568Sdes rlen = fetch_socket_read(conn->sd, buf, len); 1010210568Sdes if (rlen == 0) { 1011210568Sdes break; 1012210568Sdes } else if (rlen > 0) { 1013210568Sdes len -= rlen; 1014210568Sdes buf += rlen; 1015210568Sdes total += rlen; 1016210568Sdes continue; 1017210568Sdes } else if (rlen == FETCH_READ_ERROR) { 1018230307Sdes if (errno == EINTR) 1019230307Sdes fetch_cache_data(conn, start, total); 1020210568Sdes return (-1); 1021210568Sdes } 1022210568Sdes // assert(rlen == FETCH_READ_WAIT); 1023234837Sdes FD_ZERO(&readfds); 1024234837Sdes while (!FD_ISSET(conn->sd, &readfds)) { 102597856Sdes FD_SET(conn->sd, &readfds); 1026234837Sdes if (fetchTimeout > 0) { 1027234837Sdes gettimeofday(&now, NULL); 1028234837Sdes if (!timercmp(&timeout, &now, >)) { 1029234837Sdes errno = ETIMEDOUT; 1030234837Sdes fetch_syserr(); 1031234837Sdes return (-1); 1032234837Sdes } 1033234837Sdes timersub(&timeout, &now, &delta); 103490267Sdes } 103597866Sdes errno = 0; 1036234837Sdes if (select(conn->sd + 1, &readfds, NULL, NULL, 1037234837Sdes fetchTimeout > 0 ? &delta : NULL) < 0) { 1038230307Sdes if (errno == EINTR) { 1039230307Sdes if (fetchRestartCalls) 1040230307Sdes continue; 1041230307Sdes /* Save anything that was read. */ 1042230307Sdes fetch_cache_data(conn, start, total); 1043230307Sdes } 1044174588Sdes fetch_syserr(); 104590267Sdes return (-1); 104690267Sdes } 104790267Sdes } 104897866Sdes } 104997866Sdes return (total); 105097866Sdes} 105197866Sdes 105298117Sdes 105397866Sdes/* 105497866Sdes * Read a line of text from a connection w/ timeout 105597866Sdes */ 105697866Sdes#define MIN_BUF_SIZE 1024 105797866Sdes 105897866Sdesint 1059174588Sdesfetch_getln(conn_t *conn) 106097866Sdes{ 106197866Sdes char *tmp; 106297866Sdes size_t tmpsize; 1063106186Sdes ssize_t len; 106497866Sdes char c; 106597866Sdes 106697866Sdes if (conn->buf == NULL) { 106797866Sdes if ((conn->buf = malloc(MIN_BUF_SIZE)) == NULL) { 106897866Sdes errno = ENOMEM; 106997866Sdes return (-1); 107097866Sdes } 107197866Sdes conn->bufsize = MIN_BUF_SIZE; 107297866Sdes } 107397866Sdes 107497866Sdes conn->buf[0] = '\0'; 107597866Sdes conn->buflen = 0; 107697866Sdes 107797866Sdes do { 1078174588Sdes len = fetch_read(conn, &c, 1); 1079106186Sdes if (len == -1) 108097866Sdes return (-1); 1081106186Sdes if (len == 0) 1082106137Sobrien break; 108397856Sdes conn->buf[conn->buflen++] = c; 108497856Sdes if (conn->buflen == conn->bufsize) { 108597856Sdes tmp = conn->buf; 108697856Sdes tmpsize = conn->bufsize * 2 + 1; 108797856Sdes if ((tmp = realloc(tmp, tmpsize)) == NULL) { 108890267Sdes errno = ENOMEM; 108990267Sdes return (-1); 109090267Sdes } 109197856Sdes conn->buf = tmp; 109297856Sdes conn->bufsize = tmpsize; 109390267Sdes } 109490267Sdes } while (c != '\n'); 109590267Sdes 109697856Sdes conn->buf[conn->buflen] = '\0'; 109797856Sdes DEBUG(fprintf(stderr, "<<< %s", conn->buf)); 109890267Sdes return (0); 109955557Sdes} 110055557Sdes 110155557Sdes 110262981Sdes/* 110397866Sdes * Write to a connection w/ timeout 110462981Sdes */ 110597866Sdesssize_t 1106174588Sdesfetch_write(conn_t *conn, const char *buf, size_t len) 110797866Sdes{ 1108106175Simp struct iovec iov; 1109106175Simp 1110106175Simp iov.iov_base = __DECONST(char *, buf); 1111106175Simp iov.iov_len = len; 1112174588Sdes return fetch_writev(conn, &iov, 1); 1113106175Simp} 1114106175Simp 1115106175Simp/* 1116106175Simp * Write a vector to a connection w/ timeout 1117106175Simp * Note: can modify the iovec. 1118106175Simp */ 1119106175Simpssize_t 1120174588Sdesfetch_writev(conn_t *conn, struct iovec *iov, int iovcnt) 1121106175Simp{ 1122177447Sdes struct timeval now, timeout, delta; 112397866Sdes fd_set writefds; 112497866Sdes ssize_t wlen, total; 112597866Sdes int r; 112697866Sdes 112797866Sdes if (fetchTimeout) { 112897866Sdes FD_ZERO(&writefds); 112997866Sdes gettimeofday(&timeout, NULL); 113097866Sdes timeout.tv_sec += fetchTimeout; 113197866Sdes } 113297866Sdes 1133106175Simp total = 0; 1134106175Simp while (iovcnt > 0) { 113597866Sdes while (fetchTimeout && !FD_ISSET(conn->sd, &writefds)) { 113697866Sdes FD_SET(conn->sd, &writefds); 113797866Sdes gettimeofday(&now, NULL); 1138177447Sdes delta.tv_sec = timeout.tv_sec - now.tv_sec; 1139177447Sdes delta.tv_usec = timeout.tv_usec - now.tv_usec; 1140177447Sdes if (delta.tv_usec < 0) { 1141177447Sdes delta.tv_usec += 1000000; 1142177447Sdes delta.tv_sec--; 114397866Sdes } 1144177447Sdes if (delta.tv_sec < 0) { 114597866Sdes errno = ETIMEDOUT; 1146174588Sdes fetch_syserr(); 114797866Sdes return (-1); 114897866Sdes } 114997866Sdes errno = 0; 1150177447Sdes r = select(conn->sd + 1, NULL, &writefds, NULL, &delta); 115197866Sdes if (r == -1) { 115297866Sdes if (errno == EINTR && fetchRestartCalls) 115397866Sdes continue; 115497866Sdes return (-1); 115597866Sdes } 115697866Sdes } 115797866Sdes errno = 0; 115897891Sdes#ifdef WITH_SSL 115997866Sdes if (conn->ssl != NULL) 1160106175Simp wlen = SSL_write(conn->ssl, 1161106175Simp iov->iov_base, iov->iov_len); 116297866Sdes else 116397891Sdes#endif 1164106175Simp wlen = writev(conn->sd, iov, iovcnt); 1165106175Simp if (wlen == 0) { 116697866Sdes /* we consider a short write a failure */ 1167210568Sdes /* XXX perhaps we shouldn't in the SSL case */ 1168106175Simp errno = EPIPE; 1169174588Sdes fetch_syserr(); 117097866Sdes return (-1); 1171106175Simp } 117297866Sdes if (wlen < 0) { 117397866Sdes if (errno == EINTR && fetchRestartCalls) 117497866Sdes continue; 117597866Sdes return (-1); 117697866Sdes } 117797866Sdes total += wlen; 1178106175Simp while (iovcnt > 0 && wlen >= (ssize_t)iov->iov_len) { 1179106175Simp wlen -= iov->iov_len; 1180106175Simp iov++; 1181106175Simp iovcnt--; 1182106175Simp } 1183106175Simp if (iovcnt > 0) { 1184106175Simp iov->iov_len -= wlen; 1185106175Simp iov->iov_base = __DECONST(char *, iov->iov_base) + wlen; 1186106175Simp } 118797866Sdes } 118897866Sdes return (total); 118997866Sdes} 119097866Sdes 119198117Sdes 119297866Sdes/* 119397866Sdes * Write a line of text to a connection w/ timeout 119497866Sdes */ 119562981Sdesint 1196174588Sdesfetch_putln(conn_t *conn, const char *str, size_t len) 119762981Sdes{ 1198106175Simp struct iovec iov[2]; 1199106205Sdes int ret; 120098748Sdes 120198748Sdes DEBUG(fprintf(stderr, ">>> %s\n", str)); 1202106175Simp iov[0].iov_base = __DECONST(char *, str); 1203106175Simp iov[0].iov_len = len; 1204106175Simp iov[1].iov_base = __DECONST(char *, ENDL); 1205109967Sdes iov[1].iov_len = sizeof(ENDL); 1206106205Sdes if (len == 0) 1207174588Sdes ret = fetch_writev(conn, &iov[1], 1); 1208106205Sdes else 1209174588Sdes ret = fetch_writev(conn, iov, 2); 1210106205Sdes if (ret == -1) 121190267Sdes return (-1); 121290267Sdes return (0); 121362981Sdes} 121462981Sdes 121562981Sdes 121697856Sdes/* 121797856Sdes * Close connection 121897856Sdes */ 121997856Sdesint 1220174588Sdesfetch_close(conn_t *conn) 122197856Sdes{ 122297856Sdes int ret; 122397856Sdes 122498117Sdes if (--conn->ref > 0) 122598117Sdes return (0); 1226253680Sdes#ifdef WITH_SSL 1227253680Sdes if (conn->ssl) { 1228253680Sdes SSL_shutdown(conn->ssl); 1229253680Sdes SSL_set_connect_state(conn->ssl); 1230253680Sdes SSL_free(conn->ssl); 1231253680Sdes conn->ssl = NULL; 1232253680Sdes } 1233253680Sdes if (conn->ssl_ctx) { 1234253680Sdes SSL_CTX_free(conn->ssl_ctx); 1235253680Sdes conn->ssl_ctx = NULL; 1236253680Sdes } 1237253680Sdes if (conn->ssl_cert) { 1238253680Sdes X509_free(conn->ssl_cert); 1239253680Sdes conn->ssl_cert = NULL; 1240253680Sdes } 1241253680Sdes#endif 124297856Sdes ret = close(conn->sd); 1243230307Sdes free(conn->cache.buf); 1244141970Sdes free(conn->buf); 124597856Sdes free(conn); 124697856Sdes return (ret); 124797856Sdes} 124897856Sdes 124997856Sdes 125041989Sdes/*** Directory-related utility functions *************************************/ 125141989Sdes 125241989Sdesint 1253174588Sdesfetch_add_entry(struct url_ent **p, int *size, int *len, 125490267Sdes const char *name, struct url_stat *us) 125541989Sdes{ 125690267Sdes struct url_ent *tmp; 125741989Sdes 125890267Sdes if (*p == NULL) { 125990268Sdes *size = 0; 126090267Sdes *len = 0; 126141989Sdes } 126241989Sdes 126390267Sdes if (*len >= *size - 1) { 1264109967Sdes tmp = realloc(*p, (*size * 2 + 1) * sizeof(**p)); 126590267Sdes if (tmp == NULL) { 126690267Sdes errno = ENOMEM; 1267174588Sdes fetch_syserr(); 126890267Sdes return (-1); 126990267Sdes } 127090268Sdes *size = (*size * 2 + 1); 127190267Sdes *p = tmp; 127290267Sdes } 127341989Sdes 127490267Sdes tmp = *p + *len; 127590267Sdes snprintf(tmp->name, PATH_MAX, "%s", name); 1276176105Sdes memcpy(&tmp->stat, us, sizeof(*us)); 127741989Sdes 127890267Sdes (*len)++; 127990267Sdes (++tmp)->name[0] = 0; 128090267Sdes 128190267Sdes return (0); 128241989Sdes} 1283109695Sdes 1284109695Sdes 1285109695Sdes/*** Authentication-related utility functions ********************************/ 1286109695Sdes 1287109695Sdesstatic const char * 1288174588Sdesfetch_read_word(FILE *f) 1289109695Sdes{ 1290109695Sdes static char word[1024]; 1291109695Sdes 1292178234Scperciva if (fscanf(f, " %1023s ", word) != 1) 1293109695Sdes return (NULL); 1294109695Sdes return (word); 1295109695Sdes} 1296109695Sdes 1297109695Sdes/* 1298109695Sdes * Get authentication data for a URL from .netrc 1299109695Sdes */ 1300109695Sdesint 1301174588Sdesfetch_netrc_auth(struct url *url) 1302109695Sdes{ 1303109695Sdes char fn[PATH_MAX]; 1304109695Sdes const char *word; 1305109695Sdes char *p; 1306109695Sdes FILE *f; 1307109695Sdes 1308109695Sdes if ((p = getenv("NETRC")) != NULL) { 1309109967Sdes if (snprintf(fn, sizeof(fn), "%s", p) >= (int)sizeof(fn)) { 1310174588Sdes fetch_info("$NETRC specifies a file name " 1311109695Sdes "longer than PATH_MAX"); 1312109695Sdes return (-1); 1313109695Sdes } 1314109695Sdes } else { 1315109695Sdes if ((p = getenv("HOME")) != NULL) { 1316109695Sdes struct passwd *pwd; 1317109695Sdes 1318109695Sdes if ((pwd = getpwuid(getuid())) == NULL || 1319109695Sdes (p = pwd->pw_dir) == NULL) 1320109695Sdes return (-1); 1321109695Sdes } 1322109967Sdes if (snprintf(fn, sizeof(fn), "%s/.netrc", p) >= (int)sizeof(fn)) 1323109695Sdes return (-1); 1324109695Sdes } 1325109695Sdes 1326109695Sdes if ((f = fopen(fn, "r")) == NULL) 1327109695Sdes return (-1); 1328174588Sdes while ((word = fetch_read_word(f)) != NULL) { 1329109695Sdes if (strcmp(word, "default") == 0) { 1330174588Sdes DEBUG(fetch_info("Using default .netrc settings")); 1331109695Sdes break; 1332109695Sdes } 1333109695Sdes if (strcmp(word, "machine") == 0 && 1334174588Sdes (word = fetch_read_word(f)) != NULL && 1335109695Sdes strcasecmp(word, url->host) == 0) { 1336174588Sdes DEBUG(fetch_info("Using .netrc settings for %s", word)); 1337109695Sdes break; 1338109695Sdes } 1339109695Sdes } 1340109695Sdes if (word == NULL) 1341109695Sdes goto ferr; 1342174588Sdes while ((word = fetch_read_word(f)) != NULL) { 1343109695Sdes if (strcmp(word, "login") == 0) { 1344174588Sdes if ((word = fetch_read_word(f)) == NULL) 1345109695Sdes goto ferr; 1346109967Sdes if (snprintf(url->user, sizeof(url->user), 1347109960Sjwd "%s", word) > (int)sizeof(url->user)) { 1348174588Sdes fetch_info("login name in .netrc is too long"); 1349109695Sdes url->user[0] = '\0'; 1350109695Sdes } 1351109695Sdes } else if (strcmp(word, "password") == 0) { 1352174588Sdes if ((word = fetch_read_word(f)) == NULL) 1353109695Sdes goto ferr; 1354109967Sdes if (snprintf(url->pwd, sizeof(url->pwd), 1355109960Sjwd "%s", word) > (int)sizeof(url->pwd)) { 1356174588Sdes fetch_info("password in .netrc is too long"); 1357109695Sdes url->pwd[0] = '\0'; 1358109695Sdes } 1359109695Sdes } else if (strcmp(word, "account") == 0) { 1360174588Sdes if ((word = fetch_read_word(f)) == NULL) 1361109695Sdes goto ferr; 1362109695Sdes /* XXX not supported! */ 1363109695Sdes } else { 1364109695Sdes break; 1365109695Sdes } 1366109695Sdes } 1367109695Sdes fclose(f); 1368109695Sdes return (0); 1369109695Sdes ferr: 1370109695Sdes fclose(f); 1371109695Sdes return (-1); 1372109695Sdes} 1373174752Sdes 1374174752Sdes/* 1375174752Sdes * The no_proxy environment variable specifies a set of domains for 1376174752Sdes * which the proxy should not be consulted; the contents is a comma-, 1377174752Sdes * or space-separated list of domain names. A single asterisk will 1378174752Sdes * override all proxy variables and no transactions will be proxied 1379174752Sdes * (for compatability with lynx and curl, see the discussion at 1380174752Sdes * <http://curl.haxx.se/mail/archive_pre_oct_99/0009.html>). 1381174752Sdes */ 1382174752Sdesint 1383174752Sdesfetch_no_proxy_match(const char *host) 1384174752Sdes{ 1385174752Sdes const char *no_proxy, *p, *q; 1386174752Sdes size_t h_len, d_len; 1387174752Sdes 1388174752Sdes if ((no_proxy = getenv("NO_PROXY")) == NULL && 1389174752Sdes (no_proxy = getenv("no_proxy")) == NULL) 1390174752Sdes return (0); 1391174752Sdes 1392174752Sdes /* asterisk matches any hostname */ 1393174752Sdes if (strcmp(no_proxy, "*") == 0) 1394174752Sdes return (1); 1395174752Sdes 1396174752Sdes h_len = strlen(host); 1397174752Sdes p = no_proxy; 1398174752Sdes do { 1399174752Sdes /* position p at the beginning of a domain suffix */ 1400174761Sdes while (*p == ',' || isspace((unsigned char)*p)) 1401174752Sdes p++; 1402174752Sdes 1403174752Sdes /* position q at the first separator character */ 1404174752Sdes for (q = p; *q; ++q) 1405174761Sdes if (*q == ',' || isspace((unsigned char)*q)) 1406174752Sdes break; 1407174752Sdes 1408174752Sdes d_len = q - p; 1409198339Sfabient if (d_len > 0 && h_len >= d_len && 1410174752Sdes strncasecmp(host + h_len - d_len, 1411174752Sdes p, d_len) == 0) { 1412174752Sdes /* domain name matches */ 1413174752Sdes return (1); 1414174752Sdes } 1415174752Sdes 1416174752Sdes p = q + 1; 1417174752Sdes } while (*q); 1418174752Sdes 1419174752Sdes return (0); 1420174752Sdes} 1421