1/*-
2 * Copyright (c) 1998-2016 Dag-Erling Sm��rgrav
3 * Copyright (c) 2013 Michael Gmelin <freebsd@grem.de>
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 *    notice, this list of conditions and the following disclaimer
11 *    in this position and unchanged.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 * 3. The name of the author may not be used to endorse or promote products
16 *    derived from this software without specific prior written permission
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30#include <sys/cdefs.h>
31__FBSDID("$FreeBSD: stable/11/lib/libfetch/common.c 339250 2018-10-09 10:49:19Z des $");
32
33#include <sys/param.h>
34#include <sys/socket.h>
35#include <sys/time.h>
36#include <sys/uio.h>
37
38#include <netinet/in.h>
39
40#include <ctype.h>
41#include <errno.h>
42#include <fcntl.h>
43#include <netdb.h>
44#include <poll.h>
45#include <pwd.h>
46#include <stdarg.h>
47#include <stdlib.h>
48#include <stdio.h>
49#include <string.h>
50#include <unistd.h>
51
52#ifdef WITH_SSL
53#include <openssl/x509v3.h>
54#endif
55
56#include "fetch.h"
57#include "common.h"
58
59
60/*** Local data **************************************************************/
61
62/*
63 * Error messages for resolver errors
64 */
65static struct fetcherr netdb_errlist[] = {
66#ifdef EAI_NODATA
67	{ EAI_NODATA,	FETCH_RESOLV,	"Host not found" },
68#endif
69	{ EAI_AGAIN,	FETCH_TEMP,	"Transient resolver failure" },
70	{ EAI_FAIL,	FETCH_RESOLV,	"Non-recoverable resolver failure" },
71	{ EAI_NONAME,	FETCH_RESOLV,	"No address record" },
72	{ -1,		FETCH_UNKNOWN,	"Unknown resolver error" }
73};
74
75/* End-of-Line */
76static const char ENDL[2] = "\r\n";
77
78
79/*** Error-reporting functions ***********************************************/
80
81/*
82 * Map error code to string
83 */
84static struct fetcherr *
85fetch_finderr(struct fetcherr *p, int e)
86{
87	while (p->num != -1 && p->num != e)
88		p++;
89	return (p);
90}
91
92/*
93 * Set error code
94 */
95void
96fetch_seterr(struct fetcherr *p, int e)
97{
98	p = fetch_finderr(p, e);
99	fetchLastErrCode = p->cat;
100	snprintf(fetchLastErrString, MAXERRSTRING, "%s", p->string);
101}
102
103/*
104 * Set error code according to errno
105 */
106void
107fetch_syserr(void)
108{
109	switch (errno) {
110	case 0:
111		fetchLastErrCode = FETCH_OK;
112		break;
113	case EPERM:
114	case EACCES:
115	case EROFS:
116	case EAUTH:
117	case ENEEDAUTH:
118		fetchLastErrCode = FETCH_AUTH;
119		break;
120	case ENOENT:
121	case EISDIR: /* XXX */
122		fetchLastErrCode = FETCH_UNAVAIL;
123		break;
124	case ENOMEM:
125		fetchLastErrCode = FETCH_MEMORY;
126		break;
127	case EBUSY:
128	case EAGAIN:
129		fetchLastErrCode = FETCH_TEMP;
130		break;
131	case EEXIST:
132		fetchLastErrCode = FETCH_EXISTS;
133		break;
134	case ENOSPC:
135		fetchLastErrCode = FETCH_FULL;
136		break;
137	case EADDRINUSE:
138	case EADDRNOTAVAIL:
139	case ENETDOWN:
140	case ENETUNREACH:
141	case ENETRESET:
142	case EHOSTUNREACH:
143		fetchLastErrCode = FETCH_NETWORK;
144		break;
145	case ECONNABORTED:
146	case ECONNRESET:
147		fetchLastErrCode = FETCH_ABORT;
148		break;
149	case ETIMEDOUT:
150		fetchLastErrCode = FETCH_TIMEOUT;
151		break;
152	case ECONNREFUSED:
153	case EHOSTDOWN:
154		fetchLastErrCode = FETCH_DOWN;
155		break;
156	default:
157		fetchLastErrCode = FETCH_UNKNOWN;
158	}
159	snprintf(fetchLastErrString, MAXERRSTRING, "%s", strerror(errno));
160}
161
162
163/*
164 * Emit status message
165 */
166void
167fetch_info(const char *fmt, ...)
168{
169	va_list ap;
170
171	va_start(ap, fmt);
172	vfprintf(stderr, fmt, ap);
173	va_end(ap);
174	fputc('\n', stderr);
175}
176
177
178/*** Network-related utility functions ***************************************/
179
180/*
181 * Return the default port for a scheme
182 */
183int
184fetch_default_port(const char *scheme)
185{
186	struct servent *se;
187
188	if ((se = getservbyname(scheme, "tcp")) != NULL)
189		return (ntohs(se->s_port));
190	if (strcasecmp(scheme, SCHEME_FTP) == 0)
191		return (FTP_DEFAULT_PORT);
192	if (strcasecmp(scheme, SCHEME_HTTP) == 0)
193		return (HTTP_DEFAULT_PORT);
194	return (0);
195}
196
197/*
198 * Return the default proxy port for a scheme
199 */
200int
201fetch_default_proxy_port(const char *scheme)
202{
203	if (strcasecmp(scheme, SCHEME_FTP) == 0)
204		return (FTP_DEFAULT_PROXY_PORT);
205	if (strcasecmp(scheme, SCHEME_HTTP) == 0)
206		return (HTTP_DEFAULT_PROXY_PORT);
207	return (0);
208}
209
210
211/*
212 * Create a connection for an existing descriptor.
213 */
214conn_t *
215fetch_reopen(int sd)
216{
217	conn_t *conn;
218	int opt = 1;
219
220	/* allocate and fill connection structure */
221	if ((conn = calloc(1, sizeof(*conn))) == NULL)
222		return (NULL);
223	fcntl(sd, F_SETFD, FD_CLOEXEC);
224	setsockopt(sd, SOL_SOCKET, SO_NOSIGPIPE, &opt, sizeof opt);
225	conn->sd = sd;
226	++conn->ref;
227	return (conn);
228}
229
230
231/*
232 * Bump a connection's reference count.
233 */
234conn_t *
235fetch_ref(conn_t *conn)
236{
237
238	++conn->ref;
239	return (conn);
240}
241
242
243/*
244 * Resolve an address
245 */
246struct addrinfo *
247fetch_resolve(const char *addr, int port, int af)
248{
249	char hbuf[256], sbuf[8];
250	struct addrinfo hints, *res;
251	const char *hb, *he, *sep;
252	const char *host, *service;
253	int err, len;
254
255	/* first, check for a bracketed IPv6 address */
256	if (*addr == '[') {
257		hb = addr + 1;
258		if ((sep = strchr(hb, ']')) == NULL) {
259			errno = EINVAL;
260			goto syserr;
261		}
262		he = sep++;
263	} else {
264		hb = addr;
265		sep = strchrnul(hb, ':');
266		he = sep;
267	}
268
269	/* see if we need to copy the host name */
270	if (*he != '\0') {
271		len = snprintf(hbuf, sizeof(hbuf),
272		    "%.*s", (int)(he - hb), hb);
273		if (len < 0)
274			goto syserr;
275		if (len >= (int)sizeof(hbuf)) {
276			errno = ENAMETOOLONG;
277			goto syserr;
278		}
279		host = hbuf;
280	} else {
281		host = hb;
282	}
283
284	/* was it followed by a service name? */
285	if (*sep == '\0' && port != 0) {
286		if (port < 1 || port > 65535) {
287			errno = EINVAL;
288			goto syserr;
289		}
290		if (snprintf(sbuf, sizeof(sbuf), "%d", port) < 0)
291			goto syserr;
292		service = sbuf;
293	} else if (*sep != '\0') {
294		service = sep + 1;
295	} else {
296		service = NULL;
297	}
298
299	/* resolve */
300	memset(&hints, 0, sizeof(hints));
301	hints.ai_family = af;
302	hints.ai_socktype = SOCK_STREAM;
303	hints.ai_flags = AI_ADDRCONFIG;
304	if ((err = getaddrinfo(host, service, &hints, &res)) != 0) {
305		netdb_seterr(err);
306		return (NULL);
307	}
308	return (res);
309syserr:
310	fetch_syserr();
311	return (NULL);
312}
313
314
315
316/*
317 * Bind a socket to a specific local address
318 */
319int
320fetch_bind(int sd, int af, const char *addr)
321{
322	struct addrinfo *cliai, *ai;
323	int err;
324
325	if ((cliai = fetch_resolve(addr, 0, af)) == NULL)
326		return (-1);
327	for (ai = cliai; ai != NULL; ai = ai->ai_next)
328		if ((err = bind(sd, ai->ai_addr, ai->ai_addrlen)) == 0)
329			break;
330	if (err != 0)
331		fetch_syserr();
332	freeaddrinfo(cliai);
333	return (err == 0 ? 0 : -1);
334}
335
336
337/*
338 * Establish a TCP connection to the specified port on the specified host.
339 */
340conn_t *
341fetch_connect(const char *host, int port, int af, int verbose)
342{
343	struct addrinfo *cais = NULL, *sais = NULL, *cai, *sai;
344	const char *bindaddr;
345	conn_t *conn = NULL;
346	int err = 0, sd = -1;
347
348	DEBUGF("---> %s:%d\n", host, port);
349
350	/* resolve server address */
351	if (verbose)
352		fetch_info("resolving server address: %s:%d", host, port);
353	if ((sais = fetch_resolve(host, port, af)) == NULL)
354		goto fail;
355
356	/* resolve client address */
357	bindaddr = getenv("FETCH_BIND_ADDRESS");
358	if (bindaddr != NULL && *bindaddr != '\0') {
359		if (verbose)
360			fetch_info("resolving client address: %s", bindaddr);
361		if ((cais = fetch_resolve(bindaddr, 0, af)) == NULL)
362			goto fail;
363	}
364
365	/* try each server address in turn */
366	for (err = 0, sai = sais; sai != NULL; sai = sai->ai_next) {
367		/* open socket */
368		if ((sd = socket(sai->ai_family, SOCK_STREAM, 0)) < 0)
369			goto syserr;
370		/* attempt to bind to client address */
371		for (err = 0, cai = cais; cai != NULL; cai = cai->ai_next) {
372			if (cai->ai_family != sai->ai_family)
373				continue;
374			if ((err = bind(sd, cai->ai_addr, cai->ai_addrlen)) == 0)
375				break;
376		}
377		if (err != 0) {
378			if (verbose)
379				fetch_info("failed to bind to %s", bindaddr);
380			goto syserr;
381		}
382		/* attempt to connect to server address */
383		if ((err = connect(sd, sai->ai_addr, sai->ai_addrlen)) == 0)
384			break;
385		/* clean up before next attempt */
386		close(sd);
387		sd = -1;
388	}
389	if (err != 0) {
390		if (verbose)
391			fetch_info("failed to connect to %s:%d", host, port);
392		goto syserr;
393	}
394
395	if ((conn = fetch_reopen(sd)) == NULL)
396		goto syserr;
397	if (cais != NULL)
398		freeaddrinfo(cais);
399	if (sais != NULL)
400		freeaddrinfo(sais);
401	return (conn);
402syserr:
403	fetch_syserr();
404	goto fail;
405fail:
406	if (sd >= 0)
407		close(sd);
408	if (cais != NULL)
409		freeaddrinfo(cais);
410	if (sais != NULL)
411		freeaddrinfo(sais);
412	return (NULL);
413}
414
415#ifdef WITH_SSL
416/*
417 * Convert characters A-Z to lowercase (intentionally avoid any locale
418 * specific conversions).
419 */
420static char
421fetch_ssl_tolower(char in)
422{
423	if (in >= 'A' && in <= 'Z')
424		return (in + 32);
425	else
426		return (in);
427}
428
429/*
430 * isalpha implementation that intentionally avoids any locale specific
431 * conversions.
432 */
433static int
434fetch_ssl_isalpha(char in)
435{
436	return ((in >= 'A' && in <= 'Z') || (in >= 'a' && in <= 'z'));
437}
438
439/*
440 * Check if passed hostnames a and b are equal.
441 */
442static int
443fetch_ssl_hname_equal(const char *a, size_t alen, const char *b,
444    size_t blen)
445{
446	size_t i;
447
448	if (alen != blen)
449		return (0);
450	for (i = 0; i < alen; ++i) {
451		if (fetch_ssl_tolower(a[i]) != fetch_ssl_tolower(b[i]))
452			return (0);
453	}
454	return (1);
455}
456
457/*
458 * Check if domain label is traditional, meaning that only A-Z, a-z, 0-9
459 * and '-' (hyphen) are allowed. Hyphens have to be surrounded by alpha-
460 * numeric characters. Double hyphens (like they're found in IDN a-labels
461 * 'xn--') are not allowed. Empty labels are invalid.
462 */
463static int
464fetch_ssl_is_trad_domain_label(const char *l, size_t len, int wcok)
465{
466	size_t i;
467
468	if (!len || l[0] == '-' || l[len-1] == '-')
469		return (0);
470	for (i = 0; i < len; ++i) {
471		if (!isdigit(l[i]) &&
472		    !fetch_ssl_isalpha(l[i]) &&
473		    !(l[i] == '*' && wcok) &&
474		    !(l[i] == '-' && l[i - 1] != '-'))
475			return (0);
476	}
477	return (1);
478}
479
480/*
481 * Check if host name consists only of numbers. This might indicate an IP
482 * address, which is not a good idea for CN wildcard comparison.
483 */
484static int
485fetch_ssl_hname_is_only_numbers(const char *hostname, size_t len)
486{
487	size_t i;
488
489	for (i = 0; i < len; ++i) {
490		if (!((hostname[i] >= '0' && hostname[i] <= '9') ||
491		    hostname[i] == '.'))
492			return (0);
493	}
494	return (1);
495}
496
497/*
498 * Check if the host name h passed matches the pattern passed in m which
499 * is usually part of subjectAltName or CN of a certificate presented to
500 * the client. This includes wildcard matching. The algorithm is based on
501 * RFC6125, sections 6.4.3 and 7.2, which clarifies RFC2818 and RFC3280.
502 */
503static int
504fetch_ssl_hname_match(const char *h, size_t hlen, const char *m,
505    size_t mlen)
506{
507	int delta, hdotidx, mdot1idx, wcidx;
508	const char *hdot, *mdot1, *mdot2;
509	const char *wc; /* wildcard */
510
511	if (!(h && *h && m && *m))
512		return (0);
513	if ((wc = strnstr(m, "*", mlen)) == NULL)
514		return (fetch_ssl_hname_equal(h, hlen, m, mlen));
515	wcidx = wc - m;
516	/* hostname should not be just dots and numbers */
517	if (fetch_ssl_hname_is_only_numbers(h, hlen))
518		return (0);
519	/* only one wildcard allowed in pattern */
520	if (strnstr(wc + 1, "*", mlen - wcidx - 1) != NULL)
521		return (0);
522	/*
523	 * there must be at least two more domain labels and
524	 * wildcard has to be in the leftmost label (RFC6125)
525	 */
526	mdot1 = strnstr(m, ".", mlen);
527	if (mdot1 == NULL || mdot1 < wc || (mlen - (mdot1 - m)) < 4)
528		return (0);
529	mdot1idx = mdot1 - m;
530	mdot2 = strnstr(mdot1 + 1, ".", mlen - mdot1idx - 1);
531	if (mdot2 == NULL || (mlen - (mdot2 - m)) < 2)
532		return (0);
533	/* hostname must contain a dot and not be the 1st char */
534	hdot = strnstr(h, ".", hlen);
535	if (hdot == NULL || hdot == h)
536		return (0);
537	hdotidx = hdot - h;
538	/*
539	 * host part of hostname must be at least as long as
540	 * pattern it's supposed to match
541	 */
542	if (hdotidx < mdot1idx)
543		return (0);
544	/*
545	 * don't allow wildcards in non-traditional domain names
546	 * (IDN, A-label, U-label...)
547	 */
548	if (!fetch_ssl_is_trad_domain_label(h, hdotidx, 0) ||
549	    !fetch_ssl_is_trad_domain_label(m, mdot1idx, 1))
550		return (0);
551	/* match domain part (part after first dot) */
552	if (!fetch_ssl_hname_equal(hdot, hlen - hdotidx, mdot1,
553	    mlen - mdot1idx))
554		return (0);
555	/* match part left of wildcard */
556	if (!fetch_ssl_hname_equal(h, wcidx, m, wcidx))
557		return (0);
558	/* match part right of wildcard */
559	delta = mdot1idx - wcidx - 1;
560	if (!fetch_ssl_hname_equal(hdot - delta, delta,
561	    mdot1 - delta, delta))
562		return (0);
563	/* all tests succeeded, it's a match */
564	return (1);
565}
566
567/*
568 * Get numeric host address info - returns NULL if host was not an IP
569 * address. The caller is responsible for deallocation using
570 * freeaddrinfo(3).
571 */
572static struct addrinfo *
573fetch_ssl_get_numeric_addrinfo(const char *hostname, size_t len)
574{
575	struct addrinfo hints, *res;
576	char *host;
577
578	host = (char *)malloc(len + 1);
579	memcpy(host, hostname, len);
580	host[len] = '\0';
581	memset(&hints, 0, sizeof(hints));
582	hints.ai_family = PF_UNSPEC;
583	hints.ai_socktype = SOCK_STREAM;
584	hints.ai_protocol = 0;
585	hints.ai_flags = AI_NUMERICHOST;
586	/* port is not relevant for this purpose */
587	if (getaddrinfo(host, "443", &hints, &res) != 0)
588		res = NULL;
589	free(host);
590	return res;
591}
592
593/*
594 * Compare ip address in addrinfo with address passes.
595 */
596static int
597fetch_ssl_ipaddr_match_bin(const struct addrinfo *lhost, const char *rhost,
598    size_t rhostlen)
599{
600	const void *left;
601
602	if (lhost->ai_family == AF_INET && rhostlen == 4) {
603		left = (void *)&((struct sockaddr_in*)(void *)
604		    lhost->ai_addr)->sin_addr.s_addr;
605#ifdef INET6
606	} else if (lhost->ai_family == AF_INET6 && rhostlen == 16) {
607		left = (void *)&((struct sockaddr_in6 *)(void *)
608		    lhost->ai_addr)->sin6_addr;
609#endif
610	} else
611		return (0);
612	return (!memcmp(left, (const void *)rhost, rhostlen) ? 1 : 0);
613}
614
615/*
616 * Compare ip address in addrinfo with host passed. If host is not an IP
617 * address, comparison will fail.
618 */
619static int
620fetch_ssl_ipaddr_match(const struct addrinfo *laddr, const char *r,
621    size_t rlen)
622{
623	struct addrinfo *raddr;
624	int ret;
625	char *rip;
626
627	ret = 0;
628	if ((raddr = fetch_ssl_get_numeric_addrinfo(r, rlen)) == NULL)
629		return 0; /* not a numeric host */
630
631	if (laddr->ai_family == raddr->ai_family) {
632		if (laddr->ai_family == AF_INET) {
633			rip = (char *)&((struct sockaddr_in *)(void *)
634			    raddr->ai_addr)->sin_addr.s_addr;
635			ret = fetch_ssl_ipaddr_match_bin(laddr, rip, 4);
636#ifdef INET6
637		} else if (laddr->ai_family == AF_INET6) {
638			rip = (char *)&((struct sockaddr_in6 *)(void *)
639			    raddr->ai_addr)->sin6_addr;
640			ret = fetch_ssl_ipaddr_match_bin(laddr, rip, 16);
641#endif
642		}
643
644	}
645	freeaddrinfo(raddr);
646	return (ret);
647}
648
649/*
650 * Verify server certificate by subjectAltName.
651 */
652static int
653fetch_ssl_verify_altname(STACK_OF(GENERAL_NAME) *altnames,
654    const char *host, struct addrinfo *ip)
655{
656	const GENERAL_NAME *name;
657	size_t nslen;
658	int i;
659	const char *ns;
660
661	for (i = 0; i < sk_GENERAL_NAME_num(altnames); ++i) {
662#if OPENSSL_VERSION_NUMBER < 0x10000000L
663		/*
664		 * This is a workaround, since the following line causes
665		 * alignment issues in clang:
666		 * name = sk_GENERAL_NAME_value(altnames, i);
667		 * OpenSSL explicitly warns not to use those macros
668		 * directly, but there isn't much choice (and there
669		 * shouldn't be any ill side effects)
670		 */
671		name = (GENERAL_NAME *)SKM_sk_value(void, altnames, i);
672#else
673		name = sk_GENERAL_NAME_value(altnames, i);
674#endif
675		ns = (const char *)ASN1_STRING_data(name->d.ia5);
676		nslen = (size_t)ASN1_STRING_length(name->d.ia5);
677
678		if (name->type == GEN_DNS && ip == NULL &&
679		    fetch_ssl_hname_match(host, strlen(host), ns, nslen))
680			return (1);
681		else if (name->type == GEN_IPADD && ip != NULL &&
682		    fetch_ssl_ipaddr_match_bin(ip, ns, nslen))
683			return (1);
684	}
685	return (0);
686}
687
688/*
689 * Verify server certificate by CN.
690 */
691static int
692fetch_ssl_verify_cn(X509_NAME *subject, const char *host,
693    struct addrinfo *ip)
694{
695	ASN1_STRING *namedata;
696	X509_NAME_ENTRY *nameentry;
697	int cnlen, lastpos, loc, ret;
698	unsigned char *cn;
699
700	ret = 0;
701	lastpos = -1;
702	loc = -1;
703	cn = NULL;
704	/* get most specific CN (last entry in list) and compare */
705	while ((lastpos = X509_NAME_get_index_by_NID(subject,
706	    NID_commonName, lastpos)) != -1)
707		loc = lastpos;
708
709	if (loc > -1) {
710		nameentry = X509_NAME_get_entry(subject, loc);
711		namedata = X509_NAME_ENTRY_get_data(nameentry);
712		cnlen = ASN1_STRING_to_UTF8(&cn, namedata);
713		if (ip == NULL &&
714		    fetch_ssl_hname_match(host, strlen(host), cn, cnlen))
715			ret = 1;
716		else if (ip != NULL && fetch_ssl_ipaddr_match(ip, cn, cnlen))
717			ret = 1;
718		OPENSSL_free(cn);
719	}
720	return (ret);
721}
722
723/*
724 * Verify that server certificate subjectAltName/CN matches
725 * hostname. First check, if there are alternative subject names. If yes,
726 * those have to match. Only if those don't exist it falls back to
727 * checking the subject's CN.
728 */
729static int
730fetch_ssl_verify_hname(X509 *cert, const char *host)
731{
732	struct addrinfo *ip;
733	STACK_OF(GENERAL_NAME) *altnames;
734	X509_NAME *subject;
735	int ret;
736
737	ret = 0;
738	ip = fetch_ssl_get_numeric_addrinfo(host, strlen(host));
739	altnames = X509_get_ext_d2i(cert, NID_subject_alt_name,
740	    NULL, NULL);
741
742	if (altnames != NULL) {
743		ret = fetch_ssl_verify_altname(altnames, host, ip);
744	} else {
745		subject = X509_get_subject_name(cert);
746		if (subject != NULL)
747			ret = fetch_ssl_verify_cn(subject, host, ip);
748	}
749
750	if (ip != NULL)
751		freeaddrinfo(ip);
752	if (altnames != NULL)
753		GENERAL_NAMES_free(altnames);
754	return (ret);
755}
756
757/*
758 * Configure transport security layer based on environment.
759 */
760static void
761fetch_ssl_setup_transport_layer(SSL_CTX *ctx, int verbose)
762{
763	long ssl_ctx_options;
764
765	ssl_ctx_options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_TICKET;
766	if (getenv("SSL_ALLOW_SSL3") == NULL)
767		ssl_ctx_options |= SSL_OP_NO_SSLv3;
768	if (getenv("SSL_NO_TLS1") != NULL)
769		ssl_ctx_options |= SSL_OP_NO_TLSv1;
770	if (getenv("SSL_NO_TLS1_1") != NULL)
771		ssl_ctx_options |= SSL_OP_NO_TLSv1_1;
772	if (getenv("SSL_NO_TLS1_2") != NULL)
773		ssl_ctx_options |= SSL_OP_NO_TLSv1_2;
774	if (verbose)
775		fetch_info("SSL options: %lx", ssl_ctx_options);
776	SSL_CTX_set_options(ctx, ssl_ctx_options);
777}
778
779
780/*
781 * Configure peer verification based on environment.
782 */
783#define LOCAL_CERT_FILE	"/usr/local/etc/ssl/cert.pem"
784#define BASE_CERT_FILE	"/etc/ssl/cert.pem"
785static int
786fetch_ssl_setup_peer_verification(SSL_CTX *ctx, int verbose)
787{
788	X509_LOOKUP *crl_lookup;
789	X509_STORE *crl_store;
790	const char *ca_cert_file, *ca_cert_path, *crl_file;
791
792	if (getenv("SSL_NO_VERIFY_PEER") == NULL) {
793		ca_cert_file = getenv("SSL_CA_CERT_FILE");
794		if (ca_cert_file == NULL &&
795		    access(LOCAL_CERT_FILE, R_OK) == 0)
796			ca_cert_file = LOCAL_CERT_FILE;
797		if (ca_cert_file == NULL &&
798		    access(BASE_CERT_FILE, R_OK) == 0)
799			ca_cert_file = BASE_CERT_FILE;
800		ca_cert_path = getenv("SSL_CA_CERT_PATH");
801		if (verbose) {
802			fetch_info("Peer verification enabled");
803			if (ca_cert_file != NULL)
804				fetch_info("Using CA cert file: %s",
805				    ca_cert_file);
806			if (ca_cert_path != NULL)
807				fetch_info("Using CA cert path: %s",
808				    ca_cert_path);
809			if (ca_cert_file == NULL && ca_cert_path == NULL)
810				fetch_info("Using OpenSSL default "
811				    "CA cert file and path");
812		}
813		SSL_CTX_set_verify(ctx, SSL_VERIFY_PEER,
814		    fetch_ssl_cb_verify_crt);
815		if (ca_cert_file != NULL || ca_cert_path != NULL)
816			SSL_CTX_load_verify_locations(ctx, ca_cert_file,
817			    ca_cert_path);
818		else
819			SSL_CTX_set_default_verify_paths(ctx);
820		if ((crl_file = getenv("SSL_CRL_FILE")) != NULL) {
821			if (verbose)
822				fetch_info("Using CRL file: %s", crl_file);
823			crl_store = SSL_CTX_get_cert_store(ctx);
824			crl_lookup = X509_STORE_add_lookup(crl_store,
825			    X509_LOOKUP_file());
826			if (crl_lookup == NULL ||
827			    !X509_load_crl_file(crl_lookup, crl_file,
828				X509_FILETYPE_PEM)) {
829				fprintf(stderr,
830				    "Could not load CRL file %s\n",
831				    crl_file);
832				return (0);
833			}
834			X509_STORE_set_flags(crl_store,
835			    X509_V_FLAG_CRL_CHECK |
836			    X509_V_FLAG_CRL_CHECK_ALL);
837		}
838	}
839	return (1);
840}
841
842/*
843 * Configure client certificate based on environment.
844 */
845static int
846fetch_ssl_setup_client_certificate(SSL_CTX *ctx, int verbose)
847{
848	const char *client_cert_file, *client_key_file;
849
850	if ((client_cert_file = getenv("SSL_CLIENT_CERT_FILE")) != NULL) {
851		client_key_file = getenv("SSL_CLIENT_KEY_FILE") != NULL ?
852		    getenv("SSL_CLIENT_KEY_FILE") : client_cert_file;
853		if (verbose) {
854			fetch_info("Using client cert file: %s",
855			    client_cert_file);
856			fetch_info("Using client key file: %s",
857			    client_key_file);
858		}
859		if (SSL_CTX_use_certificate_chain_file(ctx,
860			client_cert_file) != 1) {
861			fprintf(stderr,
862			    "Could not load client certificate %s\n",
863			    client_cert_file);
864			return (0);
865		}
866		if (SSL_CTX_use_PrivateKey_file(ctx, client_key_file,
867			SSL_FILETYPE_PEM) != 1) {
868			fprintf(stderr,
869			    "Could not load client key %s\n",
870			    client_key_file);
871			return (0);
872		}
873	}
874	return (1);
875}
876
877/*
878 * Callback for SSL certificate verification, this is called on server
879 * cert verification. It takes no decision, but informs the user in case
880 * verification failed.
881 */
882int
883fetch_ssl_cb_verify_crt(int verified, X509_STORE_CTX *ctx)
884{
885	X509 *crt;
886	X509_NAME *name;
887	char *str;
888
889	str = NULL;
890	if (!verified) {
891		if ((crt = X509_STORE_CTX_get_current_cert(ctx)) != NULL &&
892		    (name = X509_get_subject_name(crt)) != NULL)
893			str = X509_NAME_oneline(name, 0, 0);
894		fprintf(stderr, "Certificate verification failed for %s\n",
895		    str != NULL ? str : "no relevant certificate");
896		OPENSSL_free(str);
897	}
898	return (verified);
899}
900
901#endif
902
903/*
904 * Enable SSL on a connection.
905 */
906int
907fetch_ssl(conn_t *conn, const struct url *URL, int verbose)
908{
909#ifdef WITH_SSL
910	int ret, ssl_err;
911	X509_NAME *name;
912	char *str;
913
914	/* Init the SSL library and context */
915	if (!SSL_library_init()){
916		fprintf(stderr, "SSL library init failed\n");
917		return (-1);
918	}
919
920	SSL_load_error_strings();
921
922	conn->ssl_meth = SSLv23_client_method();
923	conn->ssl_ctx = SSL_CTX_new(conn->ssl_meth);
924	SSL_CTX_set_mode(conn->ssl_ctx, SSL_MODE_AUTO_RETRY);
925
926	fetch_ssl_setup_transport_layer(conn->ssl_ctx, verbose);
927	if (!fetch_ssl_setup_peer_verification(conn->ssl_ctx, verbose))
928		return (-1);
929	if (!fetch_ssl_setup_client_certificate(conn->ssl_ctx, verbose))
930		return (-1);
931
932	conn->ssl = SSL_new(conn->ssl_ctx);
933	if (conn->ssl == NULL) {
934		fprintf(stderr, "SSL context creation failed\n");
935		return (-1);
936	}
937	SSL_set_fd(conn->ssl, conn->sd);
938
939#if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
940	if (!SSL_set_tlsext_host_name(conn->ssl,
941	    __DECONST(struct url *, URL)->host)) {
942		fprintf(stderr,
943		    "TLS server name indication extension failed for host %s\n",
944		    URL->host);
945		return (-1);
946	}
947#endif
948	while ((ret = SSL_connect(conn->ssl)) == -1) {
949		ssl_err = SSL_get_error(conn->ssl, ret);
950		if (ssl_err != SSL_ERROR_WANT_READ &&
951		    ssl_err != SSL_ERROR_WANT_WRITE) {
952			ERR_print_errors_fp(stderr);
953			return (-1);
954		}
955	}
956	conn->ssl_cert = SSL_get_peer_certificate(conn->ssl);
957
958	if (conn->ssl_cert == NULL) {
959		fprintf(stderr, "No server SSL certificate\n");
960		return (-1);
961	}
962
963	if (getenv("SSL_NO_VERIFY_HOSTNAME") == NULL) {
964		if (verbose)
965			fetch_info("Verify hostname");
966		if (!fetch_ssl_verify_hname(conn->ssl_cert, URL->host)) {
967			fprintf(stderr,
968			    "SSL certificate subject doesn't match host %s\n",
969			    URL->host);
970			return (-1);
971		}
972	}
973
974	if (verbose) {
975		fetch_info("%s connection established using %s",
976		    SSL_get_version(conn->ssl), SSL_get_cipher(conn->ssl));
977		name = X509_get_subject_name(conn->ssl_cert);
978		str = X509_NAME_oneline(name, 0, 0);
979		fetch_info("Certificate subject: %s", str);
980		OPENSSL_free(str);
981		name = X509_get_issuer_name(conn->ssl_cert);
982		str = X509_NAME_oneline(name, 0, 0);
983		fetch_info("Certificate issuer: %s", str);
984		OPENSSL_free(str);
985	}
986
987	return (0);
988#else
989	(void)conn;
990	(void)verbose;
991	fprintf(stderr, "SSL support disabled\n");
992	return (-1);
993#endif
994}
995
996#define FETCH_READ_WAIT		-2
997#define FETCH_READ_ERROR	-1
998#define FETCH_READ_DONE		 0
999
1000#ifdef WITH_SSL
1001static ssize_t
1002fetch_ssl_read(SSL *ssl, char *buf, size_t len)
1003{
1004	ssize_t rlen;
1005	int ssl_err;
1006
1007	rlen = SSL_read(ssl, buf, len);
1008	if (rlen < 0) {
1009		ssl_err = SSL_get_error(ssl, rlen);
1010		if (ssl_err == SSL_ERROR_WANT_READ ||
1011		    ssl_err == SSL_ERROR_WANT_WRITE) {
1012			return (FETCH_READ_WAIT);
1013		} else {
1014			ERR_print_errors_fp(stderr);
1015			return (FETCH_READ_ERROR);
1016		}
1017	}
1018	return (rlen);
1019}
1020#endif
1021
1022static ssize_t
1023fetch_socket_read(int sd, char *buf, size_t len)
1024{
1025	ssize_t rlen;
1026
1027	rlen = read(sd, buf, len);
1028	if (rlen < 0) {
1029		if (errno == EAGAIN || (errno == EINTR && fetchRestartCalls))
1030			return (FETCH_READ_WAIT);
1031		else
1032			return (FETCH_READ_ERROR);
1033	}
1034	return (rlen);
1035}
1036
1037/*
1038 * Read a character from a connection w/ timeout
1039 */
1040ssize_t
1041fetch_read(conn_t *conn, char *buf, size_t len)
1042{
1043	struct timeval now, timeout, delta;
1044	struct pollfd pfd;
1045	ssize_t rlen;
1046	int deltams;
1047
1048	if (fetchTimeout > 0) {
1049		gettimeofday(&timeout, NULL);
1050		timeout.tv_sec += fetchTimeout;
1051	}
1052
1053	deltams = INFTIM;
1054	memset(&pfd, 0, sizeof pfd);
1055	pfd.fd = conn->sd;
1056	pfd.events = POLLIN | POLLERR;
1057
1058	for (;;) {
1059		/*
1060		 * The socket is non-blocking.  Instead of the canonical
1061		 * poll() -> read(), we do the following:
1062		 *
1063		 * 1) call read() or SSL_read().
1064		 * 2) if we received some data, return it.
1065		 * 3) if an error occurred, return -1.
1066		 * 4) if read() or SSL_read() signaled EOF, return.
1067		 * 5) if we did not receive any data but we're not at EOF,
1068		 *    call poll().
1069		 *
1070		 * In the SSL case, this is necessary because if we
1071		 * receive a close notification, we have to call
1072		 * SSL_read() one additional time after we've read
1073		 * everything we received.
1074		 *
1075		 * In the non-SSL case, it may improve performance (very
1076		 * slightly) when reading small amounts of data.
1077		 */
1078#ifdef WITH_SSL
1079		if (conn->ssl != NULL)
1080			rlen = fetch_ssl_read(conn->ssl, buf, len);
1081		else
1082#endif
1083			rlen = fetch_socket_read(conn->sd, buf, len);
1084		if (rlen >= 0) {
1085			break;
1086		} else if (rlen == FETCH_READ_ERROR) {
1087			fetch_syserr();
1088			return (-1);
1089		}
1090		// assert(rlen == FETCH_READ_WAIT);
1091		if (fetchTimeout > 0) {
1092			gettimeofday(&now, NULL);
1093			if (!timercmp(&timeout, &now, >)) {
1094				errno = ETIMEDOUT;
1095				fetch_syserr();
1096				return (-1);
1097			}
1098			timersub(&timeout, &now, &delta);
1099			deltams = delta.tv_sec * 1000 +
1100			    delta.tv_usec / 1000;;
1101		}
1102		errno = 0;
1103		pfd.revents = 0;
1104		if (poll(&pfd, 1, deltams) < 0) {
1105			if (errno == EINTR && fetchRestartCalls)
1106				continue;
1107			fetch_syserr();
1108			return (-1);
1109		}
1110	}
1111	return (rlen);
1112}
1113
1114
1115/*
1116 * Read a line of text from a connection w/ timeout
1117 */
1118#define MIN_BUF_SIZE 1024
1119
1120int
1121fetch_getln(conn_t *conn)
1122{
1123	char *tmp;
1124	size_t tmpsize;
1125	ssize_t len;
1126	char c;
1127
1128	if (conn->buf == NULL) {
1129		if ((conn->buf = malloc(MIN_BUF_SIZE)) == NULL) {
1130			errno = ENOMEM;
1131			return (-1);
1132		}
1133		conn->bufsize = MIN_BUF_SIZE;
1134	}
1135
1136	conn->buf[0] = '\0';
1137	conn->buflen = 0;
1138
1139	do {
1140		len = fetch_read(conn, &c, 1);
1141		if (len == -1)
1142			return (-1);
1143		if (len == 0)
1144			break;
1145		conn->buf[conn->buflen++] = c;
1146		if (conn->buflen == conn->bufsize) {
1147			tmp = conn->buf;
1148			tmpsize = conn->bufsize * 2 + 1;
1149			if ((tmp = realloc(tmp, tmpsize)) == NULL) {
1150				errno = ENOMEM;
1151				return (-1);
1152			}
1153			conn->buf = tmp;
1154			conn->bufsize = tmpsize;
1155		}
1156	} while (c != '\n');
1157
1158	conn->buf[conn->buflen] = '\0';
1159	DEBUGF("<<< %s", conn->buf);
1160	return (0);
1161}
1162
1163
1164/*
1165 * Write to a connection w/ timeout
1166 */
1167ssize_t
1168fetch_write(conn_t *conn, const char *buf, size_t len)
1169{
1170	struct iovec iov;
1171
1172	iov.iov_base = __DECONST(char *, buf);
1173	iov.iov_len = len;
1174	return fetch_writev(conn, &iov, 1);
1175}
1176
1177/*
1178 * Write a vector to a connection w/ timeout
1179 * Note: can modify the iovec.
1180 */
1181ssize_t
1182fetch_writev(conn_t *conn, struct iovec *iov, int iovcnt)
1183{
1184	struct timeval now, timeout, delta;
1185	struct pollfd pfd;
1186	ssize_t wlen, total;
1187	int deltams;
1188
1189	memset(&pfd, 0, sizeof pfd);
1190	if (fetchTimeout) {
1191		pfd.fd = conn->sd;
1192		pfd.events = POLLOUT | POLLERR;
1193		gettimeofday(&timeout, NULL);
1194		timeout.tv_sec += fetchTimeout;
1195	}
1196
1197	total = 0;
1198	while (iovcnt > 0) {
1199		while (fetchTimeout && pfd.revents == 0) {
1200			gettimeofday(&now, NULL);
1201			if (!timercmp(&timeout, &now, >)) {
1202				errno = ETIMEDOUT;
1203				fetch_syserr();
1204				return (-1);
1205			}
1206			timersub(&timeout, &now, &delta);
1207			deltams = delta.tv_sec * 1000 +
1208			    delta.tv_usec / 1000;
1209			errno = 0;
1210			pfd.revents = 0;
1211			if (poll(&pfd, 1, deltams) < 0) {
1212				/* POSIX compliance */
1213				if (errno == EAGAIN)
1214					continue;
1215				if (errno == EINTR && fetchRestartCalls)
1216					continue;
1217				return (-1);
1218			}
1219		}
1220		errno = 0;
1221#ifdef WITH_SSL
1222		if (conn->ssl != NULL)
1223			wlen = SSL_write(conn->ssl,
1224			    iov->iov_base, iov->iov_len);
1225		else
1226#endif
1227			wlen = writev(conn->sd, iov, iovcnt);
1228		if (wlen == 0) {
1229			/* we consider a short write a failure */
1230			/* XXX perhaps we shouldn't in the SSL case */
1231			errno = EPIPE;
1232			fetch_syserr();
1233			return (-1);
1234		}
1235		if (wlen < 0) {
1236			if (errno == EINTR && fetchRestartCalls)
1237				continue;
1238			return (-1);
1239		}
1240		total += wlen;
1241		while (iovcnt > 0 && wlen >= (ssize_t)iov->iov_len) {
1242			wlen -= iov->iov_len;
1243			iov++;
1244			iovcnt--;
1245		}
1246		if (iovcnt > 0) {
1247			iov->iov_len -= wlen;
1248			iov->iov_base = __DECONST(char *, iov->iov_base) + wlen;
1249		}
1250	}
1251	return (total);
1252}
1253
1254
1255/*
1256 * Write a line of text to a connection w/ timeout
1257 */
1258int
1259fetch_putln(conn_t *conn, const char *str, size_t len)
1260{
1261	struct iovec iov[2];
1262	int ret;
1263
1264	DEBUGF(">>> %s\n", str);
1265	iov[0].iov_base = __DECONST(char *, str);
1266	iov[0].iov_len = len;
1267	iov[1].iov_base = __DECONST(char *, ENDL);
1268	iov[1].iov_len = sizeof(ENDL);
1269	if (len == 0)
1270		ret = fetch_writev(conn, &iov[1], 1);
1271	else
1272		ret = fetch_writev(conn, iov, 2);
1273	if (ret == -1)
1274		return (-1);
1275	return (0);
1276}
1277
1278
1279/*
1280 * Close connection
1281 */
1282int
1283fetch_close(conn_t *conn)
1284{
1285	int ret;
1286
1287	if (--conn->ref > 0)
1288		return (0);
1289#ifdef WITH_SSL
1290	if (conn->ssl) {
1291		SSL_shutdown(conn->ssl);
1292		SSL_set_connect_state(conn->ssl);
1293		SSL_free(conn->ssl);
1294		conn->ssl = NULL;
1295	}
1296	if (conn->ssl_ctx) {
1297		SSL_CTX_free(conn->ssl_ctx);
1298		conn->ssl_ctx = NULL;
1299	}
1300	if (conn->ssl_cert) {
1301		X509_free(conn->ssl_cert);
1302		conn->ssl_cert = NULL;
1303	}
1304#endif
1305	ret = close(conn->sd);
1306	free(conn->buf);
1307	free(conn);
1308	return (ret);
1309}
1310
1311
1312/*** Directory-related utility functions *************************************/
1313
1314int
1315fetch_add_entry(struct url_ent **p, int *size, int *len,
1316    const char *name, struct url_stat *us)
1317{
1318	struct url_ent *tmp;
1319
1320	if (*p == NULL) {
1321		*size = 0;
1322		*len = 0;
1323	}
1324
1325	if (*len >= *size - 1) {
1326		tmp = reallocarray(*p, *size * 2 + 1, sizeof(**p));
1327		if (tmp == NULL) {
1328			errno = ENOMEM;
1329			fetch_syserr();
1330			return (-1);
1331		}
1332		*size = (*size * 2 + 1);
1333		*p = tmp;
1334	}
1335
1336	tmp = *p + *len;
1337	snprintf(tmp->name, PATH_MAX, "%s", name);
1338	memcpy(&tmp->stat, us, sizeof(*us));
1339
1340	(*len)++;
1341	(++tmp)->name[0] = 0;
1342
1343	return (0);
1344}
1345
1346
1347/*** Authentication-related utility functions ********************************/
1348
1349static const char *
1350fetch_read_word(FILE *f)
1351{
1352	static char word[1024];
1353
1354	if (fscanf(f, " %1023s ", word) != 1)
1355		return (NULL);
1356	return (word);
1357}
1358
1359static int
1360fetch_netrc_open(void)
1361{
1362	struct passwd *pwd;
1363	char fn[PATH_MAX];
1364	const char *p;
1365	int fd, serrno;
1366
1367	if ((p = getenv("NETRC")) != NULL) {
1368		DEBUGF("NETRC=%s\n", p);
1369		if (snprintf(fn, sizeof(fn), "%s", p) >= (int)sizeof(fn)) {
1370			fetch_info("$NETRC specifies a file name "
1371			    "longer than PATH_MAX");
1372			return (-1);
1373		}
1374	} else {
1375		if ((p = getenv("HOME")) == NULL) {
1376			if ((pwd = getpwuid(getuid())) == NULL ||
1377			    (p = pwd->pw_dir) == NULL)
1378				return (-1);
1379		}
1380		if (snprintf(fn, sizeof(fn), "%s/.netrc", p) >= (int)sizeof(fn))
1381			return (-1);
1382	}
1383
1384	if ((fd = open(fn, O_RDONLY)) < 0) {
1385		serrno = errno;
1386		DEBUGF("%s: %s\n", fn, strerror(serrno));
1387		errno = serrno;
1388	}
1389	return (fd);
1390}
1391
1392/*
1393 * Get authentication data for a URL from .netrc
1394 */
1395int
1396fetch_netrc_auth(struct url *url)
1397{
1398	const char *word;
1399	int serrno;
1400	FILE *f;
1401
1402	if (url->netrcfd < 0)
1403		url->netrcfd = fetch_netrc_open();
1404	if (url->netrcfd < 0)
1405		return (-1);
1406	if ((f = fdopen(url->netrcfd, "r")) == NULL) {
1407		serrno = errno;
1408		DEBUGF("fdopen(netrcfd): %s", strerror(errno));
1409		close(url->netrcfd);
1410		url->netrcfd = -1;
1411		errno = serrno;
1412		return (-1);
1413	}
1414	rewind(f);
1415	DEBUGF("searching netrc for %s\n", url->host);
1416	while ((word = fetch_read_word(f)) != NULL) {
1417		if (strcmp(word, "default") == 0) {
1418			DEBUGF("using default netrc settings\n");
1419			break;
1420		}
1421		if (strcmp(word, "machine") == 0 &&
1422		    (word = fetch_read_word(f)) != NULL &&
1423		    strcasecmp(word, url->host) == 0) {
1424			DEBUGF("using netrc settings for %s\n", word);
1425			break;
1426		}
1427	}
1428	if (word == NULL)
1429		goto ferr;
1430	while ((word = fetch_read_word(f)) != NULL) {
1431		if (strcmp(word, "login") == 0) {
1432			if ((word = fetch_read_word(f)) == NULL)
1433				goto ferr;
1434			if (snprintf(url->user, sizeof(url->user),
1435				"%s", word) > (int)sizeof(url->user)) {
1436				fetch_info("login name in .netrc is too long");
1437				url->user[0] = '\0';
1438			}
1439		} else if (strcmp(word, "password") == 0) {
1440			if ((word = fetch_read_word(f)) == NULL)
1441				goto ferr;
1442			if (snprintf(url->pwd, sizeof(url->pwd),
1443				"%s", word) > (int)sizeof(url->pwd)) {
1444				fetch_info("password in .netrc is too long");
1445				url->pwd[0] = '\0';
1446			}
1447		} else if (strcmp(word, "account") == 0) {
1448			if ((word = fetch_read_word(f)) == NULL)
1449				goto ferr;
1450			/* XXX not supported! */
1451		} else {
1452			break;
1453		}
1454	}
1455	fclose(f);
1456	url->netrcfd = -1;
1457	return (0);
1458ferr:
1459	serrno = errno;
1460	fclose(f);
1461	url->netrcfd = -1;
1462	errno = serrno;
1463	return (-1);
1464}
1465
1466/*
1467 * The no_proxy environment variable specifies a set of domains for
1468 * which the proxy should not be consulted; the contents is a comma-,
1469 * or space-separated list of domain names.  A single asterisk will
1470 * override all proxy variables and no transactions will be proxied
1471 * (for compatibility with lynx and curl, see the discussion at
1472 * <http://curl.haxx.se/mail/archive_pre_oct_99/0009.html>).
1473 */
1474int
1475fetch_no_proxy_match(const char *host)
1476{
1477	const char *no_proxy, *p, *q;
1478	size_t h_len, d_len;
1479
1480	if ((no_proxy = getenv("NO_PROXY")) == NULL &&
1481	    (no_proxy = getenv("no_proxy")) == NULL)
1482		return (0);
1483
1484	/* asterisk matches any hostname */
1485	if (strcmp(no_proxy, "*") == 0)
1486		return (1);
1487
1488	h_len = strlen(host);
1489	p = no_proxy;
1490	do {
1491		/* position p at the beginning of a domain suffix */
1492		while (*p == ',' || isspace((unsigned char)*p))
1493			p++;
1494
1495		/* position q at the first separator character */
1496		for (q = p; *q; ++q)
1497			if (*q == ',' || isspace((unsigned char)*q))
1498				break;
1499
1500		d_len = q - p;
1501		if (d_len > 0 && h_len >= d_len &&
1502		    strncasecmp(host + h_len - d_len,
1503			p, d_len) == 0) {
1504			/* domain name matches */
1505			return (1);
1506		}
1507
1508		p = q + 1;
1509	} while (*q);
1510
1511	return (0);
1512}
1513