1 /* $NetBSD: common.c,v 1.7 2024/02/02 22:19:05 christos Exp $ */
2 /*-
3 * Copyright (c) 1998-2004 Dag-Erling Co�dan Sm�rgrav
4 * Copyright (c) 2008, 2010 Joerg Sonnenberger <joerg@NetBSD.org>
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer
12 * in this position and unchanged.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 *
30 * $FreeBSD: common.c,v 1.53 2007/12/19 00:26:36 des Exp $
31 */
32
33 #if HAVE_CONFIG_H
34 #include "config.h"
35 #endif
36 #ifndef NETBSD
37 #include <nbcompat.h>
38 #endif
39
40 #include <sys/types.h>
41 #include <sys/socket.h>
42 #include <sys/time.h>
43 #include <sys/uio.h>
44 #if defined(HAVE_POLL_H) || defined(NETBSD)
45 #include <poll.h>
46 #define HAVE_POLL
47 #elif HAVE_SYS_POLL_H
48 #define HAVE_POLL
49 #include <sys/poll.h>
50 #endif
51
52 #include <netinet/in.h>
53 #include <arpa/inet.h>
54
55 #include <ctype.h>
56 #include <errno.h>
57 #if defined(HAVE_INTTYPES_H) || defined(NETBSD)
58 #include <inttypes.h>
59 #endif
60 #ifndef NETBSD
61 #include <nbcompat/netdb.h>
62 #else
63 #include <netdb.h>
64 #endif
65 #include <pwd.h>
66 #include <stdarg.h>
67 #include <stdlib.h>
68 #include <stdio.h>
69 #include <string.h>
70 #include <unistd.h>
71
72 #ifndef MSG_NOSIGNAL
73 #include <signal.h>
74 #endif
75
76 #include "fetch.h"
77 #include "common.h"
78
79 /*** Local data **************************************************************/
80
81 /*
82 * Error messages for resolver errors
83 */
84 static struct fetcherr netdb_errlist[] = {
85 #ifdef EAI_NODATA
86 { EAI_NODATA, FETCH_RESOLV, "Host not found" },
87 #endif
88 { EAI_AGAIN, FETCH_TEMP, "Transient resolver failure" },
89 { EAI_FAIL, FETCH_RESOLV, "Non-recoverable resolver failure" },
90 { EAI_NONAME, FETCH_RESOLV, "No address record" },
91 { -1, FETCH_UNKNOWN, "Unknown resolver error" }
92 };
93
94 /*** Error-reporting functions ***********************************************/
95
96 /*
97 * Map error code to string
98 */
99 static struct fetcherr *
fetch_finderr(struct fetcherr * p,int e)100 fetch_finderr(struct fetcherr *p, int e)
101 {
102 while (p->num != -1 && p->num != e)
103 p++;
104 return (p);
105 }
106
107 /*
108 * Set error code
109 */
110 void
fetch_seterr(struct fetcherr * p,int e)111 fetch_seterr(struct fetcherr *p, int e)
112 {
113 p = fetch_finderr(p, e);
114 fetchLastErrCode = p->cat;
115 snprintf(fetchLastErrString, MAXERRSTRING, "%s", p->string);
116 }
117
118 /*
119 * Set error code according to errno
120 */
121 void
fetch_syserr(void)122 fetch_syserr(void)
123 {
124 switch (errno) {
125 case 0:
126 fetchLastErrCode = FETCH_OK;
127 break;
128 case EPERM:
129 case EACCES:
130 case EROFS:
131 #ifdef EAUTH
132 case EAUTH:
133 #endif
134 #ifdef ENEEDAUTH
135 case ENEEDAUTH:
136 #endif
137 fetchLastErrCode = FETCH_AUTH;
138 break;
139 case ENOENT:
140 case EISDIR: /* XXX */
141 fetchLastErrCode = FETCH_UNAVAIL;
142 break;
143 case ENOMEM:
144 fetchLastErrCode = FETCH_MEMORY;
145 break;
146 case EBUSY:
147 case EAGAIN:
148 fetchLastErrCode = FETCH_TEMP;
149 break;
150 case EEXIST:
151 fetchLastErrCode = FETCH_EXISTS;
152 break;
153 case ENOSPC:
154 fetchLastErrCode = FETCH_FULL;
155 break;
156 case EADDRINUSE:
157 case EADDRNOTAVAIL:
158 case ENETDOWN:
159 case ENETUNREACH:
160 case ENETRESET:
161 case EHOSTUNREACH:
162 fetchLastErrCode = FETCH_NETWORK;
163 break;
164 case ECONNABORTED:
165 case ECONNRESET:
166 fetchLastErrCode = FETCH_ABORT;
167 break;
168 case ETIMEDOUT:
169 fetchLastErrCode = FETCH_TIMEOUT;
170 break;
171 case ECONNREFUSED:
172 case EHOSTDOWN:
173 fetchLastErrCode = FETCH_DOWN;
174 break;
175 default:
176 fetchLastErrCode = FETCH_UNKNOWN;
177 }
178 snprintf(fetchLastErrString, MAXERRSTRING, "%s", strerror(errno));
179 }
180
181
182 /*
183 * Emit status message
184 */
185 void
fetch_info(const char * fmt,...)186 fetch_info(const char *fmt, ...)
187 {
188 va_list ap;
189
190 va_start(ap, fmt);
191 vfprintf(stderr, fmt, ap);
192 va_end(ap);
193 fputc('\n', stderr);
194 }
195
196
197 /*** Network-related utility functions ***************************************/
198
199 /*
200 * Return the default port for a scheme
201 */
202 int
fetch_default_port(const char * scheme)203 fetch_default_port(const char *scheme)
204 {
205 struct servent *se;
206
207 if ((se = getservbyname(scheme, "tcp")) != NULL)
208 return (ntohs(se->s_port));
209 if (strcasecmp(scheme, SCHEME_FTP) == 0)
210 return (FTP_DEFAULT_PORT);
211 if (strcasecmp(scheme, SCHEME_HTTP) == 0)
212 return (HTTP_DEFAULT_PORT);
213 return (0);
214 }
215
216 /*
217 * Return the default proxy port for a scheme
218 */
219 int
fetch_default_proxy_port(const char * scheme)220 fetch_default_proxy_port(const char *scheme)
221 {
222 if (strcasecmp(scheme, SCHEME_FTP) == 0)
223 return (FTP_DEFAULT_PROXY_PORT);
224 if (strcasecmp(scheme, SCHEME_HTTP) == 0)
225 return (HTTP_DEFAULT_PROXY_PORT);
226 return (0);
227 }
228
229
230 /*
231 * Create a connection for an existing descriptor.
232 */
233 conn_t *
fetch_reopen(int sd)234 fetch_reopen(int sd)
235 {
236 conn_t *conn;
237
238 /* allocate and fill connection structure */
239 if ((conn = calloc(1, sizeof(*conn))) == NULL)
240 return (NULL);
241 conn->ftp_home = NULL;
242 conn->cache_url = NULL;
243 conn->next_buf = NULL;
244 conn->next_len = 0;
245 conn->sd = sd;
246 #ifdef HAVE_POLL
247 conn->buf_events = POLLIN;
248 #endif
249 return (conn);
250 }
251
252
253 /*
254 * Bind a socket to a specific local address
255 */
256 int
fetch_bind(int sd,int af,const char * addr)257 fetch_bind(int sd, int af, const char *addr)
258 {
259 struct addrinfo hints, *res, *res0;
260
261 memset(&hints, 0, sizeof(hints));
262 hints.ai_family = af;
263 hints.ai_socktype = SOCK_STREAM;
264 hints.ai_protocol = 0;
265 if (getaddrinfo(addr, NULL, &hints, &res0))
266 return (-1);
267 for (res = res0; res; res = res->ai_next) {
268 if (bind(sd, res->ai_addr, res->ai_addrlen) == 0)
269 return (0);
270 }
271 return (-1);
272 }
273
274
275 /*
276 * Establish a TCP connection to the specified port on the specified host.
277 */
278 conn_t *
fetch_connect(struct url * url,int af,int verbose)279 fetch_connect(struct url *url, int af, int verbose)
280 {
281 conn_t *conn;
282 char pbuf[10];
283 const char *bindaddr;
284 struct addrinfo hints, *res, *res0;
285 int sd, error;
286
287 if (verbose)
288 fetch_info("looking up %s", url->host);
289
290 /* look up host name and set up socket address structure */
291 snprintf(pbuf, sizeof(pbuf), "%d", url->port);
292 memset(&hints, 0, sizeof(hints));
293 hints.ai_family = af;
294 hints.ai_socktype = SOCK_STREAM;
295 hints.ai_protocol = 0;
296 if ((error = getaddrinfo(url->host, pbuf, &hints, &res0)) != 0) {
297 netdb_seterr(error);
298 return (NULL);
299 }
300 bindaddr = getenv("FETCH_BIND_ADDRESS");
301
302 if (verbose)
303 fetch_info("connecting to %s:%d", url->host, url->port);
304
305 /* try to connect */
306 for (sd = -1, res = res0; res; sd = -1, res = res->ai_next) {
307 if ((sd = socket(res->ai_family, res->ai_socktype,
308 res->ai_protocol)) == -1)
309 continue;
310 if (bindaddr != NULL && *bindaddr != '\0' &&
311 fetch_bind(sd, res->ai_family, bindaddr) != 0) {
312 fetch_info("failed to bind to '%s'", bindaddr);
313 close(sd);
314 continue;
315 }
316 if (connect(sd, res->ai_addr, res->ai_addrlen) == 0)
317 break;
318 close(sd);
319 }
320 freeaddrinfo(res0);
321 if (sd == -1) {
322 fetch_syserr();
323 return (NULL);
324 }
325
326 if ((conn = fetch_reopen(sd)) == NULL) {
327 fetch_syserr();
328 close(sd);
329 return (NULL);
330 }
331 conn->cache_url = fetchCopyURL(url);
332 conn->cache_af = af;
333 return (conn);
334 }
335
336 static conn_t *connection_cache;
337 static int cache_global_limit = 0;
338 static int cache_per_host_limit = 0;
339
340 /*
341 * Initialise cache with the given limits.
342 */
343 void
fetchConnectionCacheInit(int global_limit,int per_host_limit)344 fetchConnectionCacheInit(int global_limit, int per_host_limit)
345 {
346
347 if (global_limit < 0)
348 cache_global_limit = INT_MAX;
349 else if (per_host_limit > global_limit)
350 cache_global_limit = per_host_limit;
351 else
352 cache_global_limit = global_limit;
353 if (per_host_limit < 0)
354 cache_per_host_limit = INT_MAX;
355 else
356 cache_per_host_limit = per_host_limit;
357 }
358
359 /*
360 * Flush cache and free all associated resources.
361 */
362 void
fetchConnectionCacheClose(void)363 fetchConnectionCacheClose(void)
364 {
365 conn_t *conn;
366
367 while ((conn = connection_cache) != NULL) {
368 connection_cache = conn->next_cached;
369 (*conn->cache_close)(conn);
370 }
371 }
372
373 /*
374 * Check connection cache for an existing entry matching
375 * protocol/host/port/user/password/family.
376 */
377 conn_t *
fetch_cache_get(const struct url * url,int af)378 fetch_cache_get(const struct url *url, int af)
379 {
380 conn_t *conn, *last_conn = NULL;
381
382 for (conn = connection_cache; conn; last_conn = conn,
383 conn = conn->next_cached)
384 {
385 if (conn->cache_url->port == url->port &&
386 strcmp(conn->cache_url->scheme, url->scheme) == 0 &&
387 strcmp(conn->cache_url->host, url->host) == 0 &&
388 strcmp(conn->cache_url->user, url->user) == 0 &&
389 strcmp(conn->cache_url->pwd, url->pwd) == 0 &&
390 (conn->cache_af == AF_UNSPEC || af == AF_UNSPEC ||
391 conn->cache_af == af)) {
392 if (last_conn != NULL)
393 last_conn->next_cached = conn->next_cached;
394 else
395 connection_cache = conn->next_cached;
396 return conn;
397 }
398 }
399
400 return NULL;
401 }
402
403 /*
404 * Put the connection back into the cache for reuse.
405 * If the connection is freed due to LRU or if the cache
406 * is explicitly closed, the given callback is called.
407 */
408 void
fetch_cache_put(conn_t * conn,int (* closecb)(conn_t *))409 fetch_cache_put(conn_t *conn, int (*closecb)(conn_t *))
410 {
411 conn_t *iter, *last, *oiter;
412 int global_count, host_count, added;
413
414 if (conn->cache_url == NULL || cache_global_limit == 0) {
415 (*closecb)(conn);
416 return;
417 }
418
419 global_count = host_count = 0;
420 last = NULL;
421 for (iter = connection_cache; iter; ) {
422 ++global_count;
423 added = !strcmp(conn->cache_url->host, iter->cache_url->host);
424 if (added)
425 ++host_count;
426 if (global_count < cache_global_limit &&
427 host_count < cache_per_host_limit) {
428 oiter = NULL;
429 last = iter;
430 } else {
431 --global_count;
432 if (added)
433 --host_count;
434 if (last != NULL)
435 last->next_cached = iter->next_cached;
436 else
437 connection_cache = iter->next_cached;
438 oiter = iter;
439 }
440 iter = iter->next_cached;
441 if (oiter)
442 (*oiter->cache_close)(oiter);
443 }
444
445 conn->cache_close = closecb;
446 conn->next_cached = connection_cache;
447 connection_cache = conn;
448 }
449
450 /*
451 * Enable SSL on a connection.
452 */
453 int
fetch_ssl(conn_t * conn,const struct url * URL,int verbose)454 fetch_ssl(conn_t *conn, const struct url *URL, int verbose)
455 {
456
457 #ifdef WITH_SSL
458 /* Init the SSL library and context */
459 if (!SSL_library_init()){
460 fprintf(stderr, "SSL library init failed\n");
461 return (-1);
462 }
463
464 SSL_load_error_strings();
465
466 conn->ssl_meth = SSLv23_client_method();
467 conn->ssl_ctx = SSL_CTX_new(conn->ssl_meth);
468 SSL_CTX_set_mode(conn->ssl_ctx, SSL_MODE_AUTO_RETRY);
469 if (getenv("SSL_NO_VERIFY_PEER") == NULL) {
470 SSL_CTX_set_default_verify_paths(conn->ssl_ctx);
471 SSL_CTX_set_verify(conn->ssl_ctx, SSL_VERIFY_PEER, NULL);
472 }
473
474 conn->ssl = SSL_new(conn->ssl_ctx);
475 if (conn->ssl == NULL){
476 fprintf(stderr, "SSL context creation failed\n");
477 return (-1);
478 }
479 conn->buf_events = 0;
480 SSL_set_fd(conn->ssl, conn->sd);
481 #if OPENSSL_VERSION_NUMBER >= 0x0090806fL && !defined(OPENSSL_NO_TLSEXT)
482 if (!SSL_set_tlsext_host_name(conn->ssl, (char *)(uintptr_t)URL->host))
483 {
484 fprintf(stderr,
485 "TLS server name indication extension failed for host %s\n",
486 URL->host);
487 return (-1);
488 }
489 #endif
490 if (SSL_connect(conn->ssl) == -1){
491 ERR_print_errors_fp(stderr);
492 return (-1);
493 }
494
495 if (verbose) {
496 X509_NAME *name;
497 char *str;
498
499 fprintf(stderr, "SSL connection established using %s\n",
500 SSL_get_cipher(conn->ssl));
501 conn->ssl_cert = SSL_get_peer_certificate(conn->ssl);
502 name = X509_get_subject_name(conn->ssl_cert);
503 str = X509_NAME_oneline(name, 0, 0);
504 printf("Certificate subject: %s\n", str);
505 free(str);
506 name = X509_get_issuer_name(conn->ssl_cert);
507 str = X509_NAME_oneline(name, 0, 0);
508 printf("Certificate issuer: %s\n", str);
509 free(str);
510 }
511
512 return (0);
513 #else
514 (void)conn;
515 (void)verbose;
516 fprintf(stderr, "SSL support disabled\n");
517 return (-1);
518 #endif
519 }
520
521 #ifdef HAVE_POLL
522 static int
compute_timeout(const struct timeval * tv)523 compute_timeout(const struct timeval *tv)
524 {
525 struct timeval cur;
526
527 gettimeofday(&cur, NULL);
528 return (tv->tv_sec - cur.tv_sec) * 1000
529 + (tv->tv_usec - cur.tv_usec) / 1000;
530 }
531 #endif
532
533 /*
534 * Read a character from a connection w/ timeout
535 */
536 ssize_t
fetch_read(conn_t * conn,char * buf,size_t len)537 fetch_read(conn_t *conn, char *buf, size_t len)
538 {
539 struct timeval timeout_end;
540 #ifdef HAVE_POLL
541 struct pollfd pfd;
542 #else
543 fd_set readfds;
544 #endif
545 int timeout_cur;
546 ssize_t rlen;
547 int r;
548
549 if (len == 0)
550 return 0;
551
552 if (conn->next_len != 0) {
553 if (conn->next_len < len)
554 len = conn->next_len;
555 memmove(buf, conn->next_buf, len);
556 conn->next_len -= len;
557 conn->next_buf += len;
558 return len;
559 }
560
561 if (fetchTimeout) {
562 #ifndef HAVE_POLL
563 FD_ZERO(&readfds);
564 #endif
565 gettimeofday(&timeout_end, NULL);
566 timeout_end.tv_sec += fetchTimeout;
567 }
568
569 for (;;) {
570 #ifdef HAVE_POLL
571 pfd.fd = conn->sd;
572 pfd.events = conn->buf_events;
573 if (fetchTimeout && pfd.events) {
574 do {
575 timeout_cur = compute_timeout(&timeout_end);
576 if (timeout_cur < 0) {
577 errno = ETIMEDOUT;
578 fetch_syserr();
579 return (-1);
580 }
581 errno = 0;
582 r = poll(&pfd, 1, timeout_cur);
583 if (r == -1) {
584 if (errno == EINTR && fetchRestartCalls)
585 continue;
586 fetch_syserr();
587 return (-1);
588 }
589 } while (pfd.revents == 0);
590 #else
591 while (fetchTimeout && !FD_ISSET(conn->sd, &readfds)) {
592 struct timeval waittv, now;
593 FD_SET(conn->sd, &readfds);
594 gettimeofday(&now, NULL);
595 waittv.tv_sec = timeout_end.tv_sec - now.tv_sec;
596 waittv.tv_usec = timeout_end.tv_usec - now.tv_usec;
597 if (waittv.tv_usec < 0) {
598 waittv.tv_usec += 1000000;
599 waittv.tv_sec--;
600 }
601 if (waittv.tv_sec < 0) {
602 errno = ETIMEDOUT;
603 fetch_syserr();
604 return (-1);
605 }
606 errno = 0;
607 r = select(conn->sd + 1, &readfds, NULL, NULL, &waittv);
608 if (r == -1) {
609 if (errno == EINTR && fetchRestartCalls)
610 continue;
611 fetch_syserr();
612 return (-1);
613 }
614 #endif
615 }
616 #ifdef WITH_SSL
617 if (conn->ssl != NULL) {
618 rlen = SSL_read(conn->ssl, buf, len);
619 if (rlen == -1) {
620 switch (SSL_get_error(conn->ssl, rlen)) {
621 case SSL_ERROR_WANT_READ:
622 conn->buf_events = POLLIN;
623 break;
624 case SSL_ERROR_WANT_WRITE:
625 conn->buf_events = POLLOUT;
626 break;
627 default:
628 errno = EIO;
629 fetch_syserr();
630 return -1;
631 }
632 } else {
633 /* Assume buffering on the SSL layer. */
634 conn->buf_events = 0;
635 }
636 } else
637 #endif
638 rlen = read(conn->sd, buf, len);
639 if (rlen >= 0)
640 break;
641
642 if (errno != EINTR || !fetchRestartCalls)
643 return (-1);
644 }
645 return (rlen);
646 }
647
648
649 /*
650 * Read a line of text from a connection w/ timeout
651 */
652 #define MIN_BUF_SIZE 1024
653
654 int
655 fetch_getln(conn_t *conn)
656 {
657 char *tmp, *next;
658 size_t tmpsize;
659 ssize_t len;
660
661 if (conn->buf == NULL) {
662 if ((conn->buf = malloc(MIN_BUF_SIZE)) == NULL) {
663 errno = ENOMEM;
664 return (-1);
665 }
666 conn->bufsize = MIN_BUF_SIZE;
667 }
668
669 conn->buflen = 0;
670 next = NULL;
671
672 do {
673 /*
674 * conn->bufsize != conn->buflen at this point,
675 * so the buffer can be NUL-terminated below for
676 * the case of len == 0.
677 */
678 len = fetch_read(conn, conn->buf + conn->buflen,
679 conn->bufsize - conn->buflen);
680 if (len == -1)
681 return (-1);
682 if (len == 0)
683 break;
684 next = memchr(conn->buf + conn->buflen, '\n', (size_t)len);
685 conn->buflen += len;
686 if (conn->buflen == conn->bufsize && next == NULL) {
687 tmp = conn->buf;
688 tmpsize = conn->bufsize * 2;
689 if (tmpsize < conn->bufsize) {
690 errno = ENOMEM;
691 return (-1);
692 }
693 if ((tmp = realloc(tmp, tmpsize)) == NULL) {
694 errno = ENOMEM;
695 return (-1);
696 }
697 conn->buf = tmp;
698 conn->bufsize = tmpsize;
699 }
700 } while (next == NULL);
701
702 if (next != NULL) {
703 *next = '\0';
704 conn->next_buf = next + 1;
705 conn->next_len = conn->buflen - (conn->next_buf - conn->buf);
706 conn->buflen = next - conn->buf;
707 } else {
708 conn->buf[conn->buflen] = '\0';
709 conn->next_len = 0;
710 }
711 return (0);
712 }
713
714 /*
715 * Write a vector to a connection w/ timeout
716 * Note: can modify the iovec.
717 */
718 ssize_t
719 fetch_write(conn_t *conn, const void *buf, size_t len)
720 {
721 struct timeval now, timeout, waittv;
722 fd_set writefds;
723 ssize_t wlen, total;
724 int r;
725 #ifndef MSG_NOSIGNAL
726 static int killed_sigpipe;
727 #endif
728
729 #ifndef MSG_NOSIGNAL
730 if (!killed_sigpipe) {
731 signal(SIGPIPE, SIG_IGN);
732 killed_sigpipe = 1;
733 }
734 #endif
735
736
737 if (fetchTimeout) {
738 FD_ZERO(&writefds);
739 gettimeofday(&timeout, NULL);
740 timeout.tv_sec += fetchTimeout;
741 }
742
743 total = 0;
744 while (len) {
745 while (fetchTimeout && !FD_ISSET(conn->sd, &writefds)) {
746 FD_SET(conn->sd, &writefds);
747 gettimeofday(&now, NULL);
748 waittv.tv_sec = timeout.tv_sec - now.tv_sec;
749 waittv.tv_usec = timeout.tv_usec - now.tv_usec;
750 if (waittv.tv_usec < 0) {
751 waittv.tv_usec += 1000000;
752 waittv.tv_sec--;
753 }
754 if (waittv.tv_sec < 0) {
755 errno = ETIMEDOUT;
756 fetch_syserr();
757 return (-1);
758 }
759 errno = 0;
760 r = select(conn->sd + 1, NULL, &writefds, NULL, &waittv);
761 if (r == -1) {
762 if (errno == EINTR && fetchRestartCalls)
763 continue;
764 return (-1);
765 }
766 }
767 errno = 0;
768 #ifdef WITH_SSL
769 if (conn->ssl != NULL)
770 wlen = SSL_write(conn->ssl, buf, (int)len);
771 else
772 #endif
773 #ifndef MSG_NOSIGNAL
774 wlen = send(conn->sd, buf, len, 0);
775 #else
776 wlen = send(conn->sd, buf, len, MSG_NOSIGNAL);
777 #endif
778 if (wlen == 0) {
779 /* we consider a short write a failure */
780 errno = EPIPE;
781 fetch_syserr();
782 return (-1);
783 }
784 if (wlen < 0) {
785 if (errno == EINTR && fetchRestartCalls)
786 continue;
787 return (-1);
788 }
789 total += wlen;
790 buf = (const char *)buf + wlen;
791 len -= wlen;
792 }
793 return (total);
794 }
795
796
797 /*
798 * Close connection
799 */
800 int
801 fetch_close(conn_t *conn)
802 {
803 int ret;
804
805 #ifdef WITH_SSL
806 if (conn->ssl) {
807 SSL_shutdown(conn->ssl);
808 SSL_set_connect_state(conn->ssl);
809 SSL_free(conn->ssl);
810 conn->ssl = NULL;
811 }
812 if (conn->ssl_ctx) {
813 SSL_CTX_free(conn->ssl_ctx);
814 conn->ssl_ctx = NULL;
815 }
816 if (conn->ssl_cert) {
817 X509_free(conn->ssl_cert);
818 conn->ssl_cert = NULL;
819 }
820 #endif
821 ret = close(conn->sd);
822 if (conn->cache_url)
823 fetchFreeURL(conn->cache_url);
824 free(conn->ftp_home);
825 free(conn->buf);
826 free(conn);
827 return (ret);
828 }
829
830
831 /*** Directory-related utility functions *************************************/
832
833 int
834 fetch_add_entry(struct url_list *ue, struct url *base, const char *name,
835 int pre_quoted)
836 {
837 struct url *tmp;
838 char *tmp_name;
839 size_t base_doc_len, name_len, i;
840 unsigned char c;
841
842 if (strchr(name, '/') != NULL ||
843 strcmp(name, "..") == 0 ||
844 strcmp(name, ".") == 0)
845 return 0;
846
847 if (strcmp(base->doc, "/") == 0)
848 base_doc_len = 0;
849 else
850 base_doc_len = strlen(base->doc);
851
852 name_len = 1;
853 for (i = 0; name[i] != '\0'; ++i) {
854 if ((!pre_quoted && name[i] == '%') ||
855 !fetch_urlpath_safe(name[i]))
856 name_len += 3;
857 else
858 ++name_len;
859 }
860
861 tmp_name = malloc( base_doc_len + name_len + 1);
862 if (tmp_name == NULL) {
863 errno = ENOMEM;
864 fetch_syserr();
865 return (-1);
866 }
867
868 if (ue->length + 1 >= ue->alloc_size) {
869 tmp = realloc(ue->urls, (ue->alloc_size * 2 + 1) * sizeof(*tmp));
870 if (tmp == NULL) {
871 free(tmp_name);
872 errno = ENOMEM;
873 fetch_syserr();
874 return (-1);
875 }
876 ue->alloc_size = ue->alloc_size * 2 + 1;
877 ue->urls = tmp;
878 }
879
880 tmp = ue->urls + ue->length;
881 strcpy(tmp->scheme, base->scheme);
882 strcpy(tmp->user, base->user);
883 strcpy(tmp->pwd, base->pwd);
884 strcpy(tmp->host, base->host);
885 tmp->port = base->port;
886 tmp->doc = tmp_name;
887 memcpy(tmp->doc, base->doc, base_doc_len);
888 tmp->doc[base_doc_len] = '/';
889
890 for (i = base_doc_len + 1; *name != '\0'; ++name) {
891 if ((!pre_quoted && *name == '%') ||
892 !fetch_urlpath_safe(*name)) {
893 tmp->doc[i++] = '%';
894 c = (unsigned char)*name / 16;
895 if (c < 10)
896 tmp->doc[i++] = '0' + c;
897 else
898 tmp->doc[i++] = 'a' - 10 + c;
899 c = (unsigned char)*name % 16;
900 if (c < 10)
901 tmp->doc[i++] = '0' + c;
902 else
903 tmp->doc[i++] = 'a' - 10 + c;
904 } else {
905 tmp->doc[i++] = *name;
906 }
907 }
908 tmp->doc[i] = '\0';
909
910 tmp->offset = 0;
911 tmp->length = 0;
912 tmp->last_modified = -1;
913
914 ++ue->length;
915
916 return (0);
917 }
918
919 void
920 fetchInitURLList(struct url_list *ue)
921 {
922 ue->length = ue->alloc_size = 0;
923 ue->urls = NULL;
924 }
925
926 int
927 fetchAppendURLList(struct url_list *dst, const struct url_list *src)
928 {
929 size_t i, j, len;
930
931 len = dst->length + src->length;
932 if (len > dst->alloc_size) {
933 struct url *tmp;
934
935 tmp = realloc(dst->urls, len * sizeof(*tmp));
936 if (tmp == NULL) {
937 errno = ENOMEM;
938 fetch_syserr();
939 return (-1);
940 }
941 dst->alloc_size = len;
942 dst->urls = tmp;
943 }
944
945 for (i = 0, j = dst->length; i < src->length; ++i, ++j) {
946 dst->urls[j] = src->urls[i];
947 dst->urls[j].doc = strdup(src->urls[i].doc);
948 if (dst->urls[j].doc == NULL) {
949 while (i-- > 0)
950 free(dst->urls[j].doc);
951 fetch_syserr();
952 return -1;
953 }
954 }
955 dst->length = len;
956
957 return 0;
958 }
959
960 void
961 fetchFreeURLList(struct url_list *ue)
962 {
963 size_t i;
964
965 for (i = 0; i < ue->length; ++i)
966 free(ue->urls[i].doc);
967 free(ue->urls);
968 ue->length = ue->alloc_size = 0;
969 }
970
971
972 /*** Authentication-related utility functions ********************************/
973
974 static const char *
975 fetch_read_word(FILE *f)
976 {
977 static char word[1024];
978
979 if (fscanf(f, " %1023s ", word) != 1)
980 return (NULL);
981 return (word);
982 }
983
984 /*
985 * Get authentication data for a URL from .netrc
986 */
987 int
988 fetch_netrc_auth(struct url *url)
989 {
990 char fn[PATH_MAX];
991 const char *word;
992 char *p;
993 FILE *f;
994
995 if ((p = getenv("NETRC")) != NULL) {
996 if (snprintf(fn, sizeof(fn), "%s", p) >= (int)sizeof(fn)) {
997 fetch_info("$NETRC specifies a file name "
998 "longer than PATH_MAX");
999 return (-1);
1000 }
1001 } else {
1002 if ((p = getenv("HOME")) != NULL) {
1003 struct passwd *pwd;
1004
1005 if ((pwd = getpwuid(getuid())) == NULL ||
1006 (p = pwd->pw_dir) == NULL)
1007 return (-1);
1008 }
1009 if (snprintf(fn, sizeof(fn), "%s/.netrc", p) >= (int)sizeof(fn))
1010 return (-1);
1011 }
1012
1013 if ((f = fopen(fn, "r")) == NULL)
1014 return (-1);
1015 while ((word = fetch_read_word(f)) != NULL) {
1016 if (strcmp(word, "default") == 0)
1017 break;
1018 if (strcmp(word, "machine") == 0 &&
1019 (word = fetch_read_word(f)) != NULL &&
1020 strcasecmp(word, url->host) == 0) {
1021 break;
1022 }
1023 }
1024 if (word == NULL)
1025 goto ferr;
1026 while ((word = fetch_read_word(f)) != NULL) {
1027 if (strcmp(word, "login") == 0) {
1028 if ((word = fetch_read_word(f)) == NULL)
1029 goto ferr;
1030 if (snprintf(url->user, sizeof(url->user),
1031 "%s", word) > (int)sizeof(url->user)) {
1032 fetch_info("login name in .netrc is too long");
1033 url->user[0] = '\0';
1034 }
1035 } else if (strcmp(word, "password") == 0) {
1036 if ((word = fetch_read_word(f)) == NULL)
1037 goto ferr;
1038 if (snprintf(url->pwd, sizeof(url->pwd),
1039 "%s", word) > (int)sizeof(url->pwd)) {
1040 fetch_info("password in .netrc is too long");
1041 url->pwd[0] = '\0';
1042 }
1043 } else if (strcmp(word, "account") == 0) {
1044 if ((word = fetch_read_word(f)) == NULL)
1045 goto ferr;
1046 /* XXX not supported! */
1047 } else {
1048 break;
1049 }
1050 }
1051 fclose(f);
1052 return (0);
1053 ferr:
1054 fclose(f);
1055 return (-1);
1056 }
1057
1058 /*
1059 * The no_proxy environment variable specifies a set of domains for
1060 * which the proxy should not be consulted; the contents is a comma-,
1061 * or space-separated list of domain names. A single asterisk will
1062 * override all proxy variables and no transactions will be proxied
1063 * (for compatability with lynx and curl, see the discussion at
1064 * <http://curl.haxx.se/mail/archive_pre_oct_99/0009.html>).
1065 */
1066 int
1067 fetch_no_proxy_match(const char *host)
1068 {
1069 const char *no_proxy, *p, *q;
1070 size_t h_len, d_len;
1071
1072 if ((no_proxy = getenv("NO_PROXY")) == NULL &&
1073 (no_proxy = getenv("no_proxy")) == NULL)
1074 return (0);
1075
1076 /* asterisk matches any hostname */
1077 if (strcmp(no_proxy, "*") == 0)
1078 return (1);
1079
1080 h_len = strlen(host);
1081 p = no_proxy;
1082 do {
1083 /* position p at the beginning of a domain suffix */
1084 while (*p == ',' || isspace((unsigned char)*p))
1085 p++;
1086
1087 /* position q at the first separator character */
1088 for (q = p; *q; ++q)
1089 if (*q == ',' || isspace((unsigned char)*q))
1090 break;
1091
1092 d_len = q - p;
1093 if (d_len > 0 && h_len > d_len &&
1094 strncasecmp(host + h_len - d_len,
1095 p, d_len) == 0) {
1096 /* domain name matches */
1097 return (1);
1098 }
1099
1100 p = q + 1;
1101 } while (*q);
1102
1103 return (0);
1104 }
1105
1106 struct fetchIO {
1107 void *io_cookie;
1108 ssize_t (*io_read)(void *, void *, size_t);
1109 ssize_t (*io_write)(void *, const void *, size_t);
1110 void (*io_close)(void *);
1111 };
1112
1113 void
1114 fetchIO_close(fetchIO *f)
1115 {
1116 if (f->io_close != NULL)
1117 (*f->io_close)(f->io_cookie);
1118
1119 free(f);
1120 }
1121
1122 fetchIO *
1123 fetchIO_unopen(void *io_cookie, ssize_t (*io_read)(void *, void *, size_t),
1124 ssize_t (*io_write)(void *, const void *, size_t),
1125 void (*io_close)(void *))
1126 {
1127 fetchIO *f;
1128
1129 f = malloc(sizeof(*f));
1130 if (f == NULL)
1131 return f;
1132
1133 f->io_cookie = io_cookie;
1134 f->io_read = io_read;
1135 f->io_write = io_write;
1136 f->io_close = io_close;
1137
1138 return f;
1139 }
1140
1141 ssize_t
1142 fetchIO_read(fetchIO *f, void *buf, size_t len)
1143 {
1144 if (f->io_read == NULL)
1145 return EBADF;
1146 return (*f->io_read)(f->io_cookie, buf, len);
1147 }
1148
1149 ssize_t
1150 fetchIO_write(fetchIO *f, const void *buf, size_t len)
1151 {
1152 if (f->io_read == NULL)
1153 return EBADF;
1154 return (*f->io_write)(f->io_cookie, buf, len);
1155 }
1156