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