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