140939Sdes/*- 2310060Sdes * Copyright (c) 1998-2016 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: stable/10/lib/libfetch/common.c 323660 2017-09-17 01:32:45Z marius $"); 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> 44262560Sdes#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; 156315904Sdes default: 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/* 244310060Sdes * Resolve an address 245310060Sdes */ 246310060Sdesstruct addrinfo * 247310060Sdesfetch_resolve(const char *addr, int port, int af) 248310060Sdes{ 249310060Sdes char hbuf[256], sbuf[8]; 250310060Sdes struct addrinfo hints, *res; 251315904Sdes const char *hb, *he, *sep; 252315904Sdes const char *host, *service; 253310060Sdes int err, len; 254310060Sdes 255315904Sdes /* first, check for a bracketed IPv6 address */ 256315904Sdes if (*addr == '[') { 257315904Sdes hb = addr + 1; 258315904Sdes if ((sep = strchr(hb, ']')) == NULL) { 259315904Sdes errno = EINVAL; 260315904Sdes goto syserr; 261315904Sdes } 262315904Sdes he = sep++; 263315904Sdes } else { 264315904Sdes hb = addr; 265315904Sdes sep = strchrnul(hb, ':'); 266315904Sdes he = sep; 267315904Sdes } 268315904Sdes 269315904Sdes /* see if we need to copy the host name */ 270315904Sdes if (*he != '\0') { 271310060Sdes len = snprintf(hbuf, sizeof(hbuf), 272315904Sdes "%.*s", (int)(he - hb), hb); 273310060Sdes if (len < 0) 274315904Sdes goto syserr; 275310060Sdes if (len >= (int)sizeof(hbuf)) { 276310060Sdes errno = ENAMETOOLONG; 277315904Sdes goto syserr; 278310060Sdes } 279310060Sdes host = hbuf; 280315904Sdes } else { 281315904Sdes host = hb; 282315904Sdes } 283315904Sdes 284315904Sdes /* was it followed by a service name? */ 285315904Sdes if (*sep == '\0' && port != 0) { 286310060Sdes if (port < 1 || port > 65535) { 287310060Sdes errno = EINVAL; 288315904Sdes goto syserr; 289310060Sdes } 290315904Sdes if (snprintf(sbuf, sizeof(sbuf), "%d", port) < 0) 291315904Sdes goto syserr; 292310060Sdes service = sbuf; 293315904Sdes } else if (*sep != '\0') { 294323660Smarius service = sep + 1; 295310060Sdes } else { 296310060Sdes service = NULL; 297310060Sdes } 298310060Sdes 299310060Sdes /* resolve */ 300310060Sdes memset(&hints, 0, sizeof(hints)); 301310060Sdes hints.ai_family = af; 302310060Sdes hints.ai_socktype = SOCK_STREAM; 303310060Sdes hints.ai_flags = AI_ADDRCONFIG; 304310060Sdes if ((err = getaddrinfo(host, service, &hints, &res)) != 0) { 305310060Sdes netdb_seterr(err); 306310060Sdes return (NULL); 307310060Sdes } 308310060Sdes return (res); 309315904Sdessyserr: 310315904Sdes fetch_syserr(); 311315904Sdes return (NULL); 312310060Sdes} 313310060Sdes 314310060Sdes 315310060Sdes 316310060Sdes/* 317111816Sdes * Bind a socket to a specific local address 318111816Sdes */ 319111816Sdesint 320174588Sdesfetch_bind(int sd, int af, const char *addr) 321111816Sdes{ 322310060Sdes struct addrinfo *cliai, *ai; 323111816Sdes int err; 324111816Sdes 325310060Sdes if ((cliai = fetch_resolve(addr, 0, af)) == NULL) 326111816Sdes return (-1); 327310060Sdes for (ai = cliai; ai != NULL; ai = ai->ai_next) 328310060Sdes if ((err = bind(sd, ai->ai_addr, ai->ai_addrlen)) == 0) 329310060Sdes break; 330310060Sdes if (err != 0) 331310060Sdes fetch_syserr(); 332310060Sdes freeaddrinfo(cliai); 333310060Sdes return (err == 0 ? 0 : -1); 334111816Sdes} 335111816Sdes 336111816Sdes 337111816Sdes/* 33840939Sdes * Establish a TCP connection to the specified port on the specified host. 33940939Sdes */ 34097856Sdesconn_t * 341174588Sdesfetch_connect(const char *host, int port, int af, int verbose) 34240939Sdes{ 343310060Sdes struct addrinfo *cais = NULL, *sais = NULL, *cai, *sai; 344111816Sdes const char *bindaddr; 345310060Sdes conn_t *conn = NULL; 346310060Sdes int err = 0, sd = -1; 34740939Sdes 34890267Sdes DEBUG(fprintf(stderr, "---> %s:%d\n", host, port)); 34941862Sdes 350310060Sdes /* resolve server address */ 35190267Sdes if (verbose) 352310060Sdes fetch_info("resolving server address: %s:%d", host, port); 353310060Sdes if ((sais = fetch_resolve(host, port, af)) == NULL) 354310060Sdes goto fail; 35540939Sdes 356310060Sdes /* resolve client address */ 357310060Sdes bindaddr = getenv("FETCH_BIND_ADDRESS"); 358310060Sdes if (bindaddr != NULL && *bindaddr != '\0') { 359310060Sdes if (verbose) 360310060Sdes fetch_info("resolving client address: %s", bindaddr); 361310060Sdes if ((cais = fetch_resolve(bindaddr, 0, af)) == NULL) 362310060Sdes goto fail; 36390267Sdes } 36490267Sdes 365310060Sdes /* try each server address in turn */ 366310060Sdes for (err = 0, sai = sais; sai != NULL; sai = sai->ai_next) { 367310060Sdes /* open socket */ 368310060Sdes if ((sd = socket(sai->ai_family, SOCK_STREAM, 0)) < 0) 369310060Sdes goto syserr; 370310060Sdes /* attempt to bind to client address */ 371310060Sdes for (err = 0, cai = cais; cai != NULL; cai = cai->ai_next) { 372310060Sdes if (cai->ai_family != sai->ai_family) 373310060Sdes continue; 374310060Sdes if ((err = bind(sd, cai->ai_addr, cai->ai_addrlen)) == 0) 375310060Sdes break; 376111816Sdes } 377310060Sdes if (err != 0) { 378310060Sdes if (verbose) 379310060Sdes fetch_info("failed to bind to %s", bindaddr); 380310060Sdes goto syserr; 381310060Sdes } 382310060Sdes /* attempt to connect to server address */ 383310060Sdes if ((err = connect(sd, sai->ai_addr, sai->ai_addrlen)) == 0) 38490267Sdes break; 385310060Sdes /* clean up before next attempt */ 38690267Sdes close(sd); 387310060Sdes sd = -1; 38890267Sdes } 389310060Sdes if (err != 0) { 390310060Sdes if (verbose) 391315904Sdes fetch_info("failed to connect to %s:%d", host, port); 392310060Sdes goto syserr; 39390267Sdes } 39440939Sdes 395310060Sdes if ((conn = fetch_reopen(sd)) == NULL) 396310060Sdes goto syserr; 397310060Sdes if (cais != NULL) 398310060Sdes freeaddrinfo(cais); 399310060Sdes if (sais != NULL) 400310060Sdes freeaddrinfo(sais); 401310060Sdes return (conn); 402310060Sdessyserr: 403310060Sdes fetch_syserr(); 404310060Sdes goto fail; 405310060Sdesfail: 406310060Sdes if (sd >= 0) 40797856Sdes close(sd); 408310060Sdes if (cais != NULL) 409310060Sdes freeaddrinfo(cais); 410310060Sdes if (sais != NULL) 411310060Sdes freeaddrinfo(sais); 412310060Sdes return (NULL); 41340939Sdes} 41441989Sdes 415253680Sdes#ifdef WITH_SSL 416253680Sdes/* 417253680Sdes * Convert characters A-Z to lowercase (intentionally avoid any locale 418253680Sdes * specific conversions). 419253680Sdes */ 420253680Sdesstatic char 421253680Sdesfetch_ssl_tolower(char in) 422253680Sdes{ 423253680Sdes if (in >= 'A' && in <= 'Z') 424253680Sdes return (in + 32); 425253680Sdes else 426253680Sdes return (in); 427253680Sdes} 42841989Sdes 42955557Sdes/* 430253680Sdes * isalpha implementation that intentionally avoids any locale specific 431253680Sdes * conversions. 432253680Sdes */ 433253680Sdesstatic int 434253680Sdesfetch_ssl_isalpha(char in) 435253680Sdes{ 436253680Sdes return ((in >= 'A' && in <= 'Z') || (in >= 'a' && in <= 'z')); 437253680Sdes} 438253680Sdes 439253680Sdes/* 440253680Sdes * Check if passed hostnames a and b are equal. 441253680Sdes */ 442253680Sdesstatic int 443253680Sdesfetch_ssl_hname_equal(const char *a, size_t alen, const char *b, 444253680Sdes size_t blen) 445253680Sdes{ 446253680Sdes size_t i; 447253680Sdes 448253680Sdes if (alen != blen) 449253680Sdes return (0); 450253680Sdes for (i = 0; i < alen; ++i) { 451253680Sdes if (fetch_ssl_tolower(a[i]) != fetch_ssl_tolower(b[i])) 452253680Sdes return (0); 453253680Sdes } 454253680Sdes return (1); 455253680Sdes} 456253680Sdes 457253680Sdes/* 458253680Sdes * Check if domain label is traditional, meaning that only A-Z, a-z, 0-9 459253680Sdes * and '-' (hyphen) are allowed. Hyphens have to be surrounded by alpha- 460253680Sdes * numeric characters. Double hyphens (like they're found in IDN a-labels 461253680Sdes * 'xn--') are not allowed. Empty labels are invalid. 462253680Sdes */ 463253680Sdesstatic int 464253680Sdesfetch_ssl_is_trad_domain_label(const char *l, size_t len, int wcok) 465253680Sdes{ 466253680Sdes size_t i; 467253680Sdes 468253680Sdes if (!len || l[0] == '-' || l[len-1] == '-') 469253680Sdes return (0); 470253680Sdes for (i = 0; i < len; ++i) { 471253680Sdes if (!isdigit(l[i]) && 472253680Sdes !fetch_ssl_isalpha(l[i]) && 473253680Sdes !(l[i] == '*' && wcok) && 474253680Sdes !(l[i] == '-' && l[i - 1] != '-')) 475253680Sdes return (0); 476253680Sdes } 477253680Sdes return (1); 478253680Sdes} 479253680Sdes 480253680Sdes/* 481253680Sdes * Check if host name consists only of numbers. This might indicate an IP 482253680Sdes * address, which is not a good idea for CN wildcard comparison. 483253680Sdes */ 484253680Sdesstatic int 485253680Sdesfetch_ssl_hname_is_only_numbers(const char *hostname, size_t len) 486253680Sdes{ 487253680Sdes size_t i; 488253680Sdes 489253680Sdes for (i = 0; i < len; ++i) { 490253680Sdes if (!((hostname[i] >= '0' && hostname[i] <= '9') || 491253680Sdes hostname[i] == '.')) 492253680Sdes return (0); 493253680Sdes } 494253680Sdes return (1); 495253680Sdes} 496253680Sdes 497253680Sdes/* 498253680Sdes * Check if the host name h passed matches the pattern passed in m which 499253680Sdes * is usually part of subjectAltName or CN of a certificate presented to 500253680Sdes * the client. This includes wildcard matching. The algorithm is based on 501253680Sdes * RFC6125, sections 6.4.3 and 7.2, which clarifies RFC2818 and RFC3280. 502253680Sdes */ 503253680Sdesstatic int 504253680Sdesfetch_ssl_hname_match(const char *h, size_t hlen, const char *m, 505253680Sdes size_t mlen) 506253680Sdes{ 507253680Sdes int delta, hdotidx, mdot1idx, wcidx; 508253680Sdes const char *hdot, *mdot1, *mdot2; 509253680Sdes const char *wc; /* wildcard */ 510253680Sdes 511253680Sdes if (!(h && *h && m && *m)) 512253680Sdes return (0); 513253680Sdes if ((wc = strnstr(m, "*", mlen)) == NULL) 514253680Sdes return (fetch_ssl_hname_equal(h, hlen, m, mlen)); 515253680Sdes wcidx = wc - m; 516253680Sdes /* hostname should not be just dots and numbers */ 517253680Sdes if (fetch_ssl_hname_is_only_numbers(h, hlen)) 518253680Sdes return (0); 519253680Sdes /* only one wildcard allowed in pattern */ 520253680Sdes if (strnstr(wc + 1, "*", mlen - wcidx - 1) != NULL) 521253680Sdes return (0); 522253680Sdes /* 523253680Sdes * there must be at least two more domain labels and 524253680Sdes * wildcard has to be in the leftmost label (RFC6125) 525253680Sdes */ 526253680Sdes mdot1 = strnstr(m, ".", mlen); 527253680Sdes if (mdot1 == NULL || mdot1 < wc || (mlen - (mdot1 - m)) < 4) 528253680Sdes return (0); 529253680Sdes mdot1idx = mdot1 - m; 530253680Sdes mdot2 = strnstr(mdot1 + 1, ".", mlen - mdot1idx - 1); 531253680Sdes if (mdot2 == NULL || (mlen - (mdot2 - m)) < 2) 532253680Sdes return (0); 533253680Sdes /* hostname must contain a dot and not be the 1st char */ 534253680Sdes hdot = strnstr(h, ".", hlen); 535253680Sdes if (hdot == NULL || hdot == h) 536253680Sdes return (0); 537253680Sdes hdotidx = hdot - h; 538253680Sdes /* 539253680Sdes * host part of hostname must be at least as long as 540253680Sdes * pattern it's supposed to match 541253680Sdes */ 542253680Sdes if (hdotidx < mdot1idx) 543253680Sdes return (0); 544253680Sdes /* 545253680Sdes * don't allow wildcards in non-traditional domain names 546253680Sdes * (IDN, A-label, U-label...) 547253680Sdes */ 548253680Sdes if (!fetch_ssl_is_trad_domain_label(h, hdotidx, 0) || 549253680Sdes !fetch_ssl_is_trad_domain_label(m, mdot1idx, 1)) 550253680Sdes return (0); 551253680Sdes /* match domain part (part after first dot) */ 552253680Sdes if (!fetch_ssl_hname_equal(hdot, hlen - hdotidx, mdot1, 553253680Sdes mlen - mdot1idx)) 554253680Sdes return (0); 555253680Sdes /* match part left of wildcard */ 556253680Sdes if (!fetch_ssl_hname_equal(h, wcidx, m, wcidx)) 557253680Sdes return (0); 558253680Sdes /* match part right of wildcard */ 559253680Sdes delta = mdot1idx - wcidx - 1; 560253680Sdes if (!fetch_ssl_hname_equal(hdot - delta, delta, 561253680Sdes mdot1 - delta, delta)) 562253680Sdes return (0); 563253680Sdes /* all tests succeded, it's a match */ 564253680Sdes return (1); 565253680Sdes} 566253680Sdes 567253680Sdes/* 568253680Sdes * Get numeric host address info - returns NULL if host was not an IP 569253680Sdes * address. The caller is responsible for deallocation using 570253680Sdes * freeaddrinfo(3). 571253680Sdes */ 572253680Sdesstatic struct addrinfo * 573253680Sdesfetch_ssl_get_numeric_addrinfo(const char *hostname, size_t len) 574253680Sdes{ 575253680Sdes struct addrinfo hints, *res; 576253680Sdes char *host; 577253680Sdes 578253680Sdes host = (char *)malloc(len + 1); 579253680Sdes memcpy(host, hostname, len); 580253680Sdes host[len] = '\0'; 581253680Sdes memset(&hints, 0, sizeof(hints)); 582253680Sdes hints.ai_family = PF_UNSPEC; 583253680Sdes hints.ai_socktype = SOCK_STREAM; 584253680Sdes hints.ai_protocol = 0; 585253680Sdes hints.ai_flags = AI_NUMERICHOST; 586253680Sdes /* port is not relevant for this purpose */ 587294194Sdes if (getaddrinfo(host, "443", &hints, &res) != 0) 588294194Sdes res = NULL; 589253680Sdes free(host); 590253680Sdes return res; 591253680Sdes} 592253680Sdes 593253680Sdes/* 594253680Sdes * Compare ip address in addrinfo with address passes. 595253680Sdes */ 596253680Sdesstatic int 597253680Sdesfetch_ssl_ipaddr_match_bin(const struct addrinfo *lhost, const char *rhost, 598253680Sdes size_t rhostlen) 599253680Sdes{ 600253680Sdes const void *left; 601253680Sdes 602253680Sdes if (lhost->ai_family == AF_INET && rhostlen == 4) { 603253680Sdes left = (void *)&((struct sockaddr_in*)(void *) 604253680Sdes lhost->ai_addr)->sin_addr.s_addr; 605253680Sdes#ifdef INET6 606253680Sdes } else if (lhost->ai_family == AF_INET6 && rhostlen == 16) { 607253680Sdes left = (void *)&((struct sockaddr_in6 *)(void *) 608253680Sdes lhost->ai_addr)->sin6_addr; 609253680Sdes#endif 610253680Sdes } else 611253680Sdes return (0); 612253680Sdes return (!memcmp(left, (const void *)rhost, rhostlen) ? 1 : 0); 613253680Sdes} 614253680Sdes 615253680Sdes/* 616253680Sdes * Compare ip address in addrinfo with host passed. If host is not an IP 617253680Sdes * address, comparison will fail. 618253680Sdes */ 619253680Sdesstatic int 620253680Sdesfetch_ssl_ipaddr_match(const struct addrinfo *laddr, const char *r, 621253680Sdes size_t rlen) 622253680Sdes{ 623253680Sdes struct addrinfo *raddr; 624253680Sdes int ret; 625253680Sdes char *rip; 626253680Sdes 627253680Sdes ret = 0; 628253680Sdes if ((raddr = fetch_ssl_get_numeric_addrinfo(r, rlen)) == NULL) 629253680Sdes return 0; /* not a numeric host */ 630253680Sdes 631253680Sdes if (laddr->ai_family == raddr->ai_family) { 632253680Sdes if (laddr->ai_family == AF_INET) { 633253680Sdes rip = (char *)&((struct sockaddr_in *)(void *) 634253680Sdes raddr->ai_addr)->sin_addr.s_addr; 635253680Sdes ret = fetch_ssl_ipaddr_match_bin(laddr, rip, 4); 636253680Sdes#ifdef INET6 637253680Sdes } else if (laddr->ai_family == AF_INET6) { 638253680Sdes rip = (char *)&((struct sockaddr_in6 *)(void *) 639253680Sdes raddr->ai_addr)->sin6_addr; 640253680Sdes ret = fetch_ssl_ipaddr_match_bin(laddr, rip, 16); 641253680Sdes#endif 642253680Sdes } 643253680Sdes 644253680Sdes } 645253680Sdes freeaddrinfo(raddr); 646253680Sdes return (ret); 647253680Sdes} 648253680Sdes 649253680Sdes/* 650253680Sdes * Verify server certificate by subjectAltName. 651253680Sdes */ 652253680Sdesstatic int 653253680Sdesfetch_ssl_verify_altname(STACK_OF(GENERAL_NAME) *altnames, 654253680Sdes const char *host, struct addrinfo *ip) 655253680Sdes{ 656253680Sdes const GENERAL_NAME *name; 657253680Sdes size_t nslen; 658253680Sdes int i; 659253680Sdes const char *ns; 660253680Sdes 661253680Sdes for (i = 0; i < sk_GENERAL_NAME_num(altnames); ++i) { 662253680Sdes#if OPENSSL_VERSION_NUMBER < 0x10000000L 663253680Sdes /* 664253680Sdes * This is a workaround, since the following line causes 665253680Sdes * alignment issues in clang: 666253680Sdes * name = sk_GENERAL_NAME_value(altnames, i); 667253680Sdes * OpenSSL explicitly warns not to use those macros 668253680Sdes * directly, but there isn't much choice (and there 669253680Sdes * shouldn't be any ill side effects) 670253680Sdes */ 671253680Sdes name = (GENERAL_NAME *)SKM_sk_value(void, altnames, i); 672253680Sdes#else 673253680Sdes name = sk_GENERAL_NAME_value(altnames, i); 674253680Sdes#endif 675253680Sdes ns = (const char *)ASN1_STRING_data(name->d.ia5); 676253680Sdes nslen = (size_t)ASN1_STRING_length(name->d.ia5); 677253680Sdes 678253680Sdes if (name->type == GEN_DNS && ip == NULL && 679253680Sdes fetch_ssl_hname_match(host, strlen(host), ns, nslen)) 680253680Sdes return (1); 681253680Sdes else if (name->type == GEN_IPADD && ip != NULL && 682253680Sdes fetch_ssl_ipaddr_match_bin(ip, ns, nslen)) 683253680Sdes return (1); 684253680Sdes } 685253680Sdes return (0); 686253680Sdes} 687253680Sdes 688253680Sdes/* 689253680Sdes * Verify server certificate by CN. 690253680Sdes */ 691253680Sdesstatic int 692253680Sdesfetch_ssl_verify_cn(X509_NAME *subject, const char *host, 693253680Sdes struct addrinfo *ip) 694253680Sdes{ 695253680Sdes ASN1_STRING *namedata; 696253680Sdes X509_NAME_ENTRY *nameentry; 697253680Sdes int cnlen, lastpos, loc, ret; 698253680Sdes unsigned char *cn; 699253680Sdes 700253680Sdes ret = 0; 701253680Sdes lastpos = -1; 702253680Sdes loc = -1; 703253680Sdes cn = NULL; 704253680Sdes /* get most specific CN (last entry in list) and compare */ 705253680Sdes while ((lastpos = X509_NAME_get_index_by_NID(subject, 706253680Sdes NID_commonName, lastpos)) != -1) 707253680Sdes loc = lastpos; 708253680Sdes 709253680Sdes if (loc > -1) { 710253680Sdes nameentry = X509_NAME_get_entry(subject, loc); 711253680Sdes namedata = X509_NAME_ENTRY_get_data(nameentry); 712253680Sdes cnlen = ASN1_STRING_to_UTF8(&cn, namedata); 713253680Sdes if (ip == NULL && 714253680Sdes fetch_ssl_hname_match(host, strlen(host), cn, cnlen)) 715253680Sdes ret = 1; 716253680Sdes else if (ip != NULL && fetch_ssl_ipaddr_match(ip, cn, cnlen)) 717253680Sdes ret = 1; 718253680Sdes OPENSSL_free(cn); 719253680Sdes } 720253680Sdes return (ret); 721253680Sdes} 722253680Sdes 723253680Sdes/* 724253680Sdes * Verify that server certificate subjectAltName/CN matches 725253680Sdes * hostname. First check, if there are alternative subject names. If yes, 726253680Sdes * those have to match. Only if those don't exist it falls back to 727253680Sdes * checking the subject's CN. 728253680Sdes */ 729253680Sdesstatic int 730253680Sdesfetch_ssl_verify_hname(X509 *cert, const char *host) 731253680Sdes{ 732253680Sdes struct addrinfo *ip; 733253680Sdes STACK_OF(GENERAL_NAME) *altnames; 734253680Sdes X509_NAME *subject; 735262560Sdes int ret; 736253680Sdes 737253680Sdes ret = 0; 738253680Sdes ip = fetch_ssl_get_numeric_addrinfo(host, strlen(host)); 739253680Sdes altnames = X509_get_ext_d2i(cert, NID_subject_alt_name, 740253680Sdes NULL, NULL); 741253680Sdes 742253680Sdes if (altnames != NULL) { 743253680Sdes ret = fetch_ssl_verify_altname(altnames, host, ip); 744253680Sdes } else { 745253680Sdes subject = X509_get_subject_name(cert); 746253680Sdes if (subject != NULL) 747253680Sdes ret = fetch_ssl_verify_cn(subject, host, ip); 748253680Sdes } 749253680Sdes 750253680Sdes if (ip != NULL) 751253680Sdes freeaddrinfo(ip); 752253680Sdes if (altnames != NULL) 753253680Sdes GENERAL_NAMES_free(altnames); 754253680Sdes return (ret); 755253680Sdes} 756253680Sdes 757253680Sdes/* 758253680Sdes * Configure transport security layer based on environment. 759253680Sdes */ 760253680Sdesstatic void 761253680Sdesfetch_ssl_setup_transport_layer(SSL_CTX *ctx, int verbose) 762253680Sdes{ 763253680Sdes long ssl_ctx_options; 764253680Sdes 765294194Sdes ssl_ctx_options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_TICKET; 766277060Sdes if (getenv("SSL_ALLOW_SSL3") == NULL) 767253680Sdes ssl_ctx_options |= SSL_OP_NO_SSLv3; 768253680Sdes if (getenv("SSL_NO_TLS1") != NULL) 769253680Sdes ssl_ctx_options |= SSL_OP_NO_TLSv1; 770277060Sdes if (getenv("SSL_NO_TLS1_1") != NULL) 771277060Sdes ssl_ctx_options |= SSL_OP_NO_TLSv1_1; 772277060Sdes if (getenv("SSL_NO_TLS1_2") != NULL) 773277060Sdes ssl_ctx_options |= SSL_OP_NO_TLSv1_2; 774253680Sdes if (verbose) 775262560Sdes fetch_info("SSL options: %lx", ssl_ctx_options); 776253680Sdes SSL_CTX_set_options(ctx, ssl_ctx_options); 777253680Sdes} 778253680Sdes 779253680Sdes 780253680Sdes/* 781253680Sdes * Configure peer verification based on environment. 782253680Sdes */ 783266632Sdes#define LOCAL_CERT_FILE "/usr/local/etc/ssl/cert.pem" 784266632Sdes#define BASE_CERT_FILE "/etc/ssl/cert.pem" 785253680Sdesstatic int 786253680Sdesfetch_ssl_setup_peer_verification(SSL_CTX *ctx, int verbose) 787253680Sdes{ 788253680Sdes X509_LOOKUP *crl_lookup; 789253680Sdes X509_STORE *crl_store; 790253680Sdes const char *ca_cert_file, *ca_cert_path, *crl_file; 791253680Sdes 792253680Sdes if (getenv("SSL_NO_VERIFY_PEER") == NULL) { 793266632Sdes ca_cert_file = getenv("SSL_CA_CERT_FILE"); 794266632Sdes if (ca_cert_file == NULL && 795266632Sdes access(LOCAL_CERT_FILE, R_OK) == 0) 796266632Sdes ca_cert_file = LOCAL_CERT_FILE; 797295843Sdes if (ca_cert_file == NULL && 798295843Sdes access(BASE_CERT_FILE, R_OK) == 0) 799266632Sdes ca_cert_file = BASE_CERT_FILE; 800253680Sdes ca_cert_path = getenv("SSL_CA_CERT_PATH"); 801253680Sdes if (verbose) { 802253680Sdes fetch_info("Peer verification enabled"); 803253680Sdes if (ca_cert_file != NULL) 804253680Sdes fetch_info("Using CA cert file: %s", 805253680Sdes ca_cert_file); 806253680Sdes if (ca_cert_path != NULL) 807253680Sdes fetch_info("Using CA cert path: %s", 808253680Sdes ca_cert_path); 809295843Sdes if (ca_cert_file == NULL && ca_cert_path == NULL) 810295843Sdes fetch_info("Using OpenSSL default " 811295843Sdes "CA cert file and path"); 812253680Sdes } 813253680Sdes SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER, 814253680Sdes fetch_ssl_cb_verify_crt); 815295843Sdes if (ca_cert_file != NULL || ca_cert_path != NULL) 816295843Sdes SSL_CTX_load_verify_locations(ctx, ca_cert_file, 817295843Sdes ca_cert_path); 818295843Sdes else 819295843Sdes SSL_CTX_set_default_verify_paths(ctx); 820253680Sdes if ((crl_file = getenv("SSL_CRL_FILE")) != NULL) { 821253680Sdes if (verbose) 822253680Sdes fetch_info("Using CRL file: %s", crl_file); 823253680Sdes crl_store = SSL_CTX_get_cert_store(ctx); 824253680Sdes crl_lookup = X509_STORE_add_lookup(crl_store, 825253680Sdes X509_LOOKUP_file()); 826253680Sdes if (crl_lookup == NULL || 827253680Sdes !X509_load_crl_file(crl_lookup, crl_file, 828253680Sdes X509_FILETYPE_PEM)) { 829253680Sdes fprintf(stderr, 830253680Sdes "Could not load CRL file %s\n", 831253680Sdes crl_file); 832253680Sdes return (0); 833253680Sdes } 834253680Sdes X509_STORE_set_flags(crl_store, 835253680Sdes X509_V_FLAG_CRL_CHECK | 836253680Sdes X509_V_FLAG_CRL_CHECK_ALL); 837253680Sdes } 838253680Sdes } 839253680Sdes return (1); 840253680Sdes} 841253680Sdes 842253680Sdes/* 843253680Sdes * Configure client certificate based on environment. 844253680Sdes */ 845253680Sdesstatic int 846253680Sdesfetch_ssl_setup_client_certificate(SSL_CTX *ctx, int verbose) 847253680Sdes{ 848253680Sdes const char *client_cert_file, *client_key_file; 849253680Sdes 850253680Sdes if ((client_cert_file = getenv("SSL_CLIENT_CERT_FILE")) != NULL) { 851253680Sdes client_key_file = getenv("SSL_CLIENT_KEY_FILE") != NULL ? 852253680Sdes getenv("SSL_CLIENT_KEY_FILE") : client_cert_file; 853253680Sdes if (verbose) { 854253680Sdes fetch_info("Using client cert file: %s", 855253680Sdes client_cert_file); 856253680Sdes fetch_info("Using client key file: %s", 857253680Sdes client_key_file); 858253680Sdes } 859253680Sdes if (SSL_CTX_use_certificate_chain_file(ctx, 860253680Sdes client_cert_file) != 1) { 861253680Sdes fprintf(stderr, 862253680Sdes "Could not load client certificate %s\n", 863253680Sdes client_cert_file); 864253680Sdes return (0); 865253680Sdes } 866253680Sdes if (SSL_CTX_use_PrivateKey_file(ctx, client_key_file, 867253680Sdes SSL_FILETYPE_PEM) != 1) { 868253680Sdes fprintf(stderr, 869253680Sdes "Could not load client key %s\n", 870253680Sdes client_key_file); 871253680Sdes return (0); 872253680Sdes } 873253680Sdes } 874253680Sdes return (1); 875253680Sdes} 876253680Sdes 877253680Sdes/* 878253680Sdes * Callback for SSL certificate verification, this is called on server 879253680Sdes * cert verification. It takes no decision, but informs the user in case 880253680Sdes * verification failed. 881253680Sdes */ 882253680Sdesint 883253680Sdesfetch_ssl_cb_verify_crt(int verified, X509_STORE_CTX *ctx) 884253680Sdes{ 885253680Sdes X509 *crt; 886253680Sdes X509_NAME *name; 887253680Sdes char *str; 888253680Sdes 889253680Sdes str = NULL; 890253680Sdes if (!verified) { 891253680Sdes if ((crt = X509_STORE_CTX_get_current_cert(ctx)) != NULL && 892253680Sdes (name = X509_get_subject_name(crt)) != NULL) 893253680Sdes str = X509_NAME_oneline(name, 0, 0); 894253680Sdes fprintf(stderr, "Certificate verification failed for %s\n", 895253680Sdes str != NULL ? str : "no relevant certificate"); 896253680Sdes OPENSSL_free(str); 897253680Sdes } 898253680Sdes return (verified); 899253680Sdes} 900253680Sdes 901253680Sdes#endif 902253680Sdes 903253680Sdes/* 90497868Sdes * Enable SSL on a connection. 90597868Sdes */ 90697868Sdesint 907253680Sdesfetch_ssl(conn_t *conn, const struct url *URL, int verbose) 90897868Sdes{ 909214256Semaste#ifdef WITH_SSL 910210568Sdes int ret, ssl_err; 911253680Sdes X509_NAME *name; 912253680Sdes char *str; 91397868Sdes 91497868Sdes /* Init the SSL library and context */ 91597868Sdes if (!SSL_library_init()){ 91697868Sdes fprintf(stderr, "SSL library init failed\n"); 91797868Sdes return (-1); 91897868Sdes } 91997868Sdes 92097868Sdes SSL_load_error_strings(); 92197868Sdes 92297868Sdes conn->ssl_meth = SSLv23_client_method(); 92397868Sdes conn->ssl_ctx = SSL_CTX_new(conn->ssl_meth); 924108579Sdes SSL_CTX_set_mode(conn->ssl_ctx, SSL_MODE_AUTO_RETRY); 92597868Sdes 926253680Sdes fetch_ssl_setup_transport_layer(conn->ssl_ctx, verbose); 927253680Sdes if (!fetch_ssl_setup_peer_verification(conn->ssl_ctx, verbose)) 928253680Sdes return (-1); 929253680Sdes if (!fetch_ssl_setup_client_certificate(conn->ssl_ctx, verbose)) 930253680Sdes return (-1); 931253680Sdes 93297868Sdes conn->ssl = SSL_new(conn->ssl_ctx); 933253680Sdes if (conn->ssl == NULL) { 93497868Sdes fprintf(stderr, "SSL context creation failed\n"); 93597868Sdes return (-1); 93697868Sdes } 93797868Sdes SSL_set_fd(conn->ssl, conn->sd); 938258756Sbdrewery 939258756Sbdrewery#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT) 940258756Sbdrewery if (!SSL_set_tlsext_host_name(conn->ssl, 941258756Sbdrewery __DECONST(struct url *, URL)->host)) { 942258756Sbdrewery fprintf(stderr, 943258756Sbdrewery "TLS server name indication extension failed for host %s\n", 944258756Sbdrewery URL->host); 945258756Sbdrewery return (-1); 946258756Sbdrewery } 947258756Sbdrewery#endif 948210568Sdes while ((ret = SSL_connect(conn->ssl)) == -1) { 949210568Sdes ssl_err = SSL_get_error(conn->ssl, ret); 950210568Sdes if (ssl_err != SSL_ERROR_WANT_READ && 951210568Sdes ssl_err != SSL_ERROR_WANT_WRITE) { 952210568Sdes ERR_print_errors_fp(stderr); 953210568Sdes return (-1); 954210568Sdes } 95597868Sdes } 956253680Sdes conn->ssl_cert = SSL_get_peer_certificate(conn->ssl); 95797868Sdes 958253680Sdes if (conn->ssl_cert == NULL) { 959253680Sdes fprintf(stderr, "No server SSL certificate\n"); 960253680Sdes return (-1); 961253680Sdes } 962253680Sdes 963253680Sdes if (getenv("SSL_NO_VERIFY_HOSTNAME") == NULL) { 964253680Sdes if (verbose) 965253680Sdes fetch_info("Verify hostname"); 966253680Sdes if (!fetch_ssl_verify_hname(conn->ssl_cert, URL->host)) { 967253680Sdes fprintf(stderr, 968253680Sdes "SSL certificate subject doesn't match host %s\n", 969253680Sdes URL->host); 970253680Sdes return (-1); 971253680Sdes } 972253680Sdes } 973253680Sdes 97497868Sdes if (verbose) { 975277060Sdes fetch_info("%s connection established using %s", 976277060Sdes SSL_get_version(conn->ssl), SSL_get_cipher(conn->ssl)); 97797868Sdes name = X509_get_subject_name(conn->ssl_cert); 97897868Sdes str = X509_NAME_oneline(name, 0, 0); 979253680Sdes fetch_info("Certificate subject: %s", str); 980253680Sdes OPENSSL_free(str); 98197868Sdes name = X509_get_issuer_name(conn->ssl_cert); 98297868Sdes str = X509_NAME_oneline(name, 0, 0); 983253680Sdes fetch_info("Certificate issuer: %s", str); 984253680Sdes OPENSSL_free(str); 98597868Sdes } 98697868Sdes 98797868Sdes return (0); 98897891Sdes#else 98997891Sdes (void)conn; 99097891Sdes (void)verbose; 99197891Sdes fprintf(stderr, "SSL support disabled\n"); 99297891Sdes return (-1); 99397891Sdes#endif 99497868Sdes} 99597868Sdes 996210568Sdes#define FETCH_READ_WAIT -2 997210568Sdes#define FETCH_READ_ERROR -1 998210568Sdes#define FETCH_READ_DONE 0 99998117Sdes 1000210568Sdes#ifdef WITH_SSL 1001210568Sdesstatic ssize_t 1002210568Sdesfetch_ssl_read(SSL *ssl, char *buf, size_t len) 1003210568Sdes{ 1004210568Sdes ssize_t rlen; 1005210568Sdes int ssl_err; 1006210568Sdes 1007210568Sdes rlen = SSL_read(ssl, buf, len); 1008210568Sdes if (rlen < 0) { 1009210568Sdes ssl_err = SSL_get_error(ssl, rlen); 1010210568Sdes if (ssl_err == SSL_ERROR_WANT_READ || 1011210568Sdes ssl_err == SSL_ERROR_WANT_WRITE) { 1012210568Sdes return (FETCH_READ_WAIT); 1013210568Sdes } else { 1014210568Sdes ERR_print_errors_fp(stderr); 1015210568Sdes return (FETCH_READ_ERROR); 1016210568Sdes } 1017210568Sdes } 1018210568Sdes return (rlen); 1019210568Sdes} 1020210568Sdes#endif 1021210568Sdes 1022210568Sdesstatic ssize_t 1023210568Sdesfetch_socket_read(int sd, char *buf, size_t len) 1024210568Sdes{ 1025210568Sdes ssize_t rlen; 1026210568Sdes 1027210568Sdes rlen = read(sd, buf, len); 1028210568Sdes if (rlen < 0) { 1029210568Sdes if (errno == EAGAIN || (errno == EINTR && fetchRestartCalls)) 1030210568Sdes return (FETCH_READ_WAIT); 1031210568Sdes else 1032210568Sdes return (FETCH_READ_ERROR); 1033210568Sdes } 1034210568Sdes return (rlen); 1035210568Sdes} 1036210568Sdes 103797868Sdes/* 103897866Sdes * Read a character from a connection w/ timeout 103955557Sdes */ 104097866Sdesssize_t 1041174588Sdesfetch_read(conn_t *conn, char *buf, size_t len) 104255557Sdes{ 1043177447Sdes struct timeval now, timeout, delta; 1044262560Sdes struct pollfd pfd; 1045262560Sdes ssize_t rlen; 1046262560Sdes int deltams; 104790267Sdes 1048234837Sdes if (fetchTimeout > 0) { 104990267Sdes gettimeofday(&timeout, NULL); 105090267Sdes timeout.tv_sec += fetchTimeout; 105155557Sdes } 105290267Sdes 1053262560Sdes deltams = INFTIM; 1054262560Sdes memset(&pfd, 0, sizeof pfd); 1055262560Sdes pfd.fd = conn->sd; 1056262560Sdes pfd.events = POLLIN | POLLERR; 1057230307Sdes 1058262560Sdes for (;;) { 1059230307Sdes /* 1060210568Sdes * The socket is non-blocking. Instead of the canonical 1061262560Sdes * poll() -> read(), we do the following: 1062210568Sdes * 1063210568Sdes * 1) call read() or SSL_read(). 1064262560Sdes * 2) if we received some data, return it. 1065262560Sdes * 3) if an error occurred, return -1. 1066210568Sdes * 4) if read() or SSL_read() signaled EOF, return. 1067210568Sdes * 5) if we did not receive any data but we're not at EOF, 1068262560Sdes * call poll(). 1069210568Sdes * 1070210568Sdes * In the SSL case, this is necessary because if we 1071210568Sdes * receive a close notification, we have to call 1072210568Sdes * SSL_read() one additional time after we've read 1073210568Sdes * everything we received. 1074210568Sdes * 1075210568Sdes * In the non-SSL case, it may improve performance (very 1076210568Sdes * slightly) when reading small amounts of data. 1077210568Sdes */ 1078210568Sdes#ifdef WITH_SSL 1079210568Sdes if (conn->ssl != NULL) 1080210568Sdes rlen = fetch_ssl_read(conn->ssl, buf, len); 1081210568Sdes else 1082210568Sdes#endif 1083210568Sdes rlen = fetch_socket_read(conn->sd, buf, len); 1084262560Sdes if (rlen >= 0) { 1085210568Sdes break; 1086210568Sdes } else if (rlen == FETCH_READ_ERROR) { 1087262560Sdes fetch_syserr(); 1088210568Sdes return (-1); 1089210568Sdes } 1090210568Sdes // assert(rlen == FETCH_READ_WAIT); 1091262560Sdes if (fetchTimeout > 0) { 1092262560Sdes gettimeofday(&now, NULL); 1093262560Sdes if (!timercmp(&timeout, &now, >)) { 1094262560Sdes errno = ETIMEDOUT; 1095174588Sdes fetch_syserr(); 109690267Sdes return (-1); 109790267Sdes } 1098262560Sdes timersub(&timeout, &now, &delta); 1099262560Sdes deltams = delta.tv_sec * 1000 + 1100262560Sdes delta.tv_usec / 1000;; 110190267Sdes } 1102262560Sdes errno = 0; 1103262560Sdes pfd.revents = 0; 1104262560Sdes if (poll(&pfd, 1, deltams) < 0) { 1105262560Sdes if (errno == EINTR && fetchRestartCalls) 1106262560Sdes continue; 1107262560Sdes fetch_syserr(); 1108262560Sdes return (-1); 1109262560Sdes } 111097866Sdes } 1111262560Sdes return (rlen); 111297866Sdes} 111397866Sdes 111498117Sdes 111597866Sdes/* 111697866Sdes * Read a line of text from a connection w/ timeout 111797866Sdes */ 111897866Sdes#define MIN_BUF_SIZE 1024 111997866Sdes 112097866Sdesint 1121174588Sdesfetch_getln(conn_t *conn) 112297866Sdes{ 112397866Sdes char *tmp; 112497866Sdes size_t tmpsize; 1125106186Sdes ssize_t len; 112697866Sdes char c; 112797866Sdes 112897866Sdes if (conn->buf == NULL) { 112997866Sdes if ((conn->buf = malloc(MIN_BUF_SIZE)) == NULL) { 113097866Sdes errno = ENOMEM; 113197866Sdes return (-1); 113297866Sdes } 113397866Sdes conn->bufsize = MIN_BUF_SIZE; 113497866Sdes } 113597866Sdes 113697866Sdes conn->buf[0] = '\0'; 113797866Sdes conn->buflen = 0; 113897866Sdes 113997866Sdes do { 1140174588Sdes len = fetch_read(conn, &c, 1); 1141106186Sdes if (len == -1) 114297866Sdes return (-1); 1143106186Sdes if (len == 0) 1144106137Sobrien break; 114597856Sdes conn->buf[conn->buflen++] = c; 114697856Sdes if (conn->buflen == conn->bufsize) { 114797856Sdes tmp = conn->buf; 114897856Sdes tmpsize = conn->bufsize * 2 + 1; 114997856Sdes if ((tmp = realloc(tmp, tmpsize)) == NULL) { 115090267Sdes errno = ENOMEM; 115190267Sdes return (-1); 115290267Sdes } 115397856Sdes conn->buf = tmp; 115497856Sdes conn->bufsize = tmpsize; 115590267Sdes } 115690267Sdes } while (c != '\n'); 115790267Sdes 115897856Sdes conn->buf[conn->buflen] = '\0'; 115997856Sdes DEBUG(fprintf(stderr, "<<< %s", conn->buf)); 116090267Sdes return (0); 116155557Sdes} 116255557Sdes 116355557Sdes 116462981Sdes/* 116597866Sdes * Write to a connection w/ timeout 116662981Sdes */ 116797866Sdesssize_t 1168174588Sdesfetch_write(conn_t *conn, const char *buf, size_t len) 116997866Sdes{ 1170106175Simp struct iovec iov; 1171106175Simp 1172106175Simp iov.iov_base = __DECONST(char *, buf); 1173106175Simp iov.iov_len = len; 1174174588Sdes return fetch_writev(conn, &iov, 1); 1175106175Simp} 1176106175Simp 1177106175Simp/* 1178106175Simp * Write a vector to a connection w/ timeout 1179106175Simp * Note: can modify the iovec. 1180106175Simp */ 1181106175Simpssize_t 1182174588Sdesfetch_writev(conn_t *conn, struct iovec *iov, int iovcnt) 1183106175Simp{ 1184177447Sdes struct timeval now, timeout, delta; 1185262560Sdes struct pollfd pfd; 118697866Sdes ssize_t wlen, total; 1187262560Sdes int deltams; 118897866Sdes 1189262560Sdes memset(&pfd, 0, sizeof pfd); 119097866Sdes if (fetchTimeout) { 1191262560Sdes pfd.fd = conn->sd; 1192262560Sdes pfd.events = POLLOUT | POLLERR; 119397866Sdes gettimeofday(&timeout, NULL); 119497866Sdes timeout.tv_sec += fetchTimeout; 119597866Sdes } 119697866Sdes 1197106175Simp total = 0; 1198106175Simp while (iovcnt > 0) { 1199262560Sdes while (fetchTimeout && pfd.revents == 0) { 120097866Sdes gettimeofday(&now, NULL); 1201262560Sdes if (!timercmp(&timeout, &now, >)) { 120297866Sdes errno = ETIMEDOUT; 1203174588Sdes fetch_syserr(); 120497866Sdes return (-1); 120597866Sdes } 1206262560Sdes timersub(&timeout, &now, &delta); 1207262560Sdes deltams = delta.tv_sec * 1000 + 1208262560Sdes delta.tv_usec / 1000; 120997866Sdes errno = 0; 1210262560Sdes pfd.revents = 0; 1211262560Sdes if (poll(&pfd, 1, deltams) < 0) { 1212268900Sbapt /* POSIX compliance */ 1213268900Sbapt if (errno == EAGAIN) 1214268900Sbapt continue; 121597866Sdes if (errno == EINTR && fetchRestartCalls) 121697866Sdes continue; 121797866Sdes return (-1); 121897866Sdes } 121997866Sdes } 122097866Sdes errno = 0; 122197891Sdes#ifdef WITH_SSL 122297866Sdes if (conn->ssl != NULL) 1223106175Simp wlen = SSL_write(conn->ssl, 1224106175Simp iov->iov_base, iov->iov_len); 122597866Sdes else 122697891Sdes#endif 1227106175Simp wlen = writev(conn->sd, iov, iovcnt); 1228106175Simp if (wlen == 0) { 122997866Sdes /* we consider a short write a failure */ 1230210568Sdes /* XXX perhaps we shouldn't in the SSL case */ 1231106175Simp errno = EPIPE; 1232174588Sdes fetch_syserr(); 123397866Sdes return (-1); 1234106175Simp } 123597866Sdes if (wlen < 0) { 123697866Sdes if (errno == EINTR && fetchRestartCalls) 123797866Sdes continue; 123897866Sdes return (-1); 123997866Sdes } 124097866Sdes total += wlen; 1241106175Simp while (iovcnt > 0 && wlen >= (ssize_t)iov->iov_len) { 1242106175Simp wlen -= iov->iov_len; 1243106175Simp iov++; 1244106175Simp iovcnt--; 1245106175Simp } 1246106175Simp if (iovcnt > 0) { 1247106175Simp iov->iov_len -= wlen; 1248106175Simp iov->iov_base = __DECONST(char *, iov->iov_base) + wlen; 1249106175Simp } 125097866Sdes } 125197866Sdes return (total); 125297866Sdes} 125397866Sdes 125498117Sdes 125597866Sdes/* 125697866Sdes * Write a line of text to a connection w/ timeout 125797866Sdes */ 125862981Sdesint 1259174588Sdesfetch_putln(conn_t *conn, const char *str, size_t len) 126062981Sdes{ 1261106175Simp struct iovec iov[2]; 1262106205Sdes int ret; 126398748Sdes 126498748Sdes DEBUG(fprintf(stderr, ">>> %s\n", str)); 1265106175Simp iov[0].iov_base = __DECONST(char *, str); 1266106175Simp iov[0].iov_len = len; 1267106175Simp iov[1].iov_base = __DECONST(char *, ENDL); 1268109967Sdes iov[1].iov_len = sizeof(ENDL); 1269106205Sdes if (len == 0) 1270174588Sdes ret = fetch_writev(conn, &iov[1], 1); 1271106205Sdes else 1272174588Sdes ret = fetch_writev(conn, iov, 2); 1273106205Sdes if (ret == -1) 127490267Sdes return (-1); 127590267Sdes return (0); 127662981Sdes} 127762981Sdes 127862981Sdes 127997856Sdes/* 128097856Sdes * Close connection 128197856Sdes */ 128297856Sdesint 1283174588Sdesfetch_close(conn_t *conn) 128497856Sdes{ 128597856Sdes int ret; 128697856Sdes 128798117Sdes if (--conn->ref > 0) 128898117Sdes return (0); 1289253680Sdes#ifdef WITH_SSL 1290253680Sdes if (conn->ssl) { 1291253680Sdes SSL_shutdown(conn->ssl); 1292253680Sdes SSL_set_connect_state(conn->ssl); 1293253680Sdes SSL_free(conn->ssl); 1294253680Sdes conn->ssl = NULL; 1295253680Sdes } 1296253680Sdes if (conn->ssl_ctx) { 1297253680Sdes SSL_CTX_free(conn->ssl_ctx); 1298253680Sdes conn->ssl_ctx = NULL; 1299253680Sdes } 1300253680Sdes if (conn->ssl_cert) { 1301253680Sdes X509_free(conn->ssl_cert); 1302253680Sdes conn->ssl_cert = NULL; 1303253680Sdes } 1304253680Sdes#endif 130597856Sdes ret = close(conn->sd); 1306141970Sdes free(conn->buf); 130797856Sdes free(conn); 130897856Sdes return (ret); 130997856Sdes} 131097856Sdes 131197856Sdes 131241989Sdes/*** Directory-related utility functions *************************************/ 131341989Sdes 131441989Sdesint 1315174588Sdesfetch_add_entry(struct url_ent **p, int *size, int *len, 131690267Sdes const char *name, struct url_stat *us) 131741989Sdes{ 131890267Sdes struct url_ent *tmp; 131941989Sdes 132090267Sdes if (*p == NULL) { 132190268Sdes *size = 0; 132290267Sdes *len = 0; 132341989Sdes } 132441989Sdes 132590267Sdes if (*len >= *size - 1) { 1326109967Sdes tmp = realloc(*p, (*size * 2 + 1) * sizeof(**p)); 132790267Sdes if (tmp == NULL) { 132890267Sdes errno = ENOMEM; 1329174588Sdes fetch_syserr(); 133090267Sdes return (-1); 133190267Sdes } 133290268Sdes *size = (*size * 2 + 1); 133390267Sdes *p = tmp; 133490267Sdes } 133541989Sdes 133690267Sdes tmp = *p + *len; 133790267Sdes snprintf(tmp->name, PATH_MAX, "%s", name); 1338176105Sdes memcpy(&tmp->stat, us, sizeof(*us)); 133941989Sdes 134090267Sdes (*len)++; 134190267Sdes (++tmp)->name[0] = 0; 134290267Sdes 134390267Sdes return (0); 134441989Sdes} 1345109695Sdes 1346109695Sdes 1347109695Sdes/*** Authentication-related utility functions ********************************/ 1348109695Sdes 1349109695Sdesstatic const char * 1350174588Sdesfetch_read_word(FILE *f) 1351109695Sdes{ 1352109695Sdes static char word[1024]; 1353109695Sdes 1354178234Scperciva if (fscanf(f, " %1023s ", word) != 1) 1355109695Sdes return (NULL); 1356109695Sdes return (word); 1357109695Sdes} 1358109695Sdes 1359315904Sdesstatic int 1360315904Sdesfetch_netrc_open(void) 1361109695Sdes{ 1362315904Sdes const char *p; 1363109695Sdes char fn[PATH_MAX]; 1364109695Sdes 1365109695Sdes if ((p = getenv("NETRC")) != NULL) { 1366109967Sdes if (snprintf(fn, sizeof(fn), "%s", p) >= (int)sizeof(fn)) { 1367174588Sdes fetch_info("$NETRC specifies a file name " 1368109695Sdes "longer than PATH_MAX"); 1369109695Sdes return (-1); 1370109695Sdes } 1371109695Sdes } else { 1372109695Sdes if ((p = getenv("HOME")) != NULL) { 1373109695Sdes struct passwd *pwd; 1374109695Sdes 1375109695Sdes if ((pwd = getpwuid(getuid())) == NULL || 1376109695Sdes (p = pwd->pw_dir) == NULL) 1377109695Sdes return (-1); 1378109695Sdes } 1379109967Sdes if (snprintf(fn, sizeof(fn), "%s/.netrc", p) >= (int)sizeof(fn)) 1380109695Sdes return (-1); 1381109695Sdes } 1382109695Sdes 1383315904Sdes return (open(fn, O_RDONLY)); 1384315904Sdes} 1385315904Sdes 1386315904Sdes/* 1387315904Sdes * Get authentication data for a URL from .netrc 1388315904Sdes */ 1389315904Sdesint 1390315904Sdesfetch_netrc_auth(struct url *url) 1391315904Sdes{ 1392315904Sdes const char *word; 1393315904Sdes FILE *f; 1394315904Sdes 1395315904Sdes if (url->netrcfd == -2) 1396315904Sdes url->netrcfd = fetch_netrc_open(); 1397315904Sdes if (url->netrcfd < 0) 1398109695Sdes return (-1); 1399315904Sdes if ((f = fdopen(url->netrcfd, "r")) == NULL) 1400315904Sdes return (-1); 1401315904Sdes rewind(f); 1402174588Sdes while ((word = fetch_read_word(f)) != NULL) { 1403109695Sdes if (strcmp(word, "default") == 0) { 1404174588Sdes DEBUG(fetch_info("Using default .netrc settings")); 1405109695Sdes break; 1406109695Sdes } 1407109695Sdes if (strcmp(word, "machine") == 0 && 1408174588Sdes (word = fetch_read_word(f)) != NULL && 1409109695Sdes strcasecmp(word, url->host) == 0) { 1410174588Sdes DEBUG(fetch_info("Using .netrc settings for %s", word)); 1411109695Sdes break; 1412109695Sdes } 1413109695Sdes } 1414109695Sdes if (word == NULL) 1415109695Sdes goto ferr; 1416174588Sdes while ((word = fetch_read_word(f)) != NULL) { 1417109695Sdes if (strcmp(word, "login") == 0) { 1418174588Sdes if ((word = fetch_read_word(f)) == NULL) 1419109695Sdes goto ferr; 1420109967Sdes if (snprintf(url->user, sizeof(url->user), 1421109960Sjwd "%s", word) > (int)sizeof(url->user)) { 1422174588Sdes fetch_info("login name in .netrc is too long"); 1423109695Sdes url->user[0] = '\0'; 1424109695Sdes } 1425109695Sdes } else if (strcmp(word, "password") == 0) { 1426174588Sdes if ((word = fetch_read_word(f)) == NULL) 1427109695Sdes goto ferr; 1428109967Sdes if (snprintf(url->pwd, sizeof(url->pwd), 1429109960Sjwd "%s", word) > (int)sizeof(url->pwd)) { 1430174588Sdes fetch_info("password in .netrc is too long"); 1431109695Sdes url->pwd[0] = '\0'; 1432109695Sdes } 1433109695Sdes } else if (strcmp(word, "account") == 0) { 1434174588Sdes if ((word = fetch_read_word(f)) == NULL) 1435109695Sdes goto ferr; 1436109695Sdes /* XXX not supported! */ 1437109695Sdes } else { 1438109695Sdes break; 1439109695Sdes } 1440109695Sdes } 1441109695Sdes fclose(f); 1442109695Sdes return (0); 1443109695Sdes ferr: 1444109695Sdes fclose(f); 1445109695Sdes return (-1); 1446109695Sdes} 1447174752Sdes 1448174752Sdes/* 1449174752Sdes * The no_proxy environment variable specifies a set of domains for 1450174752Sdes * which the proxy should not be consulted; the contents is a comma-, 1451174752Sdes * or space-separated list of domain names. A single asterisk will 1452174752Sdes * override all proxy variables and no transactions will be proxied 1453174752Sdes * (for compatability with lynx and curl, see the discussion at 1454174752Sdes * <http://curl.haxx.se/mail/archive_pre_oct_99/0009.html>). 1455174752Sdes */ 1456174752Sdesint 1457174752Sdesfetch_no_proxy_match(const char *host) 1458174752Sdes{ 1459174752Sdes const char *no_proxy, *p, *q; 1460174752Sdes size_t h_len, d_len; 1461174752Sdes 1462174752Sdes if ((no_proxy = getenv("NO_PROXY")) == NULL && 1463174752Sdes (no_proxy = getenv("no_proxy")) == NULL) 1464174752Sdes return (0); 1465174752Sdes 1466174752Sdes /* asterisk matches any hostname */ 1467174752Sdes if (strcmp(no_proxy, "*") == 0) 1468174752Sdes return (1); 1469174752Sdes 1470174752Sdes h_len = strlen(host); 1471174752Sdes p = no_proxy; 1472174752Sdes do { 1473174752Sdes /* position p at the beginning of a domain suffix */ 1474174761Sdes while (*p == ',' || isspace((unsigned char)*p)) 1475174752Sdes p++; 1476174752Sdes 1477174752Sdes /* position q at the first separator character */ 1478174752Sdes for (q = p; *q; ++q) 1479174761Sdes if (*q == ',' || isspace((unsigned char)*q)) 1480174752Sdes break; 1481174752Sdes 1482174752Sdes d_len = q - p; 1483198339Sfabient if (d_len > 0 && h_len >= d_len && 1484174752Sdes strncasecmp(host + h_len - d_len, 1485174752Sdes p, d_len) == 0) { 1486174752Sdes /* domain name matches */ 1487174752Sdes return (1); 1488174752Sdes } 1489174752Sdes 1490174752Sdes p = q + 1; 1491174752Sdes } while (*q); 1492174752Sdes 1493174752Sdes return (0); 1494174752Sdes} 1495