common.c revision 266291
140939Sdes/*- 2261284Sdes * Copyright (c) 1998-2014 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 266291 2014-05-17 03:39:56Z 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> 44261230Sdes#include <poll.h> 45109695Sdes#include <pwd.h> 4660924Sdes#include <stdarg.h> 4741862Sdes#include <stdlib.h> 4841862Sdes#include <stdio.h> 4940939Sdes#include <string.h> 5040939Sdes#include <unistd.h> 5140939Sdes 52253680Sdes#ifdef WITH_SSL 53253680Sdes#include <openssl/x509v3.h> 54253680Sdes#endif 55253680Sdes 5640939Sdes#include "fetch.h" 5740939Sdes#include "common.h" 5840939Sdes 5940975Sdes 6040939Sdes/*** Local data **************************************************************/ 6140939Sdes 6240939Sdes/* 6340939Sdes * Error messages for resolver errors 6440939Sdes */ 65174588Sdesstatic struct fetcherr netdb_errlist[] = { 66121423Sume#ifdef EAI_NODATA 6790267Sdes { EAI_NODATA, FETCH_RESOLV, "Host not found" }, 68121423Sume#endif 6990267Sdes { EAI_AGAIN, FETCH_TEMP, "Transient resolver failure" }, 7090267Sdes { EAI_FAIL, FETCH_RESOLV, "Non-recoverable resolver failure" }, 7190267Sdes { EAI_NONAME, FETCH_RESOLV, "No address record" }, 7290267Sdes { -1, FETCH_UNKNOWN, "Unknown resolver error" } 7340939Sdes}; 7440939Sdes 7562981Sdes/* End-of-Line */ 7675891Sarchiestatic const char ENDL[2] = "\r\n"; 7740939Sdes 7862981Sdes 7940939Sdes/*** Error-reporting functions ***********************************************/ 8040939Sdes 8140939Sdes/* 8240939Sdes * Map error code to string 8340939Sdes */ 8460924Sdesstatic struct fetcherr * 85174588Sdesfetch_finderr(struct fetcherr *p, int e) 8640939Sdes{ 8790267Sdes while (p->num != -1 && p->num != e) 8890267Sdes p++; 8990267Sdes return (p); 9040939Sdes} 9140939Sdes 9240939Sdes/* 9340939Sdes * Set error code 9440939Sdes */ 9540939Sdesvoid 96174588Sdesfetch_seterr(struct fetcherr *p, int e) 9740939Sdes{ 98174588Sdes p = fetch_finderr(p, e); 9990267Sdes fetchLastErrCode = p->cat; 10090267Sdes snprintf(fetchLastErrString, MAXERRSTRING, "%s", p->string); 10140939Sdes} 10240939Sdes 10340939Sdes/* 10440939Sdes * Set error code according to errno 10540939Sdes */ 10640939Sdesvoid 107174588Sdesfetch_syserr(void) 10840939Sdes{ 10990267Sdes switch (errno) { 11090267Sdes case 0: 11190267Sdes fetchLastErrCode = FETCH_OK; 11290267Sdes break; 11390267Sdes case EPERM: 11490267Sdes case EACCES: 11590267Sdes case EROFS: 11690267Sdes case EAUTH: 11790267Sdes case ENEEDAUTH: 11890267Sdes fetchLastErrCode = FETCH_AUTH; 11990267Sdes break; 12090267Sdes case ENOENT: 12190267Sdes case EISDIR: /* XXX */ 12290267Sdes fetchLastErrCode = FETCH_UNAVAIL; 12390267Sdes break; 12490267Sdes case ENOMEM: 12590267Sdes fetchLastErrCode = FETCH_MEMORY; 12690267Sdes break; 12790267Sdes case EBUSY: 12890267Sdes case EAGAIN: 12990267Sdes fetchLastErrCode = FETCH_TEMP; 13090267Sdes break; 13190267Sdes case EEXIST: 13290267Sdes fetchLastErrCode = FETCH_EXISTS; 13390267Sdes break; 13490267Sdes case ENOSPC: 13590267Sdes fetchLastErrCode = FETCH_FULL; 13690267Sdes break; 13790267Sdes case EADDRINUSE: 13890267Sdes case EADDRNOTAVAIL: 13990267Sdes case ENETDOWN: 14090267Sdes case ENETUNREACH: 14190267Sdes case ENETRESET: 14290267Sdes case EHOSTUNREACH: 14390267Sdes fetchLastErrCode = FETCH_NETWORK; 14490267Sdes break; 14590267Sdes case ECONNABORTED: 14690267Sdes case ECONNRESET: 14790267Sdes fetchLastErrCode = FETCH_ABORT; 14890267Sdes break; 14990267Sdes case ETIMEDOUT: 15090267Sdes fetchLastErrCode = FETCH_TIMEOUT; 15190267Sdes break; 15290267Sdes case ECONNREFUSED: 15390267Sdes case EHOSTDOWN: 15490267Sdes fetchLastErrCode = FETCH_DOWN; 15590267Sdes break; 15690267Sdesdefault: 15790267Sdes fetchLastErrCode = FETCH_UNKNOWN; 15890267Sdes } 15990267Sdes snprintf(fetchLastErrString, MAXERRSTRING, "%s", strerror(errno)); 16040939Sdes} 16140939Sdes 16240939Sdes 16341862Sdes/* 16441862Sdes * Emit status message 16541862Sdes */ 16660924Sdesvoid 167174588Sdesfetch_info(const char *fmt, ...) 16841862Sdes{ 16990267Sdes va_list ap; 17090267Sdes 17190267Sdes va_start(ap, fmt); 17290267Sdes vfprintf(stderr, fmt, ap); 17390267Sdes va_end(ap); 17490267Sdes fputc('\n', stderr); 17541862Sdes} 17641862Sdes 17741862Sdes 17840939Sdes/*** Network-related utility functions ***************************************/ 17940939Sdes 18040939Sdes/* 18168551Sdes * Return the default port for a scheme 18268551Sdes */ 18368551Sdesint 184174588Sdesfetch_default_port(const char *scheme) 18568551Sdes{ 18690267Sdes struct servent *se; 18768551Sdes 18890267Sdes if ((se = getservbyname(scheme, "tcp")) != NULL) 18990267Sdes return (ntohs(se->s_port)); 19090267Sdes if (strcasecmp(scheme, SCHEME_FTP) == 0) 19190267Sdes return (FTP_DEFAULT_PORT); 19290267Sdes if (strcasecmp(scheme, SCHEME_HTTP) == 0) 19390267Sdes return (HTTP_DEFAULT_PORT); 19490267Sdes return (0); 19568551Sdes} 19668551Sdes 19768551Sdes/* 19868551Sdes * Return the default proxy port for a scheme 19968551Sdes */ 20068551Sdesint 201174588Sdesfetch_default_proxy_port(const char *scheme) 20268551Sdes{ 20390267Sdes if (strcasecmp(scheme, SCHEME_FTP) == 0) 20490267Sdes return (FTP_DEFAULT_PROXY_PORT); 20590267Sdes if (strcasecmp(scheme, SCHEME_HTTP) == 0) 20690267Sdes return (HTTP_DEFAULT_PROXY_PORT); 20790267Sdes return (0); 20868551Sdes} 20968551Sdes 21098117Sdes 21168551Sdes/* 21297866Sdes * Create a connection for an existing descriptor. 21397866Sdes */ 21497866Sdesconn_t * 215174588Sdesfetch_reopen(int sd) 21697866Sdes{ 21797866Sdes conn_t *conn; 218236193Sjilles int opt = 1; 21997866Sdes 22097866Sdes /* allocate and fill connection structure */ 221109967Sdes if ((conn = calloc(1, sizeof(*conn))) == NULL) 22297866Sdes return (NULL); 223221830Sdes fcntl(sd, F_SETFD, FD_CLOEXEC); 224236193Sjilles setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof opt); 22597866Sdes conn->sd = sd; 22698117Sdes ++conn->ref; 22797866Sdes return (conn); 22897866Sdes} 22997866Sdes 23097866Sdes 23197866Sdes/* 23298117Sdes * Bump a connection's reference count. 23398117Sdes */ 23498117Sdesconn_t * 235174588Sdesfetch_ref(conn_t *conn) 23698117Sdes{ 23798117Sdes 23898117Sdes ++conn->ref; 23998117Sdes return (conn); 24098117Sdes} 24198117Sdes 24298117Sdes 24398117Sdes/* 244111816Sdes * Bind a socket to a specific local address 245111816Sdes */ 246111816Sdesint 247174588Sdesfetch_bind(int sd, int af, const char *addr) 248111816Sdes{ 249111816Sdes struct addrinfo hints, *res, *res0; 250111816Sdes int err; 251111816Sdes 252111816Sdes memset(&hints, 0, sizeof(hints)); 253111816Sdes hints.ai_family = af; 254111816Sdes hints.ai_socktype = SOCK_STREAM; 255111816Sdes hints.ai_protocol = 0; 256111816Sdes if ((err = getaddrinfo(addr, NULL, &hints, &res0)) != 0) 257111816Sdes return (-1); 258111816Sdes for (res = res0; res; res = res->ai_next) 259111816Sdes if (bind(sd, res->ai_addr, res->ai_addrlen) == 0) 260111816Sdes return (0); 261111816Sdes return (-1); 262111816Sdes} 263111816Sdes 264111816Sdes 265111816Sdes/* 26640939Sdes * Establish a TCP connection to the specified port on the specified host. 26740939Sdes */ 26897856Sdesconn_t * 269174588Sdesfetch_connect(const char *host, int port, int af, int verbose) 27040939Sdes{ 27197856Sdes conn_t *conn; 27290267Sdes char pbuf[10]; 273111816Sdes const char *bindaddr; 27490267Sdes struct addrinfo hints, *res, *res0; 27590267Sdes int sd, err; 27640939Sdes 27790267Sdes DEBUG(fprintf(stderr, "---> %s:%d\n", host, port)); 27841862Sdes 27990267Sdes if (verbose) 280174588Sdes fetch_info("looking up %s", host); 28140939Sdes 28290267Sdes /* look up host name and set up socket address structure */ 28390267Sdes snprintf(pbuf, sizeof(pbuf), "%d", port); 28490267Sdes memset(&hints, 0, sizeof(hints)); 28590267Sdes hints.ai_family = af; 28690267Sdes hints.ai_socktype = SOCK_STREAM; 28790267Sdes hints.ai_protocol = 0; 28890267Sdes if ((err = getaddrinfo(host, pbuf, &hints, &res0)) != 0) { 289174588Sdes netdb_seterr(err); 29097856Sdes return (NULL); 29190267Sdes } 292111816Sdes bindaddr = getenv("FETCH_BIND_ADDRESS"); 29390267Sdes 29490267Sdes if (verbose) 295174588Sdes fetch_info("connecting to %s:%d", host, port); 29690267Sdes 29790267Sdes /* try to connect */ 298111816Sdes for (sd = -1, res = res0; res; sd = -1, res = res->ai_next) { 29990267Sdes if ((sd = socket(res->ai_family, res->ai_socktype, 30062981Sdes res->ai_protocol)) == -1) 30190267Sdes continue; 302111816Sdes if (bindaddr != NULL && *bindaddr != '\0' && 303174588Sdes fetch_bind(sd, res->ai_family, bindaddr) != 0) { 304174588Sdes fetch_info("failed to bind to '%s'", bindaddr); 305111816Sdes close(sd); 306111816Sdes continue; 307111816Sdes } 308210568Sdes if (connect(sd, res->ai_addr, res->ai_addrlen) == 0 && 309210568Sdes fcntl(sd, F_SETFL, O_NONBLOCK) == 0) 31090267Sdes break; 31190267Sdes close(sd); 31290267Sdes } 31390267Sdes freeaddrinfo(res0); 31490267Sdes if (sd == -1) { 315174588Sdes fetch_syserr(); 31697856Sdes return (NULL); 31790267Sdes } 31840939Sdes 319174588Sdes if ((conn = fetch_reopen(sd)) == NULL) { 320174588Sdes fetch_syserr(); 32197856Sdes close(sd); 322103459Sfenner } 32397856Sdes return (conn); 32440939Sdes} 32541989Sdes 326253680Sdes#ifdef WITH_SSL 327253680Sdes/* 328253680Sdes * Convert characters A-Z to lowercase (intentionally avoid any locale 329253680Sdes * specific conversions). 330253680Sdes */ 331253680Sdesstatic char 332253680Sdesfetch_ssl_tolower(char in) 333253680Sdes{ 334253680Sdes if (in >= 'A' && in <= 'Z') 335253680Sdes return (in + 32); 336253680Sdes else 337253680Sdes return (in); 338253680Sdes} 33941989Sdes 34055557Sdes/* 341253680Sdes * isalpha implementation that intentionally avoids any locale specific 342253680Sdes * conversions. 343253680Sdes */ 344253680Sdesstatic int 345253680Sdesfetch_ssl_isalpha(char in) 346253680Sdes{ 347253680Sdes return ((in >= 'A' && in <= 'Z') || (in >= 'a' && in <= 'z')); 348253680Sdes} 349253680Sdes 350253680Sdes/* 351253680Sdes * Check if passed hostnames a and b are equal. 352253680Sdes */ 353253680Sdesstatic int 354253680Sdesfetch_ssl_hname_equal(const char *a, size_t alen, const char *b, 355253680Sdes size_t blen) 356253680Sdes{ 357253680Sdes size_t i; 358253680Sdes 359253680Sdes if (alen != blen) 360253680Sdes return (0); 361253680Sdes for (i = 0; i < alen; ++i) { 362253680Sdes if (fetch_ssl_tolower(a[i]) != fetch_ssl_tolower(b[i])) 363253680Sdes return (0); 364253680Sdes } 365253680Sdes return (1); 366253680Sdes} 367253680Sdes 368253680Sdes/* 369253680Sdes * Check if domain label is traditional, meaning that only A-Z, a-z, 0-9 370253680Sdes * and '-' (hyphen) are allowed. Hyphens have to be surrounded by alpha- 371253680Sdes * numeric characters. Double hyphens (like they're found in IDN a-labels 372253680Sdes * 'xn--') are not allowed. Empty labels are invalid. 373253680Sdes */ 374253680Sdesstatic int 375253680Sdesfetch_ssl_is_trad_domain_label(const char *l, size_t len, int wcok) 376253680Sdes{ 377253680Sdes size_t i; 378253680Sdes 379253680Sdes if (!len || l[0] == '-' || l[len-1] == '-') 380253680Sdes return (0); 381253680Sdes for (i = 0; i < len; ++i) { 382253680Sdes if (!isdigit(l[i]) && 383253680Sdes !fetch_ssl_isalpha(l[i]) && 384253680Sdes !(l[i] == '*' && wcok) && 385253680Sdes !(l[i] == '-' && l[i - 1] != '-')) 386253680Sdes return (0); 387253680Sdes } 388253680Sdes return (1); 389253680Sdes} 390253680Sdes 391253680Sdes/* 392253680Sdes * Check if host name consists only of numbers. This might indicate an IP 393253680Sdes * address, which is not a good idea for CN wildcard comparison. 394253680Sdes */ 395253680Sdesstatic int 396253680Sdesfetch_ssl_hname_is_only_numbers(const char *hostname, size_t len) 397253680Sdes{ 398253680Sdes size_t i; 399253680Sdes 400253680Sdes for (i = 0; i < len; ++i) { 401253680Sdes if (!((hostname[i] >= '0' && hostname[i] <= '9') || 402253680Sdes hostname[i] == '.')) 403253680Sdes return (0); 404253680Sdes } 405253680Sdes return (1); 406253680Sdes} 407253680Sdes 408253680Sdes/* 409253680Sdes * Check if the host name h passed matches the pattern passed in m which 410253680Sdes * is usually part of subjectAltName or CN of a certificate presented to 411253680Sdes * the client. This includes wildcard matching. The algorithm is based on 412253680Sdes * RFC6125, sections 6.4.3 and 7.2, which clarifies RFC2818 and RFC3280. 413253680Sdes */ 414253680Sdesstatic int 415253680Sdesfetch_ssl_hname_match(const char *h, size_t hlen, const char *m, 416253680Sdes size_t mlen) 417253680Sdes{ 418253680Sdes int delta, hdotidx, mdot1idx, wcidx; 419253680Sdes const char *hdot, *mdot1, *mdot2; 420253680Sdes const char *wc; /* wildcard */ 421253680Sdes 422253680Sdes if (!(h && *h && m && *m)) 423253680Sdes return (0); 424253680Sdes if ((wc = strnstr(m, "*", mlen)) == NULL) 425253680Sdes return (fetch_ssl_hname_equal(h, hlen, m, mlen)); 426253680Sdes wcidx = wc - m; 427253680Sdes /* hostname should not be just dots and numbers */ 428253680Sdes if (fetch_ssl_hname_is_only_numbers(h, hlen)) 429253680Sdes return (0); 430253680Sdes /* only one wildcard allowed in pattern */ 431253680Sdes if (strnstr(wc + 1, "*", mlen - wcidx - 1) != NULL) 432253680Sdes return (0); 433253680Sdes /* 434253680Sdes * there must be at least two more domain labels and 435253680Sdes * wildcard has to be in the leftmost label (RFC6125) 436253680Sdes */ 437253680Sdes mdot1 = strnstr(m, ".", mlen); 438253680Sdes if (mdot1 == NULL || mdot1 < wc || (mlen - (mdot1 - m)) < 4) 439253680Sdes return (0); 440253680Sdes mdot1idx = mdot1 - m; 441253680Sdes mdot2 = strnstr(mdot1 + 1, ".", mlen - mdot1idx - 1); 442253680Sdes if (mdot2 == NULL || (mlen - (mdot2 - m)) < 2) 443253680Sdes return (0); 444253680Sdes /* hostname must contain a dot and not be the 1st char */ 445253680Sdes hdot = strnstr(h, ".", hlen); 446253680Sdes if (hdot == NULL || hdot == h) 447253680Sdes return (0); 448253680Sdes hdotidx = hdot - h; 449253680Sdes /* 450253680Sdes * host part of hostname must be at least as long as 451253680Sdes * pattern it's supposed to match 452253680Sdes */ 453253680Sdes if (hdotidx < mdot1idx) 454253680Sdes return (0); 455253680Sdes /* 456253680Sdes * don't allow wildcards in non-traditional domain names 457253680Sdes * (IDN, A-label, U-label...) 458253680Sdes */ 459253680Sdes if (!fetch_ssl_is_trad_domain_label(h, hdotidx, 0) || 460253680Sdes !fetch_ssl_is_trad_domain_label(m, mdot1idx, 1)) 461253680Sdes return (0); 462253680Sdes /* match domain part (part after first dot) */ 463253680Sdes if (!fetch_ssl_hname_equal(hdot, hlen - hdotidx, mdot1, 464253680Sdes mlen - mdot1idx)) 465253680Sdes return (0); 466253680Sdes /* match part left of wildcard */ 467253680Sdes if (!fetch_ssl_hname_equal(h, wcidx, m, wcidx)) 468253680Sdes return (0); 469253680Sdes /* match part right of wildcard */ 470253680Sdes delta = mdot1idx - wcidx - 1; 471253680Sdes if (!fetch_ssl_hname_equal(hdot - delta, delta, 472253680Sdes mdot1 - delta, delta)) 473253680Sdes return (0); 474253680Sdes /* all tests succeded, it's a match */ 475253680Sdes return (1); 476253680Sdes} 477253680Sdes 478253680Sdes/* 479253680Sdes * Get numeric host address info - returns NULL if host was not an IP 480253680Sdes * address. The caller is responsible for deallocation using 481253680Sdes * freeaddrinfo(3). 482253680Sdes */ 483253680Sdesstatic struct addrinfo * 484253680Sdesfetch_ssl_get_numeric_addrinfo(const char *hostname, size_t len) 485253680Sdes{ 486253680Sdes struct addrinfo hints, *res; 487253680Sdes char *host; 488253680Sdes 489253680Sdes host = (char *)malloc(len + 1); 490253680Sdes memcpy(host, hostname, len); 491253680Sdes host[len] = '\0'; 492253680Sdes memset(&hints, 0, sizeof(hints)); 493253680Sdes hints.ai_family = PF_UNSPEC; 494253680Sdes hints.ai_socktype = SOCK_STREAM; 495253680Sdes hints.ai_protocol = 0; 496253680Sdes hints.ai_flags = AI_NUMERICHOST; 497253680Sdes /* port is not relevant for this purpose */ 498253680Sdes getaddrinfo(host, "443", &hints, &res); 499253680Sdes free(host); 500253680Sdes return res; 501253680Sdes} 502253680Sdes 503253680Sdes/* 504253680Sdes * Compare ip address in addrinfo with address passes. 505253680Sdes */ 506253680Sdesstatic int 507253680Sdesfetch_ssl_ipaddr_match_bin(const struct addrinfo *lhost, const char *rhost, 508253680Sdes size_t rhostlen) 509253680Sdes{ 510253680Sdes const void *left; 511253680Sdes 512253680Sdes if (lhost->ai_family == AF_INET && rhostlen == 4) { 513253680Sdes left = (void *)&((struct sockaddr_in*)(void *) 514253680Sdes lhost->ai_addr)->sin_addr.s_addr; 515253680Sdes#ifdef INET6 516253680Sdes } else if (lhost->ai_family == AF_INET6 && rhostlen == 16) { 517253680Sdes left = (void *)&((struct sockaddr_in6 *)(void *) 518253680Sdes lhost->ai_addr)->sin6_addr; 519253680Sdes#endif 520253680Sdes } else 521253680Sdes return (0); 522253680Sdes return (!memcmp(left, (const void *)rhost, rhostlen) ? 1 : 0); 523253680Sdes} 524253680Sdes 525253680Sdes/* 526253680Sdes * Compare ip address in addrinfo with host passed. If host is not an IP 527253680Sdes * address, comparison will fail. 528253680Sdes */ 529253680Sdesstatic int 530253680Sdesfetch_ssl_ipaddr_match(const struct addrinfo *laddr, const char *r, 531253680Sdes size_t rlen) 532253680Sdes{ 533253680Sdes struct addrinfo *raddr; 534253680Sdes int ret; 535253680Sdes char *rip; 536253680Sdes 537253680Sdes ret = 0; 538253680Sdes if ((raddr = fetch_ssl_get_numeric_addrinfo(r, rlen)) == NULL) 539253680Sdes return 0; /* not a numeric host */ 540253680Sdes 541253680Sdes if (laddr->ai_family == raddr->ai_family) { 542253680Sdes if (laddr->ai_family == AF_INET) { 543253680Sdes rip = (char *)&((struct sockaddr_in *)(void *) 544253680Sdes raddr->ai_addr)->sin_addr.s_addr; 545253680Sdes ret = fetch_ssl_ipaddr_match_bin(laddr, rip, 4); 546253680Sdes#ifdef INET6 547253680Sdes } else if (laddr->ai_family == AF_INET6) { 548253680Sdes rip = (char *)&((struct sockaddr_in6 *)(void *) 549253680Sdes raddr->ai_addr)->sin6_addr; 550253680Sdes ret = fetch_ssl_ipaddr_match_bin(laddr, rip, 16); 551253680Sdes#endif 552253680Sdes } 553253680Sdes 554253680Sdes } 555253680Sdes freeaddrinfo(raddr); 556253680Sdes return (ret); 557253680Sdes} 558253680Sdes 559253680Sdes/* 560253680Sdes * Verify server certificate by subjectAltName. 561253680Sdes */ 562253680Sdesstatic int 563253680Sdesfetch_ssl_verify_altname(STACK_OF(GENERAL_NAME) *altnames, 564253680Sdes const char *host, struct addrinfo *ip) 565253680Sdes{ 566253680Sdes const GENERAL_NAME *name; 567253680Sdes size_t nslen; 568253680Sdes int i; 569253680Sdes const char *ns; 570253680Sdes 571253680Sdes for (i = 0; i < sk_GENERAL_NAME_num(altnames); ++i) { 572253680Sdes#if OPENSSL_VERSION_NUMBER < 0x10000000L 573253680Sdes /* 574253680Sdes * This is a workaround, since the following line causes 575253680Sdes * alignment issues in clang: 576253680Sdes * name = sk_GENERAL_NAME_value(altnames, i); 577253680Sdes * OpenSSL explicitly warns not to use those macros 578253680Sdes * directly, but there isn't much choice (and there 579253680Sdes * shouldn't be any ill side effects) 580253680Sdes */ 581253680Sdes name = (GENERAL_NAME *)SKM_sk_value(void, altnames, i); 582253680Sdes#else 583253680Sdes name = sk_GENERAL_NAME_value(altnames, i); 584253680Sdes#endif 585253680Sdes ns = (const char *)ASN1_STRING_data(name->d.ia5); 586253680Sdes nslen = (size_t)ASN1_STRING_length(name->d.ia5); 587253680Sdes 588253680Sdes if (name->type == GEN_DNS && ip == NULL && 589253680Sdes fetch_ssl_hname_match(host, strlen(host), ns, nslen)) 590253680Sdes return (1); 591253680Sdes else if (name->type == GEN_IPADD && ip != NULL && 592253680Sdes fetch_ssl_ipaddr_match_bin(ip, ns, nslen)) 593253680Sdes return (1); 594253680Sdes } 595253680Sdes return (0); 596253680Sdes} 597253680Sdes 598253680Sdes/* 599253680Sdes * Verify server certificate by CN. 600253680Sdes */ 601253680Sdesstatic int 602253680Sdesfetch_ssl_verify_cn(X509_NAME *subject, const char *host, 603253680Sdes struct addrinfo *ip) 604253680Sdes{ 605253680Sdes ASN1_STRING *namedata; 606253680Sdes X509_NAME_ENTRY *nameentry; 607253680Sdes int cnlen, lastpos, loc, ret; 608253680Sdes unsigned char *cn; 609253680Sdes 610253680Sdes ret = 0; 611253680Sdes lastpos = -1; 612253680Sdes loc = -1; 613253680Sdes cn = NULL; 614253680Sdes /* get most specific CN (last entry in list) and compare */ 615253680Sdes while ((lastpos = X509_NAME_get_index_by_NID(subject, 616253680Sdes NID_commonName, lastpos)) != -1) 617253680Sdes loc = lastpos; 618253680Sdes 619253680Sdes if (loc > -1) { 620253680Sdes nameentry = X509_NAME_get_entry(subject, loc); 621253680Sdes namedata = X509_NAME_ENTRY_get_data(nameentry); 622253680Sdes cnlen = ASN1_STRING_to_UTF8(&cn, namedata); 623253680Sdes if (ip == NULL && 624253680Sdes fetch_ssl_hname_match(host, strlen(host), cn, cnlen)) 625253680Sdes ret = 1; 626253680Sdes else if (ip != NULL && fetch_ssl_ipaddr_match(ip, cn, cnlen)) 627253680Sdes ret = 1; 628253680Sdes OPENSSL_free(cn); 629253680Sdes } 630253680Sdes return (ret); 631253680Sdes} 632253680Sdes 633253680Sdes/* 634253680Sdes * Verify that server certificate subjectAltName/CN matches 635253680Sdes * hostname. First check, if there are alternative subject names. If yes, 636253680Sdes * those have to match. Only if those don't exist it falls back to 637253680Sdes * checking the subject's CN. 638253680Sdes */ 639253680Sdesstatic int 640253680Sdesfetch_ssl_verify_hname(X509 *cert, const char *host) 641253680Sdes{ 642253680Sdes struct addrinfo *ip; 643253680Sdes STACK_OF(GENERAL_NAME) *altnames; 644253680Sdes X509_NAME *subject; 645261230Sdes int ret; 646253680Sdes 647253680Sdes ret = 0; 648253680Sdes ip = fetch_ssl_get_numeric_addrinfo(host, strlen(host)); 649253680Sdes altnames = X509_get_ext_d2i(cert, NID_subject_alt_name, 650253680Sdes NULL, NULL); 651253680Sdes 652253680Sdes if (altnames != NULL) { 653253680Sdes ret = fetch_ssl_verify_altname(altnames, host, ip); 654253680Sdes } else { 655253680Sdes subject = X509_get_subject_name(cert); 656253680Sdes if (subject != NULL) 657253680Sdes ret = fetch_ssl_verify_cn(subject, host, ip); 658253680Sdes } 659253680Sdes 660253680Sdes if (ip != NULL) 661253680Sdes freeaddrinfo(ip); 662253680Sdes if (altnames != NULL) 663253680Sdes GENERAL_NAMES_free(altnames); 664253680Sdes return (ret); 665253680Sdes} 666253680Sdes 667253680Sdes/* 668253680Sdes * Configure transport security layer based on environment. 669253680Sdes */ 670253680Sdesstatic void 671253680Sdesfetch_ssl_setup_transport_layer(SSL_CTX *ctx, int verbose) 672253680Sdes{ 673253680Sdes long ssl_ctx_options; 674253680Sdes 675253680Sdes ssl_ctx_options = SSL_OP_ALL | SSL_OP_NO_TICKET; 676253680Sdes if (getenv("SSL_ALLOW_SSL2") == NULL) 677253680Sdes ssl_ctx_options |= SSL_OP_NO_SSLv2; 678253680Sdes if (getenv("SSL_NO_SSL3") != NULL) 679253680Sdes ssl_ctx_options |= SSL_OP_NO_SSLv3; 680253680Sdes if (getenv("SSL_NO_TLS1") != NULL) 681253680Sdes ssl_ctx_options |= SSL_OP_NO_TLSv1; 682253680Sdes if (verbose) 683260904Sdes fetch_info("SSL options: %lx", ssl_ctx_options); 684253680Sdes SSL_CTX_set_options(ctx, ssl_ctx_options); 685253680Sdes} 686253680Sdes 687253680Sdes 688253680Sdes/* 689253680Sdes * Configure peer verification based on environment. 690253680Sdes */ 691266291Sdes#define LOCAL_CERT_FILE "/usr/local/etc/ssl/cert.pem" 692266291Sdes#define BASE_CERT_FILE "/etc/ssl/cert.pem" 693253680Sdesstatic int 694253680Sdesfetch_ssl_setup_peer_verification(SSL_CTX *ctx, int verbose) 695253680Sdes{ 696253680Sdes X509_LOOKUP *crl_lookup; 697253680Sdes X509_STORE *crl_store; 698253680Sdes const char *ca_cert_file, *ca_cert_path, *crl_file; 699253680Sdes 700253680Sdes if (getenv("SSL_NO_VERIFY_PEER") == NULL) { 701266291Sdes ca_cert_file = getenv("SSL_CA_CERT_FILE"); 702266291Sdes if (ca_cert_file == NULL && 703266291Sdes access(LOCAL_CERT_FILE, R_OK) == 0) 704266291Sdes ca_cert_file = LOCAL_CERT_FILE; 705266291Sdes if (ca_cert_file == NULL) 706266291Sdes ca_cert_file = BASE_CERT_FILE; 707253680Sdes ca_cert_path = getenv("SSL_CA_CERT_PATH"); 708253680Sdes if (verbose) { 709253680Sdes fetch_info("Peer verification enabled"); 710253680Sdes if (ca_cert_file != NULL) 711253680Sdes fetch_info("Using CA cert file: %s", 712253680Sdes ca_cert_file); 713253680Sdes if (ca_cert_path != NULL) 714253680Sdes fetch_info("Using CA cert path: %s", 715253680Sdes ca_cert_path); 716253680Sdes } 717253680Sdes SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, 718253680Sdes fetch_ssl_cb_verify_crt); 719253680Sdes SSL_CTX_load_verify_locations(ctx, ca_cert_file, 720253680Sdes ca_cert_path); 721253680Sdes if ((crl_file = getenv("SSL_CRL_FILE")) != NULL) { 722253680Sdes if (verbose) 723253680Sdes fetch_info("Using CRL file: %s", crl_file); 724253680Sdes crl_store = SSL_CTX_get_cert_store(ctx); 725253680Sdes crl_lookup = X509_STORE_add_lookup(crl_store, 726253680Sdes X509_LOOKUP_file()); 727253680Sdes if (crl_lookup == NULL || 728253680Sdes !X509_load_crl_file(crl_lookup, crl_file, 729253680Sdes X509_FILETYPE_PEM)) { 730253680Sdes fprintf(stderr, 731253680Sdes "Could not load CRL file %s\n", 732253680Sdes crl_file); 733253680Sdes return (0); 734253680Sdes } 735253680Sdes X509_STORE_set_flags(crl_store, 736253680Sdes X509_V_FLAG_CRL_CHECK | 737253680Sdes X509_V_FLAG_CRL_CHECK_ALL); 738253680Sdes } 739253680Sdes } 740253680Sdes return (1); 741253680Sdes} 742253680Sdes 743253680Sdes/* 744253680Sdes * Configure client certificate based on environment. 745253680Sdes */ 746253680Sdesstatic int 747253680Sdesfetch_ssl_setup_client_certificate(SSL_CTX *ctx, int verbose) 748253680Sdes{ 749253680Sdes const char *client_cert_file, *client_key_file; 750253680Sdes 751253680Sdes if ((client_cert_file = getenv("SSL_CLIENT_CERT_FILE")) != NULL) { 752253680Sdes client_key_file = getenv("SSL_CLIENT_KEY_FILE") != NULL ? 753253680Sdes getenv("SSL_CLIENT_KEY_FILE") : client_cert_file; 754253680Sdes if (verbose) { 755253680Sdes fetch_info("Using client cert file: %s", 756253680Sdes client_cert_file); 757253680Sdes fetch_info("Using client key file: %s", 758253680Sdes client_key_file); 759253680Sdes } 760253680Sdes if (SSL_CTX_use_certificate_chain_file(ctx, 761253680Sdes client_cert_file) != 1) { 762253680Sdes fprintf(stderr, 763253680Sdes "Could not load client certificate %s\n", 764253680Sdes client_cert_file); 765253680Sdes return (0); 766253680Sdes } 767253680Sdes if (SSL_CTX_use_PrivateKey_file(ctx, client_key_file, 768253680Sdes SSL_FILETYPE_PEM) != 1) { 769253680Sdes fprintf(stderr, 770253680Sdes "Could not load client key %s\n", 771253680Sdes client_key_file); 772253680Sdes return (0); 773253680Sdes } 774253680Sdes } 775253680Sdes return (1); 776253680Sdes} 777253680Sdes 778253680Sdes/* 779253680Sdes * Callback for SSL certificate verification, this is called on server 780253680Sdes * cert verification. It takes no decision, but informs the user in case 781253680Sdes * verification failed. 782253680Sdes */ 783253680Sdesint 784253680Sdesfetch_ssl_cb_verify_crt(int verified, X509_STORE_CTX *ctx) 785253680Sdes{ 786253680Sdes X509 *crt; 787253680Sdes X509_NAME *name; 788253680Sdes char *str; 789253680Sdes 790253680Sdes str = NULL; 791253680Sdes if (!verified) { 792253680Sdes if ((crt = X509_STORE_CTX_get_current_cert(ctx)) != NULL && 793253680Sdes (name = X509_get_subject_name(crt)) != NULL) 794253680Sdes str = X509_NAME_oneline(name, 0, 0); 795253680Sdes fprintf(stderr, "Certificate verification failed for %s\n", 796253680Sdes str != NULL ? str : "no relevant certificate"); 797253680Sdes OPENSSL_free(str); 798253680Sdes } 799253680Sdes return (verified); 800253680Sdes} 801253680Sdes 802253680Sdes#endif 803253680Sdes 804253680Sdes/* 80597868Sdes * Enable SSL on a connection. 80697868Sdes */ 80797868Sdesint 808253680Sdesfetch_ssl(conn_t *conn, const struct url *URL, int verbose) 80997868Sdes{ 810214256Semaste#ifdef WITH_SSL 811210568Sdes int ret, ssl_err; 812253680Sdes X509_NAME *name; 813253680Sdes char *str; 81497868Sdes 81597868Sdes /* Init the SSL library and context */ 81697868Sdes if (!SSL_library_init()){ 81797868Sdes fprintf(stderr, "SSL library init failed\n"); 81897868Sdes return (-1); 81997868Sdes } 82097868Sdes 82197868Sdes SSL_load_error_strings(); 82297868Sdes 82397868Sdes conn->ssl_meth = SSLv23_client_method(); 82497868Sdes conn->ssl_ctx = SSL_CTX_new(conn->ssl_meth); 825108579Sdes SSL_CTX_set_mode(conn->ssl_ctx, SSL_MODE_AUTO_RETRY); 82697868Sdes 827253680Sdes fetch_ssl_setup_transport_layer(conn->ssl_ctx, verbose); 828253680Sdes if (!fetch_ssl_setup_peer_verification(conn->ssl_ctx, verbose)) 829253680Sdes return (-1); 830253680Sdes if (!fetch_ssl_setup_client_certificate(conn->ssl_ctx, verbose)) 831253680Sdes return (-1); 832253680Sdes 83397868Sdes conn->ssl = SSL_new(conn->ssl_ctx); 834253680Sdes if (conn->ssl == NULL) { 83597868Sdes fprintf(stderr, "SSL context creation failed\n"); 83697868Sdes return (-1); 83797868Sdes } 83897868Sdes SSL_set_fd(conn->ssl, conn->sd); 839258347Sbdrewery 840258347Sbdrewery#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT) 841258349Sbdrewery if (!SSL_set_tlsext_host_name(conn->ssl, 842258349Sbdrewery __DECONST(struct url *, URL)->host)) { 843258347Sbdrewery fprintf(stderr, 844258347Sbdrewery "TLS server name indication extension failed for host %s\n", 845258347Sbdrewery URL->host); 846258347Sbdrewery return (-1); 847258347Sbdrewery } 848258347Sbdrewery#endif 849210568Sdes while ((ret = SSL_connect(conn->ssl)) == -1) { 850210568Sdes ssl_err = SSL_get_error(conn->ssl, ret); 851210568Sdes if (ssl_err != SSL_ERROR_WANT_READ && 852210568Sdes ssl_err != SSL_ERROR_WANT_WRITE) { 853210568Sdes ERR_print_errors_fp(stderr); 854210568Sdes return (-1); 855210568Sdes } 85697868Sdes } 857253680Sdes conn->ssl_cert = SSL_get_peer_certificate(conn->ssl); 85897868Sdes 859253680Sdes if (conn->ssl_cert == NULL) { 860253680Sdes fprintf(stderr, "No server SSL certificate\n"); 861253680Sdes return (-1); 862253680Sdes } 863253680Sdes 864253680Sdes if (getenv("SSL_NO_VERIFY_HOSTNAME") == NULL) { 865253680Sdes if (verbose) 866253680Sdes fetch_info("Verify hostname"); 867253680Sdes if (!fetch_ssl_verify_hname(conn->ssl_cert, URL->host)) { 868253680Sdes fprintf(stderr, 869253680Sdes "SSL certificate subject doesn't match host %s\n", 870253680Sdes URL->host); 871253680Sdes return (-1); 872253680Sdes } 873253680Sdes } 874253680Sdes 87597868Sdes if (verbose) { 876253680Sdes fetch_info("SSL connection established using %s", 87797868Sdes SSL_get_cipher(conn->ssl)); 87897868Sdes name = X509_get_subject_name(conn->ssl_cert); 87997868Sdes str = X509_NAME_oneline(name, 0, 0); 880253680Sdes fetch_info("Certificate subject: %s", str); 881253680Sdes OPENSSL_free(str); 88297868Sdes name = X509_get_issuer_name(conn->ssl_cert); 88397868Sdes str = X509_NAME_oneline(name, 0, 0); 884253680Sdes fetch_info("Certificate issuer: %s", str); 885253680Sdes OPENSSL_free(str); 88697868Sdes } 88797868Sdes 88897868Sdes return (0); 88997891Sdes#else 89097891Sdes (void)conn; 89197891Sdes (void)verbose; 89297891Sdes fprintf(stderr, "SSL support disabled\n"); 89397891Sdes return (-1); 89497891Sdes#endif 89597868Sdes} 89697868Sdes 897210568Sdes#define FETCH_READ_WAIT -2 898210568Sdes#define FETCH_READ_ERROR -1 899210568Sdes#define FETCH_READ_DONE 0 90098117Sdes 901210568Sdes#ifdef WITH_SSL 902210568Sdesstatic ssize_t 903210568Sdesfetch_ssl_read(SSL *ssl, char *buf, size_t len) 904210568Sdes{ 905210568Sdes ssize_t rlen; 906210568Sdes int ssl_err; 907210568Sdes 908210568Sdes rlen = SSL_read(ssl, buf, len); 909210568Sdes if (rlen < 0) { 910210568Sdes ssl_err = SSL_get_error(ssl, rlen); 911210568Sdes if (ssl_err == SSL_ERROR_WANT_READ || 912210568Sdes ssl_err == SSL_ERROR_WANT_WRITE) { 913210568Sdes return (FETCH_READ_WAIT); 914210568Sdes } else { 915210568Sdes ERR_print_errors_fp(stderr); 916210568Sdes return (FETCH_READ_ERROR); 917210568Sdes } 918210568Sdes } 919210568Sdes return (rlen); 920210568Sdes} 921210568Sdes#endif 922210568Sdes 923210568Sdesstatic ssize_t 924210568Sdesfetch_socket_read(int sd, char *buf, size_t len) 925210568Sdes{ 926210568Sdes ssize_t rlen; 927210568Sdes 928210568Sdes rlen = read(sd, buf, len); 929210568Sdes if (rlen < 0) { 930210568Sdes if (errno == EAGAIN || (errno == EINTR && fetchRestartCalls)) 931210568Sdes return (FETCH_READ_WAIT); 932210568Sdes else 933210568Sdes return (FETCH_READ_ERROR); 934210568Sdes } 935210568Sdes return (rlen); 936210568Sdes} 937210568Sdes 93897868Sdes/* 93997866Sdes * Read a character from a connection w/ timeout 94055557Sdes */ 94197866Sdesssize_t 942174588Sdesfetch_read(conn_t *conn, char *buf, size_t len) 94355557Sdes{ 944177447Sdes struct timeval now, timeout, delta; 945261230Sdes struct pollfd pfd; 946261230Sdes ssize_t rlen; 947261230Sdes int deltams; 94890267Sdes 949234837Sdes if (fetchTimeout > 0) { 95090267Sdes gettimeofday(&timeout, NULL); 95190267Sdes timeout.tv_sec += fetchTimeout; 95255557Sdes } 95390267Sdes 954261230Sdes deltams = INFTIM; 955261230Sdes memset(&pfd, 0, sizeof pfd); 956261230Sdes pfd.fd = conn->sd; 957261230Sdes pfd.events = POLLIN | POLLERR; 958230307Sdes 959261230Sdes for (;;) { 960230307Sdes /* 961210568Sdes * The socket is non-blocking. Instead of the canonical 962261230Sdes * poll() -> read(), we do the following: 963210568Sdes * 964210568Sdes * 1) call read() or SSL_read(). 965261230Sdes * 2) if we received some data, return it. 966261230Sdes * 3) if an error occurred, return -1. 967210568Sdes * 4) if read() or SSL_read() signaled EOF, return. 968210568Sdes * 5) if we did not receive any data but we're not at EOF, 969261230Sdes * call poll(). 970210568Sdes * 971210568Sdes * In the SSL case, this is necessary because if we 972210568Sdes * receive a close notification, we have to call 973210568Sdes * SSL_read() one additional time after we've read 974210568Sdes * everything we received. 975210568Sdes * 976210568Sdes * In the non-SSL case, it may improve performance (very 977210568Sdes * slightly) when reading small amounts of data. 978210568Sdes */ 979210568Sdes#ifdef WITH_SSL 980210568Sdes if (conn->ssl != NULL) 981210568Sdes rlen = fetch_ssl_read(conn->ssl, buf, len); 982210568Sdes else 983210568Sdes#endif 984210568Sdes rlen = fetch_socket_read(conn->sd, buf, len); 985261263Sdes if (rlen >= 0) { 986210568Sdes break; 987210568Sdes } else if (rlen == FETCH_READ_ERROR) { 988261263Sdes fetch_syserr(); 989210568Sdes return (-1); 990210568Sdes } 991261263Sdes // assert(rlen == FETCH_READ_WAIT); 992261230Sdes if (fetchTimeout > 0) { 993261230Sdes gettimeofday(&now, NULL); 994261230Sdes if (!timercmp(&timeout, &now, >)) { 995261230Sdes errno = ETIMEDOUT; 996174588Sdes fetch_syserr(); 99790267Sdes return (-1); 99890267Sdes } 999261230Sdes timersub(&timeout, &now, &delta); 1000261230Sdes deltams = delta.tv_sec * 1000 + 1001261230Sdes delta.tv_usec / 1000;; 100290267Sdes } 1003261230Sdes errno = 0; 1004261230Sdes pfd.revents = 0; 1005261230Sdes if (poll(&pfd, 1, deltams) < 0) { 1006261230Sdes if (errno == EINTR && fetchRestartCalls) 1007261230Sdes continue; 1008261230Sdes fetch_syserr(); 1009261230Sdes return (-1); 1010261230Sdes } 101197866Sdes } 1012261230Sdes return (rlen); 101397866Sdes} 101497866Sdes 101598117Sdes 101697866Sdes/* 101797866Sdes * Read a line of text from a connection w/ timeout 101897866Sdes */ 101997866Sdes#define MIN_BUF_SIZE 1024 102097866Sdes 102197866Sdesint 1022174588Sdesfetch_getln(conn_t *conn) 102397866Sdes{ 102497866Sdes char *tmp; 102597866Sdes size_t tmpsize; 1026106186Sdes ssize_t len; 102797866Sdes char c; 102897866Sdes 102997866Sdes if (conn->buf == NULL) { 103097866Sdes if ((conn->buf = malloc(MIN_BUF_SIZE)) == NULL) { 103197866Sdes errno = ENOMEM; 103297866Sdes return (-1); 103397866Sdes } 103497866Sdes conn->bufsize = MIN_BUF_SIZE; 103597866Sdes } 103697866Sdes 103797866Sdes conn->buf[0] = '\0'; 103897866Sdes conn->buflen = 0; 103997866Sdes 104097866Sdes do { 1041174588Sdes len = fetch_read(conn, &c, 1); 1042106186Sdes if (len == -1) 104397866Sdes return (-1); 1044106186Sdes if (len == 0) 1045106137Sobrien break; 104697856Sdes conn->buf[conn->buflen++] = c; 104797856Sdes if (conn->buflen == conn->bufsize) { 104897856Sdes tmp = conn->buf; 104997856Sdes tmpsize = conn->bufsize * 2 + 1; 105097856Sdes if ((tmp = realloc(tmp, tmpsize)) == NULL) { 105190267Sdes errno = ENOMEM; 105290267Sdes return (-1); 105390267Sdes } 105497856Sdes conn->buf = tmp; 105597856Sdes conn->bufsize = tmpsize; 105690267Sdes } 105790267Sdes } while (c != '\n'); 105890267Sdes 105997856Sdes conn->buf[conn->buflen] = '\0'; 106097856Sdes DEBUG(fprintf(stderr, "<<< %s", conn->buf)); 106190267Sdes return (0); 106255557Sdes} 106355557Sdes 106455557Sdes 106562981Sdes/* 106697866Sdes * Write to a connection w/ timeout 106762981Sdes */ 106897866Sdesssize_t 1069174588Sdesfetch_write(conn_t *conn, const char *buf, size_t len) 107097866Sdes{ 1071106175Simp struct iovec iov; 1072106175Simp 1073106175Simp iov.iov_base = __DECONST(char *, buf); 1074106175Simp iov.iov_len = len; 1075174588Sdes return fetch_writev(conn, &iov, 1); 1076106175Simp} 1077106175Simp 1078106175Simp/* 1079106175Simp * Write a vector to a connection w/ timeout 1080106175Simp * Note: can modify the iovec. 1081106175Simp */ 1082106175Simpssize_t 1083174588Sdesfetch_writev(conn_t *conn, struct iovec *iov, int iovcnt) 1084106175Simp{ 1085177447Sdes struct timeval now, timeout, delta; 1086261230Sdes struct pollfd pfd; 108797866Sdes ssize_t wlen, total; 1088261263Sdes int deltams; 108997866Sdes 1090261230Sdes memset(&pfd, 0, sizeof pfd); 109197866Sdes if (fetchTimeout) { 1092261230Sdes pfd.fd = conn->sd; 1093261230Sdes pfd.events = POLLOUT | POLLERR; 109497866Sdes gettimeofday(&timeout, NULL); 109597866Sdes timeout.tv_sec += fetchTimeout; 109697866Sdes } 109797866Sdes 1098106175Simp total = 0; 1099106175Simp while (iovcnt > 0) { 1100261230Sdes while (fetchTimeout && pfd.revents == 0) { 110197866Sdes gettimeofday(&now, NULL); 1102261263Sdes if (!timercmp(&timeout, &now, >)) { 110397866Sdes errno = ETIMEDOUT; 1104174588Sdes fetch_syserr(); 110597866Sdes return (-1); 110697866Sdes } 1107261263Sdes timersub(&timeout, &now, &delta); 1108261263Sdes deltams = delta.tv_sec * 1000 + 1109261263Sdes delta.tv_usec / 1000; 111097866Sdes errno = 0; 1111261263Sdes pfd.revents = 0; 1112261263Sdes if (poll(&pfd, 1, deltams) < 0) { 111397866Sdes if (errno == EINTR && fetchRestartCalls) 111497866Sdes continue; 111597866Sdes return (-1); 111697866Sdes } 111797866Sdes } 111897866Sdes errno = 0; 111997891Sdes#ifdef WITH_SSL 112097866Sdes if (conn->ssl != NULL) 1121106175Simp wlen = SSL_write(conn->ssl, 1122106175Simp iov->iov_base, iov->iov_len); 112397866Sdes else 112497891Sdes#endif 1125106175Simp wlen = writev(conn->sd, iov, iovcnt); 1126106175Simp if (wlen == 0) { 112797866Sdes /* we consider a short write a failure */ 1128210568Sdes /* XXX perhaps we shouldn't in the SSL case */ 1129106175Simp errno = EPIPE; 1130174588Sdes fetch_syserr(); 113197866Sdes return (-1); 1132106175Simp } 113397866Sdes if (wlen < 0) { 113497866Sdes if (errno == EINTR && fetchRestartCalls) 113597866Sdes continue; 113697866Sdes return (-1); 113797866Sdes } 113897866Sdes total += wlen; 1139106175Simp while (iovcnt > 0 && wlen >= (ssize_t)iov->iov_len) { 1140106175Simp wlen -= iov->iov_len; 1141106175Simp iov++; 1142106175Simp iovcnt--; 1143106175Simp } 1144106175Simp if (iovcnt > 0) { 1145106175Simp iov->iov_len -= wlen; 1146106175Simp iov->iov_base = __DECONST(char *, iov->iov_base) + wlen; 1147106175Simp } 114897866Sdes } 114997866Sdes return (total); 115097866Sdes} 115197866Sdes 115298117Sdes 115397866Sdes/* 115497866Sdes * Write a line of text to a connection w/ timeout 115597866Sdes */ 115662981Sdesint 1157174588Sdesfetch_putln(conn_t *conn, const char *str, size_t len) 115862981Sdes{ 1159106175Simp struct iovec iov[2]; 1160106205Sdes int ret; 116198748Sdes 116298748Sdes DEBUG(fprintf(stderr, ">>> %s\n", str)); 1163106175Simp iov[0].iov_base = __DECONST(char *, str); 1164106175Simp iov[0].iov_len = len; 1165106175Simp iov[1].iov_base = __DECONST(char *, ENDL); 1166109967Sdes iov[1].iov_len = sizeof(ENDL); 1167106205Sdes if (len == 0) 1168174588Sdes ret = fetch_writev(conn, &iov[1], 1); 1169106205Sdes else 1170174588Sdes ret = fetch_writev(conn, iov, 2); 1171106205Sdes if (ret == -1) 117290267Sdes return (-1); 117390267Sdes return (0); 117462981Sdes} 117562981Sdes 117662981Sdes 117797856Sdes/* 117897856Sdes * Close connection 117997856Sdes */ 118097856Sdesint 1181174588Sdesfetch_close(conn_t *conn) 118297856Sdes{ 118397856Sdes int ret; 118497856Sdes 118598117Sdes if (--conn->ref > 0) 118698117Sdes return (0); 1187253680Sdes#ifdef WITH_SSL 1188253680Sdes if (conn->ssl) { 1189253680Sdes SSL_shutdown(conn->ssl); 1190253680Sdes SSL_set_connect_state(conn->ssl); 1191253680Sdes SSL_free(conn->ssl); 1192253680Sdes conn->ssl = NULL; 1193253680Sdes } 1194253680Sdes if (conn->ssl_ctx) { 1195253680Sdes SSL_CTX_free(conn->ssl_ctx); 1196253680Sdes conn->ssl_ctx = NULL; 1197253680Sdes } 1198253680Sdes if (conn->ssl_cert) { 1199253680Sdes X509_free(conn->ssl_cert); 1200253680Sdes conn->ssl_cert = NULL; 1201253680Sdes } 1202253680Sdes#endif 120397856Sdes ret = close(conn->sd); 1204141970Sdes free(conn->buf); 120597856Sdes free(conn); 120697856Sdes return (ret); 120797856Sdes} 120897856Sdes 120997856Sdes 121041989Sdes/*** Directory-related utility functions *************************************/ 121141989Sdes 121241989Sdesint 1213174588Sdesfetch_add_entry(struct url_ent **p, int *size, int *len, 121490267Sdes const char *name, struct url_stat *us) 121541989Sdes{ 121690267Sdes struct url_ent *tmp; 121741989Sdes 121890267Sdes if (*p == NULL) { 121990268Sdes *size = 0; 122090267Sdes *len = 0; 122141989Sdes } 122241989Sdes 122390267Sdes if (*len >= *size - 1) { 1224109967Sdes tmp = realloc(*p, (*size * 2 + 1) * sizeof(**p)); 122590267Sdes if (tmp == NULL) { 122690267Sdes errno = ENOMEM; 1227174588Sdes fetch_syserr(); 122890267Sdes return (-1); 122990267Sdes } 123090268Sdes *size = (*size * 2 + 1); 123190267Sdes *p = tmp; 123290267Sdes } 123341989Sdes 123490267Sdes tmp = *p + *len; 123590267Sdes snprintf(tmp->name, PATH_MAX, "%s", name); 1236176105Sdes memcpy(&tmp->stat, us, sizeof(*us)); 123741989Sdes 123890267Sdes (*len)++; 123990267Sdes (++tmp)->name[0] = 0; 124090267Sdes 124190267Sdes return (0); 124241989Sdes} 1243109695Sdes 1244109695Sdes 1245109695Sdes/*** Authentication-related utility functions ********************************/ 1246109695Sdes 1247109695Sdesstatic const char * 1248174588Sdesfetch_read_word(FILE *f) 1249109695Sdes{ 1250109695Sdes static char word[1024]; 1251109695Sdes 1252178234Scperciva if (fscanf(f, " %1023s ", word) != 1) 1253109695Sdes return (NULL); 1254109695Sdes return (word); 1255109695Sdes} 1256109695Sdes 1257109695Sdes/* 1258109695Sdes * Get authentication data for a URL from .netrc 1259109695Sdes */ 1260109695Sdesint 1261174588Sdesfetch_netrc_auth(struct url *url) 1262109695Sdes{ 1263109695Sdes char fn[PATH_MAX]; 1264109695Sdes const char *word; 1265109695Sdes char *p; 1266109695Sdes FILE *f; 1267109695Sdes 1268109695Sdes if ((p = getenv("NETRC")) != NULL) { 1269109967Sdes if (snprintf(fn, sizeof(fn), "%s", p) >= (int)sizeof(fn)) { 1270174588Sdes fetch_info("$NETRC specifies a file name " 1271109695Sdes "longer than PATH_MAX"); 1272109695Sdes return (-1); 1273109695Sdes } 1274109695Sdes } else { 1275109695Sdes if ((p = getenv("HOME")) != NULL) { 1276109695Sdes struct passwd *pwd; 1277109695Sdes 1278109695Sdes if ((pwd = getpwuid(getuid())) == NULL || 1279109695Sdes (p = pwd->pw_dir) == NULL) 1280109695Sdes return (-1); 1281109695Sdes } 1282109967Sdes if (snprintf(fn, sizeof(fn), "%s/.netrc", p) >= (int)sizeof(fn)) 1283109695Sdes return (-1); 1284109695Sdes } 1285109695Sdes 1286109695Sdes if ((f = fopen(fn, "r")) == NULL) 1287109695Sdes return (-1); 1288174588Sdes while ((word = fetch_read_word(f)) != NULL) { 1289109695Sdes if (strcmp(word, "default") == 0) { 1290174588Sdes DEBUG(fetch_info("Using default .netrc settings")); 1291109695Sdes break; 1292109695Sdes } 1293109695Sdes if (strcmp(word, "machine") == 0 && 1294174588Sdes (word = fetch_read_word(f)) != NULL && 1295109695Sdes strcasecmp(word, url->host) == 0) { 1296174588Sdes DEBUG(fetch_info("Using .netrc settings for %s", word)); 1297109695Sdes break; 1298109695Sdes } 1299109695Sdes } 1300109695Sdes if (word == NULL) 1301109695Sdes goto ferr; 1302174588Sdes while ((word = fetch_read_word(f)) != NULL) { 1303109695Sdes if (strcmp(word, "login") == 0) { 1304174588Sdes if ((word = fetch_read_word(f)) == NULL) 1305109695Sdes goto ferr; 1306109967Sdes if (snprintf(url->user, sizeof(url->user), 1307109960Sjwd "%s", word) > (int)sizeof(url->user)) { 1308174588Sdes fetch_info("login name in .netrc is too long"); 1309109695Sdes url->user[0] = '\0'; 1310109695Sdes } 1311109695Sdes } else if (strcmp(word, "password") == 0) { 1312174588Sdes if ((word = fetch_read_word(f)) == NULL) 1313109695Sdes goto ferr; 1314109967Sdes if (snprintf(url->pwd, sizeof(url->pwd), 1315109960Sjwd "%s", word) > (int)sizeof(url->pwd)) { 1316174588Sdes fetch_info("password in .netrc is too long"); 1317109695Sdes url->pwd[0] = '\0'; 1318109695Sdes } 1319109695Sdes } else if (strcmp(word, "account") == 0) { 1320174588Sdes if ((word = fetch_read_word(f)) == NULL) 1321109695Sdes goto ferr; 1322109695Sdes /* XXX not supported! */ 1323109695Sdes } else { 1324109695Sdes break; 1325109695Sdes } 1326109695Sdes } 1327109695Sdes fclose(f); 1328109695Sdes return (0); 1329109695Sdes ferr: 1330109695Sdes fclose(f); 1331109695Sdes return (-1); 1332109695Sdes} 1333174752Sdes 1334174752Sdes/* 1335174752Sdes * The no_proxy environment variable specifies a set of domains for 1336174752Sdes * which the proxy should not be consulted; the contents is a comma-, 1337174752Sdes * or space-separated list of domain names. A single asterisk will 1338174752Sdes * override all proxy variables and no transactions will be proxied 1339174752Sdes * (for compatability with lynx and curl, see the discussion at 1340174752Sdes * <http://curl.haxx.se/mail/archive_pre_oct_99/0009.html>). 1341174752Sdes */ 1342174752Sdesint 1343174752Sdesfetch_no_proxy_match(const char *host) 1344174752Sdes{ 1345174752Sdes const char *no_proxy, *p, *q; 1346174752Sdes size_t h_len, d_len; 1347174752Sdes 1348174752Sdes if ((no_proxy = getenv("NO_PROXY")) == NULL && 1349174752Sdes (no_proxy = getenv("no_proxy")) == NULL) 1350174752Sdes return (0); 1351174752Sdes 1352174752Sdes /* asterisk matches any hostname */ 1353174752Sdes if (strcmp(no_proxy, "*") == 0) 1354174752Sdes return (1); 1355174752Sdes 1356174752Sdes h_len = strlen(host); 1357174752Sdes p = no_proxy; 1358174752Sdes do { 1359174752Sdes /* position p at the beginning of a domain suffix */ 1360174761Sdes while (*p == ',' || isspace((unsigned char)*p)) 1361174752Sdes p++; 1362174752Sdes 1363174752Sdes /* position q at the first separator character */ 1364174752Sdes for (q = p; *q; ++q) 1365174761Sdes if (*q == ',' || isspace((unsigned char)*q)) 1366174752Sdes break; 1367174752Sdes 1368174752Sdes d_len = q - p; 1369198339Sfabient if (d_len > 0 && h_len >= d_len && 1370174752Sdes strncasecmp(host + h_len - d_len, 1371174752Sdes p, d_len) == 0) { 1372174752Sdes /* domain name matches */ 1373174752Sdes return (1); 1374174752Sdes } 1375174752Sdes 1376174752Sdes p = q + 1; 1377174752Sdes } while (*q); 1378174752Sdes 1379174752Sdes return (0); 1380174752Sdes} 1381