xref: /dflybsd-src/lib/libfetch/common.c (revision 5807cf3c35db5fe11789b11a0bbdc96210746d1f)
1 /*-
2  * Copyright (c) 1998-2004 Dag-Erling Co�dan Sm�rgrav
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice, this list of conditions and the following disclaimer
10  *    in this position and unchanged.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  * 3. The name of the author may not be used to endorse or promote products
15  *    derived from this software without specific prior written permission
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27  *
28  * $FreeBSD: src/lib/libfetch/common.c,v 1.56 2008/04/15 23:29:51 cperciva Exp $
29  */
30 
31 #include <sys/param.h>
32 #include <sys/socket.h>
33 #include <sys/time.h>
34 #include <sys/uio.h>
35 
36 #include <netinet/in.h>
37 
38 #include <ctype.h>
39 #include <errno.h>
40 #include <fcntl.h>
41 #include <netdb.h>
42 #include <pwd.h>
43 #include <stdarg.h>
44 #include <stdlib.h>
45 #include <stdio.h>
46 #include <string.h>
47 #include <unistd.h>
48 
49 #include "fetch.h"
50 #include "common.h"
51 
52 
53 /*** Local data **************************************************************/
54 
55 /*
56  * Error messages for resolver errors
57  */
58 static struct fetcherr netdb_errlist[] = {
59 #ifdef EAI_NODATA
60 	{ EAI_NODATA,	FETCH_RESOLV,	"Host not found" },
61 #endif
62 	{ EAI_AGAIN,	FETCH_TEMP,	"Transient resolver failure" },
63 	{ EAI_FAIL,	FETCH_RESOLV,	"Non-recoverable resolver failure" },
64 	{ EAI_NONAME,	FETCH_RESOLV,	"No address record" },
65 	{ -1,		FETCH_UNKNOWN,	"Unknown resolver error" }
66 };
67 
68 /* End-of-Line */
69 static const char ENDL[2] = "\r\n";
70 
71 
72 /*** Error-reporting functions ***********************************************/
73 
74 /*
75  * Map error code to string
76  */
77 static struct fetcherr *
78 fetch_finderr(struct fetcherr *p, int e)
79 {
80 	while (p->num != -1 && p->num != e)
81 		p++;
82 	return (p);
83 }
84 
85 /*
86  * Set error code
87  */
88 void
89 fetch_seterr(struct fetcherr *p, int e)
90 {
91 	p = fetch_finderr(p, e);
92 	fetchLastErrCode = p->cat;
93 	snprintf(fetchLastErrString, MAXERRSTRING, "%s", p->string);
94 }
95 
96 /*
97  * Set error code according to errno
98  */
99 void
100 fetch_syserr(void)
101 {
102 	switch (errno) {
103 	case 0:
104 		fetchLastErrCode = FETCH_OK;
105 		break;
106 	case EPERM:
107 	case EACCES:
108 	case EROFS:
109 	case EAUTH:
110 	case ENEEDAUTH:
111 		fetchLastErrCode = FETCH_AUTH;
112 		break;
113 	case ENOENT:
114 	case EISDIR: /* XXX */
115 		fetchLastErrCode = FETCH_UNAVAIL;
116 		break;
117 	case ENOMEM:
118 		fetchLastErrCode = FETCH_MEMORY;
119 		break;
120 	case EBUSY:
121 	case EAGAIN:
122 		fetchLastErrCode = FETCH_TEMP;
123 		break;
124 	case EEXIST:
125 		fetchLastErrCode = FETCH_EXISTS;
126 		break;
127 	case ENOSPC:
128 		fetchLastErrCode = FETCH_FULL;
129 		break;
130 	case EADDRINUSE:
131 	case EADDRNOTAVAIL:
132 	case ENETDOWN:
133 	case ENETUNREACH:
134 	case ENETRESET:
135 	case EHOSTUNREACH:
136 		fetchLastErrCode = FETCH_NETWORK;
137 		break;
138 	case ECONNABORTED:
139 	case ECONNRESET:
140 		fetchLastErrCode = FETCH_ABORT;
141 		break;
142 	case ETIMEDOUT:
143 		fetchLastErrCode = FETCH_TIMEOUT;
144 		break;
145 	case ECONNREFUSED:
146 	case EHOSTDOWN:
147 		fetchLastErrCode = FETCH_DOWN;
148 		break;
149 default:
150 		fetchLastErrCode = FETCH_UNKNOWN;
151 	}
152 	snprintf(fetchLastErrString, MAXERRSTRING, "%s", strerror(errno));
153 }
154 
155 
156 /*
157  * Emit status message
158  */
159 void
160 fetch_info(const char *fmt, ...)
161 {
162 	va_list ap;
163 
164 	va_start(ap, fmt);
165 	vfprintf(stderr, fmt, ap);
166 	va_end(ap);
167 	fputc('\n', stderr);
168 }
169 
170 
171 /*** Network-related utility functions ***************************************/
172 
173 /*
174  * Return the default port for a scheme
175  */
176 int
177 fetch_default_port(const char *scheme)
178 {
179 	struct servent *se;
180 
181 	if ((se = getservbyname(scheme, "tcp")) != NULL)
182 		return (ntohs(se->s_port));
183 	if (strcasecmp(scheme, SCHEME_FTP) == 0)
184 		return (FTP_DEFAULT_PORT);
185 	if (strcasecmp(scheme, SCHEME_HTTP) == 0)
186 		return (HTTP_DEFAULT_PORT);
187 	return (0);
188 }
189 
190 /*
191  * Return the default proxy port for a scheme
192  */
193 int
194 fetch_default_proxy_port(const char *scheme)
195 {
196 	if (strcasecmp(scheme, SCHEME_FTP) == 0)
197 		return (FTP_DEFAULT_PROXY_PORT);
198 	if (strcasecmp(scheme, SCHEME_HTTP) == 0)
199 		return (HTTP_DEFAULT_PROXY_PORT);
200 	return (0);
201 }
202 
203 
204 /*
205  * Create a connection for an existing descriptor.
206  */
207 conn_t *
208 fetch_reopen(int sd)
209 {
210 	conn_t *conn;
211 
212 	/* allocate and fill connection structure */
213 	if ((conn = calloc(1, sizeof(*conn))) == NULL)
214 		return (NULL);
215 	conn->sd = sd;
216 	++conn->ref;
217 	return (conn);
218 }
219 
220 
221 /*
222  * Bump a connection's reference count.
223  */
224 conn_t *
225 fetch_ref(conn_t *conn)
226 {
227 
228 	++conn->ref;
229 	return (conn);
230 }
231 
232 
233 /*
234  * Bind a socket to a specific local address
235  */
236 int
237 fetch_bind(int sd, int af, const char *addr)
238 {
239 	struct addrinfo hints, *res, *res0;
240 	int err;
241 
242 	memset(&hints, 0, sizeof(hints));
243 	hints.ai_family = af;
244 	hints.ai_socktype = SOCK_STREAM;
245 	hints.ai_protocol = 0;
246 	if ((err = getaddrinfo(addr, NULL, &hints, &res0)) != 0)
247 		return (-1);
248 	for (res = res0; res; res = res->ai_next)
249 		if (bind(sd, res->ai_addr, res->ai_addrlen) == 0)
250 			return (0);
251 	return (-1);
252 }
253 
254 
255 /*
256  * Establish a TCP connection to the specified port on the specified host.
257  */
258 conn_t *
259 fetch_connect(const char *host, int port, int af, int verbose)
260 {
261 	conn_t *conn;
262 	char pbuf[10];
263 	const char *bindaddr;
264 	struct addrinfo hints, *res, *res0;
265 	int sd, err;
266 
267 	DEBUG(fprintf(stderr, "---> %s:%d\n", host, port));
268 
269 	if (verbose)
270 		fetch_info("looking up %s", host);
271 
272 	/* look up host name and set up socket address structure */
273 	snprintf(pbuf, sizeof(pbuf), "%d", port);
274 	memset(&hints, 0, sizeof(hints));
275 	hints.ai_family = af;
276 	hints.ai_socktype = SOCK_STREAM;
277 	hints.ai_protocol = 0;
278 	if ((err = getaddrinfo(host, pbuf, &hints, &res0)) != 0) {
279 		netdb_seterr(err);
280 		return (NULL);
281 	}
282 	bindaddr = getenv("FETCH_BIND_ADDRESS");
283 
284 	if (verbose)
285 		fetch_info("connecting to %s:%d", host, port);
286 
287 	/* try to connect */
288 	for (sd = -1, res = res0; res; sd = -1, res = res->ai_next) {
289 		if ((sd = socket(res->ai_family, res->ai_socktype,
290 			 res->ai_protocol)) == -1)
291 			continue;
292 		if (bindaddr != NULL && *bindaddr != '\0' &&
293 		    fetch_bind(sd, res->ai_family, bindaddr) != 0) {
294 			fetch_info("failed to bind to '%s'", bindaddr);
295 			close(sd);
296 			continue;
297 		}
298 		if (connect(sd, res->ai_addr, res->ai_addrlen) == 0 &&
299                     fcntl(sd, F_SETFL, O_NONBLOCK) == 0)
300 			break;
301 		close(sd);
302 	}
303 	freeaddrinfo(res0);
304 	if (sd == -1) {
305 		fetch_syserr();
306 		return (NULL);
307 	}
308 
309 	if ((conn = fetch_reopen(sd)) == NULL) {
310 		fetch_syserr();
311 		close(sd);
312 	}
313 	return (conn);
314 }
315 
316 
317 /*
318  * Enable SSL on a connection.
319  */
320 int
321 fetch_ssl(conn_t *conn, int verbose)
322 {
323         int ret, ssl_err;
324 
325 #ifdef WITH_SSL
326 	/* Init the SSL library and context */
327 	if (!SSL_library_init()){
328 		fprintf(stderr, "SSL library init failed\n");
329 		return (-1);
330 	}
331 
332 	SSL_load_error_strings();
333 
334 	conn->ssl_meth = SSLv23_client_method();
335 	conn->ssl_ctx = SSL_CTX_new(conn->ssl_meth);
336 	SSL_CTX_set_mode(conn->ssl_ctx, SSL_MODE_AUTO_RETRY);
337 
338 	conn->ssl = SSL_new(conn->ssl_ctx);
339 	if (conn->ssl == NULL){
340 		fprintf(stderr, "SSL context creation failed\n");
341 		return (-1);
342 	}
343 	SSL_set_fd(conn->ssl, conn->sd);
344 	while ((ret = SSL_connect(conn->ssl)) == -1) {
345 		ssl_err = SSL_get_error(conn->ssl, ret);
346 		if (ssl_err != SSL_ERROR_WANT_READ &&
347 		    ssl_err != SSL_ERROR_WANT_WRITE) {
348 			ERR_print_errors_fp(stderr);
349 			return (-1);
350 		}
351 	}
352 
353 	if (verbose) {
354 		X509_NAME *name;
355 		char *str;
356 
357 		fprintf(stderr, "SSL connection established using %s\n",
358 		    SSL_get_cipher(conn->ssl));
359 		conn->ssl_cert = SSL_get_peer_certificate(conn->ssl);
360 		name = X509_get_subject_name(conn->ssl_cert);
361 		str = X509_NAME_oneline(name, 0, 0);
362 		printf("Certificate subject: %s\n", str);
363 		free(str);
364 		name = X509_get_issuer_name(conn->ssl_cert);
365 		str = X509_NAME_oneline(name, 0, 0);
366 		printf("Certificate issuer: %s\n", str);
367 		free(str);
368 	}
369 
370 	return (0);
371 #else
372 	(void)conn;
373 	(void)verbose;
374 	fprintf(stderr, "SSL support disabled\n");
375 	return (-1);
376 #endif
377 }
378 
379 #define FETCH_READ_WAIT		-2
380 #define FETCH_READ_ERROR	-1
381 #define FETCH_READ_DONE		 0
382 
383 #ifdef WITH_SSL
384 static ssize_t
385 fetch_ssl_read(SSL *ssl, char *buf, size_t len)
386 {
387 	ssize_t rlen;
388 	int ssl_err;
389 
390 	rlen = SSL_read(ssl, buf, len);
391 	if (rlen < 0) {
392 		ssl_err = SSL_get_error(ssl, rlen);
393 		if (ssl_err == SSL_ERROR_WANT_READ ||
394 		    ssl_err == SSL_ERROR_WANT_WRITE) {
395 			return (FETCH_READ_WAIT);
396 		} else {
397 			ERR_print_errors_fp(stderr);
398 			return (FETCH_READ_ERROR);
399 		}
400 	}
401 	return (rlen);
402 }
403 #endif
404 
405 static ssize_t
406 fetch_socket_read(int sd, char *buf, size_t len)
407 {
408 	ssize_t rlen;
409 
410 	rlen = read(sd, buf, len);
411 	if (rlen < 0) {
412 		if (errno == EAGAIN || (errno == EINTR && fetchRestartCalls))
413 			return (FETCH_READ_WAIT);
414 		else
415 			return (FETCH_READ_ERROR);
416 	}
417 	return (rlen);
418 }
419 
420 /*
421  * Read a character from a connection w/ timeout
422  */
423 ssize_t
424 fetch_read(conn_t *conn, char *buf, size_t len)
425 {
426 	struct timeval now, timeout, delta;
427 	fd_set readfds;
428 	ssize_t rlen, total;
429 	int r;
430 
431 	if (fetchTimeout) {
432 		FD_ZERO(&readfds);
433 		gettimeofday(&timeout, NULL);
434 		timeout.tv_sec += fetchTimeout;
435 	}
436 
437 	total = 0;
438 	while (len > 0) {
439 		/*
440 		 * The socket is non-blocking.  Instead of the canonical
441 		 * select() -> read(), we do the following:
442 		 *
443 		 * 1) call read() or SSL_read().
444 		 * 2) if an error occurred, return -1.
445 		 * 3) if we received data but we still expect more,
446 		 *    update our counters and loop.
447 		 * 4) if read() or SSL_read() signaled EOF, return.
448 		 * 5) if we did not receive any data but we're not at EOF,
449 		 *    call select().
450 		 *
451 		 * In the SSL case, this is necessary because if we
452 		 * receive a close notification, we have to call
453 		 * SSL_read() one additional time after we've read
454 		 * everything we received.
455 		 *
456 		 * In the non-SSL case, it may improve performance (very
457 		 * slightly) when reading small amounts of data.
458 		 */
459 #ifdef WITH_SSL
460 		if (conn->ssl != NULL)
461 			rlen = fetch_ssl_read(conn->ssl, buf, len);
462 		else
463 #endif
464 			rlen = fetch_socket_read(conn->sd, buf, len);
465 		if (rlen == 0) {
466 			break;
467 		} else if (rlen > 0) {
468 			len -= rlen;
469 			buf += rlen;
470 			total += rlen;
471 			continue;
472 		} else if (rlen == FETCH_READ_ERROR) {
473 			return (-1);
474 		}
475 		// assert(rlen == FETCH_READ_WAIT);
476 		while (fetchTimeout && !FD_ISSET(conn->sd, &readfds)) {
477 			FD_SET(conn->sd, &readfds);
478 			gettimeofday(&now, NULL);
479 			delta.tv_sec = timeout.tv_sec - now.tv_sec;
480 			delta.tv_usec = timeout.tv_usec - now.tv_usec;
481 			if (delta.tv_usec < 0) {
482 				delta.tv_usec += 1000000;
483 				delta.tv_sec--;
484 			}
485 			if (delta.tv_sec < 0) {
486 				errno = ETIMEDOUT;
487 				fetch_syserr();
488 				return (-1);
489 			}
490 			errno = 0;
491 			r = select(conn->sd + 1, &readfds, NULL, NULL, &delta);
492 			if (r == -1) {
493 				if (errno == EINTR && fetchRestartCalls)
494 					continue;
495 				fetch_syserr();
496 				return (-1);
497 			}
498 		}
499 	}
500 	return (total);
501 }
502 
503 
504 /*
505  * Read a line of text from a connection w/ timeout
506  */
507 #define MIN_BUF_SIZE 1024
508 
509 int
510 fetch_getln(conn_t *conn)
511 {
512 	char *tmp;
513 	size_t tmpsize;
514 	ssize_t len;
515 	char c;
516 
517 	if (conn->buf == NULL) {
518 		if ((conn->buf = malloc(MIN_BUF_SIZE)) == NULL) {
519 			errno = ENOMEM;
520 			return (-1);
521 		}
522 		conn->bufsize = MIN_BUF_SIZE;
523 	}
524 
525 	conn->buf[0] = '\0';
526 	conn->buflen = 0;
527 
528 	do {
529 		len = fetch_read(conn, &c, 1);
530 		if (len == -1)
531 			return (-1);
532 		if (len == 0)
533 			break;
534 		conn->buf[conn->buflen++] = c;
535 		if (conn->buflen == conn->bufsize) {
536 			tmp = conn->buf;
537 			tmpsize = conn->bufsize * 2 + 1;
538 			if ((tmp = realloc(tmp, tmpsize)) == NULL) {
539 				errno = ENOMEM;
540 				return (-1);
541 			}
542 			conn->buf = tmp;
543 			conn->bufsize = tmpsize;
544 		}
545 	} while (c != '\n');
546 
547 	conn->buf[conn->buflen] = '\0';
548 	DEBUG(fprintf(stderr, "<<< %s", conn->buf));
549 	return (0);
550 }
551 
552 
553 /*
554  * Write to a connection w/ timeout
555  */
556 ssize_t
557 fetch_write(conn_t *conn, const char *buf, size_t len)
558 {
559 	struct iovec iov;
560 
561 	iov.iov_base = __DECONST(char *, buf);
562 	iov.iov_len = len;
563 	return fetch_writev(conn, &iov, 1);
564 }
565 
566 /*
567  * Write a vector to a connection w/ timeout
568  * Note: can modify the iovec.
569  */
570 ssize_t
571 fetch_writev(conn_t *conn, struct iovec *iov, int iovcnt)
572 {
573 	struct timeval now, timeout, delta;
574 	fd_set writefds;
575 	ssize_t wlen, total;
576 	int r;
577 
578 	if (fetchTimeout) {
579 		FD_ZERO(&writefds);
580 		gettimeofday(&timeout, NULL);
581 		timeout.tv_sec += fetchTimeout;
582 	}
583 
584 	total = 0;
585 	while (iovcnt > 0) {
586 		while (fetchTimeout && !FD_ISSET(conn->sd, &writefds)) {
587 			FD_SET(conn->sd, &writefds);
588 			gettimeofday(&now, NULL);
589 			delta.tv_sec = timeout.tv_sec - now.tv_sec;
590 			delta.tv_usec = timeout.tv_usec - now.tv_usec;
591 			if (delta.tv_usec < 0) {
592 				delta.tv_usec += 1000000;
593 				delta.tv_sec--;
594 			}
595 			if (delta.tv_sec < 0) {
596 				errno = ETIMEDOUT;
597 				fetch_syserr();
598 				return (-1);
599 			}
600 			errno = 0;
601 			r = select(conn->sd + 1, NULL, &writefds, NULL, &delta);
602 			if (r == -1) {
603 				if (errno == EINTR && fetchRestartCalls)
604 					continue;
605 				return (-1);
606 			}
607 		}
608 		errno = 0;
609 #ifdef WITH_SSL
610 		if (conn->ssl != NULL)
611 			wlen = SSL_write(conn->ssl,
612 			    iov->iov_base, iov->iov_len);
613 		else
614 #endif
615 			wlen = writev(conn->sd, iov, iovcnt);
616 		if (wlen == 0) {
617 			/* we consider a short write a failure */
618 			/* XXX perhaps we shouldn't in the SSL case */
619 			errno = EPIPE;
620 			fetch_syserr();
621 			return (-1);
622 		}
623 		if (wlen < 0) {
624 			if (errno == EINTR && fetchRestartCalls)
625 				continue;
626 			return (-1);
627 		}
628 		total += wlen;
629 		while (iovcnt > 0 && wlen >= (ssize_t)iov->iov_len) {
630 			wlen -= iov->iov_len;
631 			iov++;
632 			iovcnt--;
633 		}
634 		if (iovcnt > 0) {
635 			iov->iov_len -= wlen;
636 			iov->iov_base = __DECONST(char *, iov->iov_base) + wlen;
637 		}
638 	}
639 	return (total);
640 }
641 
642 
643 /*
644  * Write a line of text to a connection w/ timeout
645  */
646 int
647 fetch_putln(conn_t *conn, const char *str, size_t len)
648 {
649 	struct iovec iov[2];
650 	int ret;
651 
652 	DEBUG(fprintf(stderr, ">>> %s\n", str));
653 	iov[0].iov_base = __DECONST(char *, str);
654 	iov[0].iov_len = len;
655 	iov[1].iov_base = __DECONST(char *, ENDL);
656 	iov[1].iov_len = sizeof(ENDL);
657 	if (len == 0)
658 		ret = fetch_writev(conn, &iov[1], 1);
659 	else
660 		ret = fetch_writev(conn, iov, 2);
661 	if (ret == -1)
662 		return (-1);
663 	return (0);
664 }
665 
666 
667 /*
668  * Close connection
669  */
670 int
671 fetch_close(conn_t *conn)
672 {
673 	int ret;
674 
675 	if (--conn->ref > 0)
676 		return (0);
677 	ret = close(conn->sd);
678 	free(conn->buf);
679 	free(conn);
680 	return (ret);
681 }
682 
683 
684 /*** Directory-related utility functions *************************************/
685 
686 int
687 fetch_add_entry(struct url_ent **p, int *size, int *len,
688     const char *name, struct url_stat *us)
689 {
690 	struct url_ent *tmp;
691 
692 	if (*p == NULL) {
693 		*size = 0;
694 		*len = 0;
695 	}
696 
697 	if (*len >= *size - 1) {
698 		tmp = realloc(*p, (*size * 2 + 1) * sizeof(**p));
699 		if (tmp == NULL) {
700 			errno = ENOMEM;
701 			fetch_syserr();
702 			return (-1);
703 		}
704 		*size = (*size * 2 + 1);
705 		*p = tmp;
706 	}
707 
708 	tmp = *p + *len;
709 	snprintf(tmp->name, PATH_MAX, "%s", name);
710 	memcpy(&tmp->stat, us, sizeof(*us));
711 
712 	(*len)++;
713 	(++tmp)->name[0] = 0;
714 
715 	return (0);
716 }
717 
718 
719 /*** Authentication-related utility functions ********************************/
720 
721 static const char *
722 fetch_read_word(FILE *f)
723 {
724 	static char word[1024];
725 
726 	if (fscanf(f, " %1023s ", word) != 1)
727 		return (NULL);
728 	return (word);
729 }
730 
731 /*
732  * Get authentication data for a URL from .netrc
733  */
734 int
735 fetch_netrc_auth(struct url *url)
736 {
737 	char fn[PATH_MAX];
738 	const char *word;
739 	char *p;
740 	FILE *f;
741 
742 	if ((p = getenv("NETRC")) != NULL) {
743 		if (snprintf(fn, sizeof(fn), "%s", p) >= (int)sizeof(fn)) {
744 			fetch_info("$NETRC specifies a file name "
745 			    "longer than PATH_MAX");
746 			return (-1);
747 		}
748 	} else {
749 		if ((p = getenv("HOME")) != NULL) {
750 			struct passwd *pwd;
751 
752 			if ((pwd = getpwuid(getuid())) == NULL ||
753 			    (p = pwd->pw_dir) == NULL)
754 				return (-1);
755 		}
756 		if (snprintf(fn, sizeof(fn), "%s/.netrc", p) >= (int)sizeof(fn))
757 			return (-1);
758 	}
759 
760 	if ((f = fopen(fn, "r")) == NULL)
761 		return (-1);
762 	while ((word = fetch_read_word(f)) != NULL) {
763 		if (strcmp(word, "default") == 0) {
764 			DEBUG(fetch_info("Using default .netrc settings"));
765 			break;
766 		}
767 		if (strcmp(word, "machine") == 0 &&
768 		    (word = fetch_read_word(f)) != NULL &&
769 		    strcasecmp(word, url->host) == 0) {
770 			DEBUG(fetch_info("Using .netrc settings for %s", word));
771 			break;
772 		}
773 	}
774 	if (word == NULL)
775 		goto ferr;
776 	while ((word = fetch_read_word(f)) != NULL) {
777 		if (strcmp(word, "login") == 0) {
778 			if ((word = fetch_read_word(f)) == NULL)
779 				goto ferr;
780 			if (snprintf(url->user, sizeof(url->user),
781 				"%s", word) > (int)sizeof(url->user)) {
782 				fetch_info("login name in .netrc is too long");
783 				url->user[0] = '\0';
784 			}
785 		} else if (strcmp(word, "password") == 0) {
786 			if ((word = fetch_read_word(f)) == NULL)
787 				goto ferr;
788 			if (snprintf(url->pwd, sizeof(url->pwd),
789 				"%s", word) > (int)sizeof(url->pwd)) {
790 				fetch_info("password in .netrc is too long");
791 				url->pwd[0] = '\0';
792 			}
793 		} else if (strcmp(word, "account") == 0) {
794 			if ((word = fetch_read_word(f)) == NULL)
795 				goto ferr;
796 			/* XXX not supported! */
797 		} else {
798 			break;
799 		}
800 	}
801 	fclose(f);
802 	return (0);
803  ferr:
804 	fclose(f);
805 	return (-1);
806 }
807 
808 /*
809  * The no_proxy environment variable specifies a set of domains for
810  * which the proxy should not be consulted; the contents is a comma-,
811  * or space-separated list of domain names.  A single asterisk will
812  * override all proxy variables and no transactions will be proxied
813  * (for compatability with lynx and curl, see the discussion at
814  * <http://curl.haxx.se/mail/archive_pre_oct_99/0009.html>).
815  */
816 int
817 fetch_no_proxy_match(const char *host)
818 {
819 	const char *no_proxy, *p, *q;
820 	size_t h_len, d_len;
821 
822 	if ((no_proxy = getenv("NO_PROXY")) == NULL &&
823 	    (no_proxy = getenv("no_proxy")) == NULL)
824 		return (0);
825 
826 	/* asterisk matches any hostname */
827 	if (strcmp(no_proxy, "*") == 0)
828 		return (1);
829 
830 	h_len = strlen(host);
831 	p = no_proxy;
832 	do {
833 		/* position p at the beginning of a domain suffix */
834 		while (*p == ',' || isspace((unsigned char)*p))
835 			p++;
836 
837 		/* position q at the first separator character */
838 		for (q = p; *q; ++q)
839 			if (*q == ',' || isspace((unsigned char)*q))
840 				break;
841 
842 		d_len = q - p;
843 		if (d_len > 0 && h_len >= d_len &&
844 		    strncasecmp(host + h_len - d_len,
845 			p, d_len) == 0) {
846 			/* domain name matches */
847 			return (1);
848 		}
849 
850 		p = q + 1;
851 	} while (*q);
852 
853 	return (0);
854 }
855