1842a95ccSDag-Erling Smørgrav /*- 22cbbf9daSDag-Erling Smørgrav * Copyright (c) 1998-2004 Dag-Erling Co�dan Sm�rgrav 3842a95ccSDag-Erling Smørgrav * All rights reserved. 4842a95ccSDag-Erling Smørgrav * 5842a95ccSDag-Erling Smørgrav * Redistribution and use in source and binary forms, with or without 6842a95ccSDag-Erling Smørgrav * modification, are permitted provided that the following conditions 7842a95ccSDag-Erling Smørgrav * are met: 8842a95ccSDag-Erling Smørgrav * 1. Redistributions of source code must retain the above copyright 9842a95ccSDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer 10842a95ccSDag-Erling Smørgrav * in this position and unchanged. 11842a95ccSDag-Erling Smørgrav * 2. Redistributions in binary form must reproduce the above copyright 12842a95ccSDag-Erling Smørgrav * notice, this list of conditions and the following disclaimer in the 13842a95ccSDag-Erling Smørgrav * documentation and/or other materials provided with the distribution. 14842a95ccSDag-Erling Smørgrav * 3. The name of the author may not be used to endorse or promote products 15842a95ccSDag-Erling Smørgrav * derived from this software without specific prior written permission 16842a95ccSDag-Erling Smørgrav * 17842a95ccSDag-Erling Smørgrav * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 18842a95ccSDag-Erling Smørgrav * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 19842a95ccSDag-Erling Smørgrav * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 20842a95ccSDag-Erling Smørgrav * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 21842a95ccSDag-Erling Smørgrav * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 22842a95ccSDag-Erling Smørgrav * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 23842a95ccSDag-Erling Smørgrav * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 24842a95ccSDag-Erling Smørgrav * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 25842a95ccSDag-Erling Smørgrav * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 26842a95ccSDag-Erling Smørgrav * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 27842a95ccSDag-Erling Smørgrav */ 28842a95ccSDag-Erling Smørgrav 29cecb889fSMatthew Dillon #include <sys/cdefs.h> 30cecb889fSMatthew Dillon __FBSDID("$FreeBSD$"); 31cecb889fSMatthew Dillon 320fba3a00SDag-Erling Smørgrav #include <sys/param.h> 33842a95ccSDag-Erling Smørgrav #include <sys/socket.h> 34fc6e9e65SDag-Erling Smørgrav #include <sys/time.h> 35a1763027SDag-Erling Smørgrav #include <sys/uio.h> 3662a2681cSDag-Erling Smørgrav 37842a95ccSDag-Erling Smørgrav #include <netinet/in.h> 38842a95ccSDag-Erling Smørgrav 3962a2681cSDag-Erling Smørgrav #include <ctype.h> 40842a95ccSDag-Erling Smørgrav #include <errno.h> 41842a95ccSDag-Erling Smørgrav #include <netdb.h> 4207350d12SDag-Erling Smørgrav #include <pwd.h> 43ba101983SDag-Erling Smørgrav #include <stdarg.h> 440fba3a00SDag-Erling Smørgrav #include <stdlib.h> 450fba3a00SDag-Erling Smørgrav #include <stdio.h> 46842a95ccSDag-Erling Smørgrav #include <string.h> 47842a95ccSDag-Erling Smørgrav #include <unistd.h> 48842a95ccSDag-Erling Smørgrav 49842a95ccSDag-Erling Smørgrav #include "fetch.h" 50842a95ccSDag-Erling Smørgrav #include "common.h" 51842a95ccSDag-Erling Smørgrav 52d8acd8dcSDag-Erling Smørgrav 53842a95ccSDag-Erling Smørgrav /*** Local data **************************************************************/ 54842a95ccSDag-Erling Smørgrav 55842a95ccSDag-Erling Smørgrav /* 56842a95ccSDag-Erling Smørgrav * Error messages for resolver errors 57842a95ccSDag-Erling Smørgrav */ 58a1b37df2SDag-Erling Smørgrav static struct fetcherr netdb_errlist[] = { 593d82ba43SHajimu UMEMOTO #ifdef EAI_NODATA 6028c645cfSHajimu UMEMOTO { EAI_NODATA, FETCH_RESOLV, "Host not found" }, 613d82ba43SHajimu UMEMOTO #endif 6228c645cfSHajimu UMEMOTO { EAI_AGAIN, FETCH_TEMP, "Transient resolver failure" }, 6328c645cfSHajimu UMEMOTO { EAI_FAIL, FETCH_RESOLV, "Non-recoverable resolver failure" }, 6428c645cfSHajimu UMEMOTO { EAI_NONAME, FETCH_RESOLV, "No address record" }, 65d8acd8dcSDag-Erling Smørgrav { -1, FETCH_UNKNOWN, "Unknown resolver error" } 66842a95ccSDag-Erling Smørgrav }; 67842a95ccSDag-Erling Smørgrav 68a1763027SDag-Erling Smørgrav /* End-of-Line */ 6938c7e4a6SArchie Cobbs static const char ENDL[2] = "\r\n"; 70a1763027SDag-Erling Smørgrav 71842a95ccSDag-Erling Smørgrav 72842a95ccSDag-Erling Smørgrav /*** Error-reporting functions ***********************************************/ 73842a95ccSDag-Erling Smørgrav 74842a95ccSDag-Erling Smørgrav /* 75842a95ccSDag-Erling Smørgrav * Map error code to string 76842a95ccSDag-Erling Smørgrav */ 77ba101983SDag-Erling Smørgrav static struct fetcherr * 78a1b37df2SDag-Erling Smørgrav fetch_finderr(struct fetcherr *p, int e) 79842a95ccSDag-Erling Smørgrav { 80ba101983SDag-Erling Smørgrav while (p->num != -1 && p->num != e) 81ba101983SDag-Erling Smørgrav p++; 82e19e6098SDag-Erling Smørgrav return (p); 83842a95ccSDag-Erling Smørgrav } 84842a95ccSDag-Erling Smørgrav 85842a95ccSDag-Erling Smørgrav /* 86842a95ccSDag-Erling Smørgrav * Set error code 87842a95ccSDag-Erling Smørgrav */ 88842a95ccSDag-Erling Smørgrav void 89a1b37df2SDag-Erling Smørgrav fetch_seterr(struct fetcherr *p, int e) 90842a95ccSDag-Erling Smørgrav { 91a1b37df2SDag-Erling Smørgrav p = fetch_finderr(p, e); 92ba101983SDag-Erling Smørgrav fetchLastErrCode = p->cat; 93ba101983SDag-Erling Smørgrav snprintf(fetchLastErrString, MAXERRSTRING, "%s", p->string); 94842a95ccSDag-Erling Smørgrav } 95842a95ccSDag-Erling Smørgrav 96842a95ccSDag-Erling Smørgrav /* 97842a95ccSDag-Erling Smørgrav * Set error code according to errno 98842a95ccSDag-Erling Smørgrav */ 99842a95ccSDag-Erling Smørgrav void 100a1b37df2SDag-Erling Smørgrav fetch_syserr(void) 101842a95ccSDag-Erling Smørgrav { 102d8acd8dcSDag-Erling Smørgrav switch (errno) { 103d8acd8dcSDag-Erling Smørgrav case 0: 1040fba3a00SDag-Erling Smørgrav fetchLastErrCode = FETCH_OK; 105d8acd8dcSDag-Erling Smørgrav break; 106d8acd8dcSDag-Erling Smørgrav case EPERM: 107d8acd8dcSDag-Erling Smørgrav case EACCES: 108d8acd8dcSDag-Erling Smørgrav case EROFS: 109d8acd8dcSDag-Erling Smørgrav case EAUTH: 110d8acd8dcSDag-Erling Smørgrav case ENEEDAUTH: 1110fba3a00SDag-Erling Smørgrav fetchLastErrCode = FETCH_AUTH; 112d8acd8dcSDag-Erling Smørgrav break; 113d8acd8dcSDag-Erling Smørgrav case ENOENT: 114d8acd8dcSDag-Erling Smørgrav case EISDIR: /* XXX */ 1150fba3a00SDag-Erling Smørgrav fetchLastErrCode = FETCH_UNAVAIL; 116d8acd8dcSDag-Erling Smørgrav break; 117d8acd8dcSDag-Erling Smørgrav case ENOMEM: 1180fba3a00SDag-Erling Smørgrav fetchLastErrCode = FETCH_MEMORY; 119d8acd8dcSDag-Erling Smørgrav break; 120d8acd8dcSDag-Erling Smørgrav case EBUSY: 121d8acd8dcSDag-Erling Smørgrav case EAGAIN: 1220fba3a00SDag-Erling Smørgrav fetchLastErrCode = FETCH_TEMP; 123d8acd8dcSDag-Erling Smørgrav break; 124d8acd8dcSDag-Erling Smørgrav case EEXIST: 1250fba3a00SDag-Erling Smørgrav fetchLastErrCode = FETCH_EXISTS; 126d8acd8dcSDag-Erling Smørgrav break; 127d8acd8dcSDag-Erling Smørgrav case ENOSPC: 1280fba3a00SDag-Erling Smørgrav fetchLastErrCode = FETCH_FULL; 129d8acd8dcSDag-Erling Smørgrav break; 130d8acd8dcSDag-Erling Smørgrav case EADDRINUSE: 131d8acd8dcSDag-Erling Smørgrav case EADDRNOTAVAIL: 132d8acd8dcSDag-Erling Smørgrav case ENETDOWN: 133d8acd8dcSDag-Erling Smørgrav case ENETUNREACH: 134d8acd8dcSDag-Erling Smørgrav case ENETRESET: 135d8acd8dcSDag-Erling Smørgrav case EHOSTUNREACH: 1360fba3a00SDag-Erling Smørgrav fetchLastErrCode = FETCH_NETWORK; 137d8acd8dcSDag-Erling Smørgrav break; 138d8acd8dcSDag-Erling Smørgrav case ECONNABORTED: 139d8acd8dcSDag-Erling Smørgrav case ECONNRESET: 1400fba3a00SDag-Erling Smørgrav fetchLastErrCode = FETCH_ABORT; 141d8acd8dcSDag-Erling Smørgrav break; 142d8acd8dcSDag-Erling Smørgrav case ETIMEDOUT: 1430fba3a00SDag-Erling Smørgrav fetchLastErrCode = FETCH_TIMEOUT; 144d8acd8dcSDag-Erling Smørgrav break; 145d8acd8dcSDag-Erling Smørgrav case ECONNREFUSED: 146d8acd8dcSDag-Erling Smørgrav case EHOSTDOWN: 1470fba3a00SDag-Erling Smørgrav fetchLastErrCode = FETCH_DOWN; 148d8acd8dcSDag-Erling Smørgrav break; 149d8acd8dcSDag-Erling Smørgrav default: 1500fba3a00SDag-Erling Smørgrav fetchLastErrCode = FETCH_UNKNOWN; 151d8acd8dcSDag-Erling Smørgrav } 152e19e6098SDag-Erling Smørgrav snprintf(fetchLastErrString, MAXERRSTRING, "%s", strerror(errno)); 1530fba3a00SDag-Erling Smørgrav } 1540fba3a00SDag-Erling Smørgrav 1550fba3a00SDag-Erling Smørgrav 1560fba3a00SDag-Erling Smørgrav /* 1570fba3a00SDag-Erling Smørgrav * Emit status message 1580fba3a00SDag-Erling Smørgrav */ 159ba101983SDag-Erling Smørgrav void 160a1b37df2SDag-Erling Smørgrav fetch_info(const char *fmt, ...) 1610fba3a00SDag-Erling Smørgrav { 1620fba3a00SDag-Erling Smørgrav va_list ap; 1630fba3a00SDag-Erling Smørgrav 1640fba3a00SDag-Erling Smørgrav va_start(ap, fmt); 165ba101983SDag-Erling Smørgrav vfprintf(stderr, fmt, ap); 1660fba3a00SDag-Erling Smørgrav va_end(ap); 167a68f8b58SDag-Erling Smørgrav fputc('\n', stderr); 168842a95ccSDag-Erling Smørgrav } 169842a95ccSDag-Erling Smørgrav 170842a95ccSDag-Erling Smørgrav 171842a95ccSDag-Erling Smørgrav /*** Network-related utility functions ***************************************/ 172842a95ccSDag-Erling Smørgrav 173842a95ccSDag-Erling Smørgrav /* 174e828ada7SDag-Erling Smørgrav * Return the default port for a scheme 175e828ada7SDag-Erling Smørgrav */ 176e828ada7SDag-Erling Smørgrav int 177a1b37df2SDag-Erling Smørgrav fetch_default_port(const char *scheme) 178e828ada7SDag-Erling Smørgrav { 179e828ada7SDag-Erling Smørgrav struct servent *se; 180e828ada7SDag-Erling Smørgrav 181e828ada7SDag-Erling Smørgrav if ((se = getservbyname(scheme, "tcp")) != NULL) 182e19e6098SDag-Erling Smørgrav return (ntohs(se->s_port)); 183e828ada7SDag-Erling Smørgrav if (strcasecmp(scheme, SCHEME_FTP) == 0) 184e19e6098SDag-Erling Smørgrav return (FTP_DEFAULT_PORT); 185e828ada7SDag-Erling Smørgrav if (strcasecmp(scheme, SCHEME_HTTP) == 0) 186e19e6098SDag-Erling Smørgrav return (HTTP_DEFAULT_PORT); 187e19e6098SDag-Erling Smørgrav return (0); 188e828ada7SDag-Erling Smørgrav } 189e828ada7SDag-Erling Smørgrav 190e828ada7SDag-Erling Smørgrav /* 191e828ada7SDag-Erling Smørgrav * Return the default proxy port for a scheme 192e828ada7SDag-Erling Smørgrav */ 193e828ada7SDag-Erling Smørgrav int 194a1b37df2SDag-Erling Smørgrav fetch_default_proxy_port(const char *scheme) 195e828ada7SDag-Erling Smørgrav { 196e828ada7SDag-Erling Smørgrav if (strcasecmp(scheme, SCHEME_FTP) == 0) 197e19e6098SDag-Erling Smørgrav return (FTP_DEFAULT_PROXY_PORT); 198e828ada7SDag-Erling Smørgrav if (strcasecmp(scheme, SCHEME_HTTP) == 0) 199e19e6098SDag-Erling Smørgrav return (HTTP_DEFAULT_PROXY_PORT); 200e19e6098SDag-Erling Smørgrav return (0); 201e828ada7SDag-Erling Smørgrav } 202e828ada7SDag-Erling Smørgrav 203f606d589SDag-Erling Smørgrav 204e828ada7SDag-Erling Smørgrav /* 2059601e333SDag-Erling Smørgrav * Create a connection for an existing descriptor. 2069601e333SDag-Erling Smørgrav */ 2079601e333SDag-Erling Smørgrav conn_t * 208a1b37df2SDag-Erling Smørgrav fetch_reopen(int sd) 2099601e333SDag-Erling Smørgrav { 2109601e333SDag-Erling Smørgrav conn_t *conn; 2119601e333SDag-Erling Smørgrav 2129601e333SDag-Erling Smørgrav /* allocate and fill connection structure */ 213930105c1SDag-Erling Smørgrav if ((conn = calloc(1, sizeof(*conn))) == NULL) 2149601e333SDag-Erling Smørgrav return (NULL); 2159601e333SDag-Erling Smørgrav conn->sd = sd; 216f606d589SDag-Erling Smørgrav ++conn->ref; 217f606d589SDag-Erling Smørgrav return (conn); 218f606d589SDag-Erling Smørgrav } 219f606d589SDag-Erling Smørgrav 220f606d589SDag-Erling Smørgrav 221f606d589SDag-Erling Smørgrav /* 222f606d589SDag-Erling Smørgrav * Bump a connection's reference count. 223f606d589SDag-Erling Smørgrav */ 224f606d589SDag-Erling Smørgrav conn_t * 225a1b37df2SDag-Erling Smørgrav fetch_ref(conn_t *conn) 226f606d589SDag-Erling Smørgrav { 227f606d589SDag-Erling Smørgrav 228f606d589SDag-Erling Smørgrav ++conn->ref; 2299601e333SDag-Erling Smørgrav return (conn); 2309601e333SDag-Erling Smørgrav } 2319601e333SDag-Erling Smørgrav 2329601e333SDag-Erling Smørgrav 2339601e333SDag-Erling Smørgrav /* 234c42cb9d9SDag-Erling Smørgrav * Bind a socket to a specific local address 235c42cb9d9SDag-Erling Smørgrav */ 236c42cb9d9SDag-Erling Smørgrav int 237a1b37df2SDag-Erling Smørgrav fetch_bind(int sd, int af, const char *addr) 238c42cb9d9SDag-Erling Smørgrav { 239c42cb9d9SDag-Erling Smørgrav struct addrinfo hints, *res, *res0; 240c42cb9d9SDag-Erling Smørgrav int err; 241c42cb9d9SDag-Erling Smørgrav 242c42cb9d9SDag-Erling Smørgrav memset(&hints, 0, sizeof(hints)); 243c42cb9d9SDag-Erling Smørgrav hints.ai_family = af; 244c42cb9d9SDag-Erling Smørgrav hints.ai_socktype = SOCK_STREAM; 245c42cb9d9SDag-Erling Smørgrav hints.ai_protocol = 0; 246c42cb9d9SDag-Erling Smørgrav if ((err = getaddrinfo(addr, NULL, &hints, &res0)) != 0) 247c42cb9d9SDag-Erling Smørgrav return (-1); 248c42cb9d9SDag-Erling Smørgrav for (res = res0; res; res = res->ai_next) 249c42cb9d9SDag-Erling Smørgrav if (bind(sd, res->ai_addr, res->ai_addrlen) == 0) 250c42cb9d9SDag-Erling Smørgrav return (0); 251c42cb9d9SDag-Erling Smørgrav return (-1); 252c42cb9d9SDag-Erling Smørgrav } 253c42cb9d9SDag-Erling Smørgrav 254c42cb9d9SDag-Erling Smørgrav 255c42cb9d9SDag-Erling Smørgrav /* 256842a95ccSDag-Erling Smørgrav * Establish a TCP connection to the specified port on the specified host. 257842a95ccSDag-Erling Smørgrav */ 258dea29ca1SDag-Erling Smørgrav conn_t * 259a1b37df2SDag-Erling Smørgrav fetch_connect(const char *host, int port, int af, int verbose) 260842a95ccSDag-Erling Smørgrav { 261dea29ca1SDag-Erling Smørgrav conn_t *conn; 26228c645cfSHajimu UMEMOTO char pbuf[10]; 263c42cb9d9SDag-Erling Smørgrav const char *bindaddr; 26428c645cfSHajimu UMEMOTO struct addrinfo hints, *res, *res0; 26528c645cfSHajimu UMEMOTO int sd, err; 266842a95ccSDag-Erling Smørgrav 267f67efa37SDag-Erling Smørgrav DEBUG(fprintf(stderr, "---> %s:%d\n", host, port)); 268842a95ccSDag-Erling Smørgrav 2690fba3a00SDag-Erling Smørgrav if (verbose) 270a1b37df2SDag-Erling Smørgrav fetch_info("looking up %s", host); 2710fba3a00SDag-Erling Smørgrav 27228c645cfSHajimu UMEMOTO /* look up host name and set up socket address structure */ 27328c645cfSHajimu UMEMOTO snprintf(pbuf, sizeof(pbuf), "%d", port); 27428c645cfSHajimu UMEMOTO memset(&hints, 0, sizeof(hints)); 27528c645cfSHajimu UMEMOTO hints.ai_family = af; 27628c645cfSHajimu UMEMOTO hints.ai_socktype = SOCK_STREAM; 27728c645cfSHajimu UMEMOTO hints.ai_protocol = 0; 27828c645cfSHajimu UMEMOTO if ((err = getaddrinfo(host, pbuf, &hints, &res0)) != 0) { 279a1b37df2SDag-Erling Smørgrav netdb_seterr(err); 280dea29ca1SDag-Erling Smørgrav return (NULL); 281842a95ccSDag-Erling Smørgrav } 282c42cb9d9SDag-Erling Smørgrav bindaddr = getenv("FETCH_BIND_ADDRESS"); 283842a95ccSDag-Erling Smørgrav 2840fba3a00SDag-Erling Smørgrav if (verbose) 285a1b37df2SDag-Erling Smørgrav fetch_info("connecting to %s:%d", host, port); 2860fba3a00SDag-Erling Smørgrav 287842a95ccSDag-Erling Smørgrav /* try to connect */ 288c42cb9d9SDag-Erling Smørgrav for (sd = -1, res = res0; res; sd = -1, res = res->ai_next) { 28928c645cfSHajimu UMEMOTO if ((sd = socket(res->ai_family, res->ai_socktype, 290a1763027SDag-Erling Smørgrav res->ai_protocol)) == -1) 29128c645cfSHajimu UMEMOTO continue; 292c42cb9d9SDag-Erling Smørgrav if (bindaddr != NULL && *bindaddr != '\0' && 293a1b37df2SDag-Erling Smørgrav fetch_bind(sd, res->ai_family, bindaddr) != 0) { 294a1b37df2SDag-Erling Smørgrav fetch_info("failed to bind to '%s'", bindaddr); 295c42cb9d9SDag-Erling Smørgrav close(sd); 296c42cb9d9SDag-Erling Smørgrav continue; 297c42cb9d9SDag-Erling Smørgrav } 298c42cb9d9SDag-Erling Smørgrav if (connect(sd, res->ai_addr, res->ai_addrlen) == 0) 29928c645cfSHajimu UMEMOTO break; 300842a95ccSDag-Erling Smørgrav close(sd); 30128c645cfSHajimu UMEMOTO } 3027487ef62SHajimu UMEMOTO freeaddrinfo(res0); 303a1763027SDag-Erling Smørgrav if (sd == -1) { 304a1b37df2SDag-Erling Smørgrav fetch_syserr(); 305dea29ca1SDag-Erling Smørgrav return (NULL); 306842a95ccSDag-Erling Smørgrav } 307842a95ccSDag-Erling Smørgrav 308a1b37df2SDag-Erling Smørgrav if ((conn = fetch_reopen(sd)) == NULL) { 309a1b37df2SDag-Erling Smørgrav fetch_syserr(); 310dea29ca1SDag-Erling Smørgrav close(sd); 31140cfbfd5SBill Fenner } 312dea29ca1SDag-Erling Smørgrav return (conn); 313842a95ccSDag-Erling Smørgrav } 314ce71b736SDag-Erling Smørgrav 315ce71b736SDag-Erling Smørgrav 316fc6e9e65SDag-Erling Smørgrav /* 317111e2510SDag-Erling Smørgrav * Enable SSL on a connection. 318111e2510SDag-Erling Smørgrav */ 319111e2510SDag-Erling Smørgrav int 320a1b37df2SDag-Erling Smørgrav fetch_ssl(conn_t *conn, int verbose) 321111e2510SDag-Erling Smørgrav { 322111e2510SDag-Erling Smørgrav 3233070f6cbSDag-Erling Smørgrav #ifdef WITH_SSL 324111e2510SDag-Erling Smørgrav /* Init the SSL library and context */ 325111e2510SDag-Erling Smørgrav if (!SSL_library_init()){ 326111e2510SDag-Erling Smørgrav fprintf(stderr, "SSL library init failed\n"); 327111e2510SDag-Erling Smørgrav return (-1); 328111e2510SDag-Erling Smørgrav } 329111e2510SDag-Erling Smørgrav 330111e2510SDag-Erling Smørgrav SSL_load_error_strings(); 331111e2510SDag-Erling Smørgrav 332111e2510SDag-Erling Smørgrav conn->ssl_meth = SSLv23_client_method(); 333111e2510SDag-Erling Smørgrav conn->ssl_ctx = SSL_CTX_new(conn->ssl_meth); 334f8020ddeSDag-Erling Smørgrav SSL_CTX_set_mode(conn->ssl_ctx, SSL_MODE_AUTO_RETRY); 335111e2510SDag-Erling Smørgrav 336111e2510SDag-Erling Smørgrav conn->ssl = SSL_new(conn->ssl_ctx); 337111e2510SDag-Erling Smørgrav if (conn->ssl == NULL){ 338111e2510SDag-Erling Smørgrav fprintf(stderr, "SSL context creation failed\n"); 339111e2510SDag-Erling Smørgrav return (-1); 340111e2510SDag-Erling Smørgrav } 341111e2510SDag-Erling Smørgrav SSL_set_fd(conn->ssl, conn->sd); 342111e2510SDag-Erling Smørgrav if (SSL_connect(conn->ssl) == -1){ 343111e2510SDag-Erling Smørgrav ERR_print_errors_fp(stderr); 344111e2510SDag-Erling Smørgrav return (-1); 345111e2510SDag-Erling Smørgrav } 346111e2510SDag-Erling Smørgrav 347111e2510SDag-Erling Smørgrav if (verbose) { 348111e2510SDag-Erling Smørgrav X509_NAME *name; 349111e2510SDag-Erling Smørgrav char *str; 350111e2510SDag-Erling Smørgrav 351111e2510SDag-Erling Smørgrav fprintf(stderr, "SSL connection established using %s\n", 352111e2510SDag-Erling Smørgrav SSL_get_cipher(conn->ssl)); 353111e2510SDag-Erling Smørgrav conn->ssl_cert = SSL_get_peer_certificate(conn->ssl); 354111e2510SDag-Erling Smørgrav name = X509_get_subject_name(conn->ssl_cert); 355111e2510SDag-Erling Smørgrav str = X509_NAME_oneline(name, 0, 0); 356111e2510SDag-Erling Smørgrav printf("Certificate subject: %s\n", str); 357111e2510SDag-Erling Smørgrav free(str); 358111e2510SDag-Erling Smørgrav name = X509_get_issuer_name(conn->ssl_cert); 359111e2510SDag-Erling Smørgrav str = X509_NAME_oneline(name, 0, 0); 360111e2510SDag-Erling Smørgrav printf("Certificate issuer: %s\n", str); 361111e2510SDag-Erling Smørgrav free(str); 362111e2510SDag-Erling Smørgrav } 363111e2510SDag-Erling Smørgrav 364111e2510SDag-Erling Smørgrav return (0); 3653070f6cbSDag-Erling Smørgrav #else 3663070f6cbSDag-Erling Smørgrav (void)conn; 3673070f6cbSDag-Erling Smørgrav (void)verbose; 3683070f6cbSDag-Erling Smørgrav fprintf(stderr, "SSL support disabled\n"); 3693070f6cbSDag-Erling Smørgrav return (-1); 3703070f6cbSDag-Erling Smørgrav #endif 371111e2510SDag-Erling Smørgrav } 372111e2510SDag-Erling Smørgrav 373f606d589SDag-Erling Smørgrav 374111e2510SDag-Erling Smørgrav /* 3759601e333SDag-Erling Smørgrav * Read a character from a connection w/ timeout 3769601e333SDag-Erling Smørgrav */ 3779601e333SDag-Erling Smørgrav ssize_t 378a1b37df2SDag-Erling Smørgrav fetch_read(conn_t *conn, char *buf, size_t len) 3799601e333SDag-Erling Smørgrav { 3805092cf05SDag-Erling Smørgrav struct timeval now, timeout, delta; 3819601e333SDag-Erling Smørgrav fd_set readfds; 3829601e333SDag-Erling Smørgrav ssize_t rlen, total; 3839601e333SDag-Erling Smørgrav int r; 3849601e333SDag-Erling Smørgrav 3859601e333SDag-Erling Smørgrav if (fetchTimeout) { 3869601e333SDag-Erling Smørgrav FD_ZERO(&readfds); 3879601e333SDag-Erling Smørgrav gettimeofday(&timeout, NULL); 3889601e333SDag-Erling Smørgrav timeout.tv_sec += fetchTimeout; 3899601e333SDag-Erling Smørgrav } 3909601e333SDag-Erling Smørgrav 3919601e333SDag-Erling Smørgrav total = 0; 3929601e333SDag-Erling Smørgrav while (len > 0) { 3939601e333SDag-Erling Smørgrav while (fetchTimeout && !FD_ISSET(conn->sd, &readfds)) { 3949601e333SDag-Erling Smørgrav FD_SET(conn->sd, &readfds); 3959601e333SDag-Erling Smørgrav gettimeofday(&now, NULL); 3965092cf05SDag-Erling Smørgrav delta.tv_sec = timeout.tv_sec - now.tv_sec; 3975092cf05SDag-Erling Smørgrav delta.tv_usec = timeout.tv_usec - now.tv_usec; 3985092cf05SDag-Erling Smørgrav if (delta.tv_usec < 0) { 3995092cf05SDag-Erling Smørgrav delta.tv_usec += 1000000; 4005092cf05SDag-Erling Smørgrav delta.tv_sec--; 4019601e333SDag-Erling Smørgrav } 4025092cf05SDag-Erling Smørgrav if (delta.tv_sec < 0) { 403bb13d0afSDag-Erling Smørgrav errno = ETIMEDOUT; 404a1b37df2SDag-Erling Smørgrav fetch_syserr(); 405bb13d0afSDag-Erling Smørgrav return (-1); 406bb13d0afSDag-Erling Smørgrav } 4079601e333SDag-Erling Smørgrav errno = 0; 4085092cf05SDag-Erling Smørgrav r = select(conn->sd + 1, &readfds, NULL, NULL, &delta); 4099601e333SDag-Erling Smørgrav if (r == -1) { 4109601e333SDag-Erling Smørgrav if (errno == EINTR && fetchRestartCalls) 4119601e333SDag-Erling Smørgrav continue; 412a1b37df2SDag-Erling Smørgrav fetch_syserr(); 4139601e333SDag-Erling Smørgrav return (-1); 4149601e333SDag-Erling Smørgrav } 4159601e333SDag-Erling Smørgrav } 4163070f6cbSDag-Erling Smørgrav #ifdef WITH_SSL 4179601e333SDag-Erling Smørgrav if (conn->ssl != NULL) 4189601e333SDag-Erling Smørgrav rlen = SSL_read(conn->ssl, buf, len); 4199601e333SDag-Erling Smørgrav else 4203070f6cbSDag-Erling Smørgrav #endif 4219601e333SDag-Erling Smørgrav rlen = read(conn->sd, buf, len); 4221a5424b1SDag-Erling Smørgrav if (rlen == 0) 4231a5424b1SDag-Erling Smørgrav break; 4249601e333SDag-Erling Smørgrav if (rlen < 0) { 4259601e333SDag-Erling Smørgrav if (errno == EINTR && fetchRestartCalls) 4269601e333SDag-Erling Smørgrav continue; 4279601e333SDag-Erling Smørgrav return (-1); 4289601e333SDag-Erling Smørgrav } 4299601e333SDag-Erling Smørgrav len -= rlen; 4309601e333SDag-Erling Smørgrav buf += rlen; 4319601e333SDag-Erling Smørgrav total += rlen; 4329601e333SDag-Erling Smørgrav } 4339601e333SDag-Erling Smørgrav return (total); 4349601e333SDag-Erling Smørgrav } 4359601e333SDag-Erling Smørgrav 436f606d589SDag-Erling Smørgrav 4379601e333SDag-Erling Smørgrav /* 4389601e333SDag-Erling Smørgrav * Read a line of text from a connection w/ timeout 439fc6e9e65SDag-Erling Smørgrav */ 440fc6e9e65SDag-Erling Smørgrav #define MIN_BUF_SIZE 1024 441fc6e9e65SDag-Erling Smørgrav 442fc6e9e65SDag-Erling Smørgrav int 443a1b37df2SDag-Erling Smørgrav fetch_getln(conn_t *conn) 444fc6e9e65SDag-Erling Smørgrav { 4459601e333SDag-Erling Smørgrav char *tmp; 4469601e333SDag-Erling Smørgrav size_t tmpsize; 447bb13d0afSDag-Erling Smørgrav ssize_t len; 448fc6e9e65SDag-Erling Smørgrav char c; 449fc6e9e65SDag-Erling Smørgrav 450dea29ca1SDag-Erling Smørgrav if (conn->buf == NULL) { 451dea29ca1SDag-Erling Smørgrav if ((conn->buf = malloc(MIN_BUF_SIZE)) == NULL) { 452fc6e9e65SDag-Erling Smørgrav errno = ENOMEM; 453e19e6098SDag-Erling Smørgrav return (-1); 454fc6e9e65SDag-Erling Smørgrav } 455dea29ca1SDag-Erling Smørgrav conn->bufsize = MIN_BUF_SIZE; 456fc6e9e65SDag-Erling Smørgrav } 457fc6e9e65SDag-Erling Smørgrav 458dea29ca1SDag-Erling Smørgrav conn->buf[0] = '\0'; 459dea29ca1SDag-Erling Smørgrav conn->buflen = 0; 460fc6e9e65SDag-Erling Smørgrav 461fc6e9e65SDag-Erling Smørgrav do { 462a1b37df2SDag-Erling Smørgrav len = fetch_read(conn, &c, 1); 463bb13d0afSDag-Erling Smørgrav if (len == -1) 464e19e6098SDag-Erling Smørgrav return (-1); 465bb13d0afSDag-Erling Smørgrav if (len == 0) 466b68fbebdSDavid E. O'Brien break; 467dea29ca1SDag-Erling Smørgrav conn->buf[conn->buflen++] = c; 468dea29ca1SDag-Erling Smørgrav if (conn->buflen == conn->bufsize) { 469dea29ca1SDag-Erling Smørgrav tmp = conn->buf; 470dea29ca1SDag-Erling Smørgrav tmpsize = conn->bufsize * 2 + 1; 471dea29ca1SDag-Erling Smørgrav if ((tmp = realloc(tmp, tmpsize)) == NULL) { 472fc6e9e65SDag-Erling Smørgrav errno = ENOMEM; 473e19e6098SDag-Erling Smørgrav return (-1); 474fc6e9e65SDag-Erling Smørgrav } 475dea29ca1SDag-Erling Smørgrav conn->buf = tmp; 476dea29ca1SDag-Erling Smørgrav conn->bufsize = tmpsize; 477fc6e9e65SDag-Erling Smørgrav } 478fc6e9e65SDag-Erling Smørgrav } while (c != '\n'); 479fc6e9e65SDag-Erling Smørgrav 480dea29ca1SDag-Erling Smørgrav conn->buf[conn->buflen] = '\0'; 481dea29ca1SDag-Erling Smørgrav DEBUG(fprintf(stderr, "<<< %s", conn->buf)); 482e19e6098SDag-Erling Smørgrav return (0); 483fc6e9e65SDag-Erling Smørgrav } 484fc6e9e65SDag-Erling Smørgrav 485fc6e9e65SDag-Erling Smørgrav 486a1763027SDag-Erling Smørgrav /* 4879601e333SDag-Erling Smørgrav * Write to a connection w/ timeout 4889601e333SDag-Erling Smørgrav */ 4899601e333SDag-Erling Smørgrav ssize_t 490a1b37df2SDag-Erling Smørgrav fetch_write(conn_t *conn, const char *buf, size_t len) 4919601e333SDag-Erling Smørgrav { 492a4a37038SWarner Losh struct iovec iov; 493a4a37038SWarner Losh 494a4a37038SWarner Losh iov.iov_base = __DECONST(char *, buf); 495a4a37038SWarner Losh iov.iov_len = len; 496a1b37df2SDag-Erling Smørgrav return fetch_writev(conn, &iov, 1); 497a4a37038SWarner Losh } 498a4a37038SWarner Losh 499a4a37038SWarner Losh /* 500a4a37038SWarner Losh * Write a vector to a connection w/ timeout 501a4a37038SWarner Losh * Note: can modify the iovec. 502a4a37038SWarner Losh */ 503a4a37038SWarner Losh ssize_t 504a1b37df2SDag-Erling Smørgrav fetch_writev(conn_t *conn, struct iovec *iov, int iovcnt) 505a4a37038SWarner Losh { 5065092cf05SDag-Erling Smørgrav struct timeval now, timeout, delta; 5079601e333SDag-Erling Smørgrav fd_set writefds; 5089601e333SDag-Erling Smørgrav ssize_t wlen, total; 5099601e333SDag-Erling Smørgrav int r; 5109601e333SDag-Erling Smørgrav 5119601e333SDag-Erling Smørgrav if (fetchTimeout) { 5129601e333SDag-Erling Smørgrav FD_ZERO(&writefds); 5139601e333SDag-Erling Smørgrav gettimeofday(&timeout, NULL); 5149601e333SDag-Erling Smørgrav timeout.tv_sec += fetchTimeout; 5159601e333SDag-Erling Smørgrav } 5169601e333SDag-Erling Smørgrav 517a4a37038SWarner Losh total = 0; 518a4a37038SWarner Losh while (iovcnt > 0) { 5199601e333SDag-Erling Smørgrav while (fetchTimeout && !FD_ISSET(conn->sd, &writefds)) { 5209601e333SDag-Erling Smørgrav FD_SET(conn->sd, &writefds); 5219601e333SDag-Erling Smørgrav gettimeofday(&now, NULL); 5225092cf05SDag-Erling Smørgrav delta.tv_sec = timeout.tv_sec - now.tv_sec; 5235092cf05SDag-Erling Smørgrav delta.tv_usec = timeout.tv_usec - now.tv_usec; 5245092cf05SDag-Erling Smørgrav if (delta.tv_usec < 0) { 5255092cf05SDag-Erling Smørgrav delta.tv_usec += 1000000; 5265092cf05SDag-Erling Smørgrav delta.tv_sec--; 5279601e333SDag-Erling Smørgrav } 5285092cf05SDag-Erling Smørgrav if (delta.tv_sec < 0) { 5299601e333SDag-Erling Smørgrav errno = ETIMEDOUT; 530a1b37df2SDag-Erling Smørgrav fetch_syserr(); 5319601e333SDag-Erling Smørgrav return (-1); 5329601e333SDag-Erling Smørgrav } 5339601e333SDag-Erling Smørgrav errno = 0; 5345092cf05SDag-Erling Smørgrav r = select(conn->sd + 1, NULL, &writefds, NULL, &delta); 5359601e333SDag-Erling Smørgrav if (r == -1) { 5369601e333SDag-Erling Smørgrav if (errno == EINTR && fetchRestartCalls) 5379601e333SDag-Erling Smørgrav continue; 5389601e333SDag-Erling Smørgrav return (-1); 5399601e333SDag-Erling Smørgrav } 5409601e333SDag-Erling Smørgrav } 5419601e333SDag-Erling Smørgrav errno = 0; 5423070f6cbSDag-Erling Smørgrav #ifdef WITH_SSL 5439601e333SDag-Erling Smørgrav if (conn->ssl != NULL) 544a4a37038SWarner Losh wlen = SSL_write(conn->ssl, 545a4a37038SWarner Losh iov->iov_base, iov->iov_len); 5469601e333SDag-Erling Smørgrav else 5473070f6cbSDag-Erling Smørgrav #endif 548a4a37038SWarner Losh wlen = writev(conn->sd, iov, iovcnt); 549a4a37038SWarner Losh if (wlen == 0) { 5509601e333SDag-Erling Smørgrav /* we consider a short write a failure */ 551a4a37038SWarner Losh errno = EPIPE; 552a1b37df2SDag-Erling Smørgrav fetch_syserr(); 5539601e333SDag-Erling Smørgrav return (-1); 554a4a37038SWarner Losh } 5559601e333SDag-Erling Smørgrav if (wlen < 0) { 5569601e333SDag-Erling Smørgrav if (errno == EINTR && fetchRestartCalls) 5579601e333SDag-Erling Smørgrav continue; 5589601e333SDag-Erling Smørgrav return (-1); 5599601e333SDag-Erling Smørgrav } 5609601e333SDag-Erling Smørgrav total += wlen; 561a4a37038SWarner Losh while (iovcnt > 0 && wlen >= (ssize_t)iov->iov_len) { 562a4a37038SWarner Losh wlen -= iov->iov_len; 563a4a37038SWarner Losh iov++; 564a4a37038SWarner Losh iovcnt--; 565a4a37038SWarner Losh } 566a4a37038SWarner Losh if (iovcnt > 0) { 567a4a37038SWarner Losh iov->iov_len -= wlen; 568a4a37038SWarner Losh iov->iov_base = __DECONST(char *, iov->iov_base) + wlen; 569a4a37038SWarner Losh } 5709601e333SDag-Erling Smørgrav } 5719601e333SDag-Erling Smørgrav return (total); 5729601e333SDag-Erling Smørgrav } 5739601e333SDag-Erling Smørgrav 574f606d589SDag-Erling Smørgrav 5759601e333SDag-Erling Smørgrav /* 5769601e333SDag-Erling Smørgrav * Write a line of text to a connection w/ timeout 577a1763027SDag-Erling Smørgrav */ 578a1763027SDag-Erling Smørgrav int 579a1b37df2SDag-Erling Smørgrav fetch_putln(conn_t *conn, const char *str, size_t len) 580a1763027SDag-Erling Smørgrav { 581a4a37038SWarner Losh struct iovec iov[2]; 5827504527eSDag-Erling Smørgrav int ret; 58366ffb8a3SDag-Erling Smørgrav 58466ffb8a3SDag-Erling Smørgrav DEBUG(fprintf(stderr, ">>> %s\n", str)); 585a4a37038SWarner Losh iov[0].iov_base = __DECONST(char *, str); 586a4a37038SWarner Losh iov[0].iov_len = len; 587a4a37038SWarner Losh iov[1].iov_base = __DECONST(char *, ENDL); 588930105c1SDag-Erling Smørgrav iov[1].iov_len = sizeof(ENDL); 5897504527eSDag-Erling Smørgrav if (len == 0) 590a1b37df2SDag-Erling Smørgrav ret = fetch_writev(conn, &iov[1], 1); 5917504527eSDag-Erling Smørgrav else 592a1b37df2SDag-Erling Smørgrav ret = fetch_writev(conn, iov, 2); 5937504527eSDag-Erling Smørgrav if (ret == -1) 594e19e6098SDag-Erling Smørgrav return (-1); 595e19e6098SDag-Erling Smørgrav return (0); 596a1763027SDag-Erling Smørgrav } 597a1763027SDag-Erling Smørgrav 598a1763027SDag-Erling Smørgrav 599dea29ca1SDag-Erling Smørgrav /* 600dea29ca1SDag-Erling Smørgrav * Close connection 601dea29ca1SDag-Erling Smørgrav */ 602dea29ca1SDag-Erling Smørgrav int 603a1b37df2SDag-Erling Smørgrav fetch_close(conn_t *conn) 604dea29ca1SDag-Erling Smørgrav { 605dea29ca1SDag-Erling Smørgrav int ret; 606dea29ca1SDag-Erling Smørgrav 607f606d589SDag-Erling Smørgrav if (--conn->ref > 0) 608f606d589SDag-Erling Smørgrav return (0); 609dea29ca1SDag-Erling Smørgrav ret = close(conn->sd); 61055cf7be1SDag-Erling Smørgrav free(conn->buf); 611dea29ca1SDag-Erling Smørgrav free(conn); 612dea29ca1SDag-Erling Smørgrav return (ret); 613dea29ca1SDag-Erling Smørgrav } 614dea29ca1SDag-Erling Smørgrav 615dea29ca1SDag-Erling Smørgrav 616ce71b736SDag-Erling Smørgrav /*** Directory-related utility functions *************************************/ 617ce71b736SDag-Erling Smørgrav 618ce71b736SDag-Erling Smørgrav int 619a1b37df2SDag-Erling Smørgrav fetch_add_entry(struct url_ent **p, int *size, int *len, 620f573a5fcSDag-Erling Smørgrav const char *name, struct url_stat *us) 621ce71b736SDag-Erling Smørgrav { 622ce71b736SDag-Erling Smørgrav struct url_ent *tmp; 623ce71b736SDag-Erling Smørgrav 624ce71b736SDag-Erling Smørgrav if (*p == NULL) { 6255a51c23bSDag-Erling Smørgrav *size = 0; 626ce71b736SDag-Erling Smørgrav *len = 0; 627ce71b736SDag-Erling Smørgrav } 628ce71b736SDag-Erling Smørgrav 629ce71b736SDag-Erling Smørgrav if (*len >= *size - 1) { 630930105c1SDag-Erling Smørgrav tmp = realloc(*p, (*size * 2 + 1) * sizeof(**p)); 631ce71b736SDag-Erling Smørgrav if (tmp == NULL) { 632ce71b736SDag-Erling Smørgrav errno = ENOMEM; 633a1b37df2SDag-Erling Smørgrav fetch_syserr(); 634e19e6098SDag-Erling Smørgrav return (-1); 635ce71b736SDag-Erling Smørgrav } 6365a51c23bSDag-Erling Smørgrav *size = (*size * 2 + 1); 637ce71b736SDag-Erling Smørgrav *p = tmp; 638ce71b736SDag-Erling Smørgrav } 639ce71b736SDag-Erling Smørgrav 640ce71b736SDag-Erling Smørgrav tmp = *p + *len; 6412b26f942SDag-Erling Smørgrav snprintf(tmp->name, PATH_MAX, "%s", name); 642340b079bSDag-Erling Smørgrav memcpy(&tmp->stat, us, sizeof(*us)); 643ce71b736SDag-Erling Smørgrav 644ce71b736SDag-Erling Smørgrav (*len)++; 645ce71b736SDag-Erling Smørgrav (++tmp)->name[0] = 0; 646ce71b736SDag-Erling Smørgrav 647e19e6098SDag-Erling Smørgrav return (0); 648ce71b736SDag-Erling Smørgrav } 64907350d12SDag-Erling Smørgrav 65007350d12SDag-Erling Smørgrav 65107350d12SDag-Erling Smørgrav /*** Authentication-related utility functions ********************************/ 65207350d12SDag-Erling Smørgrav 65307350d12SDag-Erling Smørgrav static const char * 654a1b37df2SDag-Erling Smørgrav fetch_read_word(FILE *f) 65507350d12SDag-Erling Smørgrav { 65607350d12SDag-Erling Smørgrav static char word[1024]; 65707350d12SDag-Erling Smørgrav 658fc2841a9SColin Percival if (fscanf(f, " %1023s ", word) != 1) 65907350d12SDag-Erling Smørgrav return (NULL); 66007350d12SDag-Erling Smørgrav return (word); 66107350d12SDag-Erling Smørgrav } 66207350d12SDag-Erling Smørgrav 66307350d12SDag-Erling Smørgrav /* 66407350d12SDag-Erling Smørgrav * Get authentication data for a URL from .netrc 66507350d12SDag-Erling Smørgrav */ 66607350d12SDag-Erling Smørgrav int 667a1b37df2SDag-Erling Smørgrav fetch_netrc_auth(struct url *url) 66807350d12SDag-Erling Smørgrav { 66907350d12SDag-Erling Smørgrav char fn[PATH_MAX]; 67007350d12SDag-Erling Smørgrav const char *word; 67107350d12SDag-Erling Smørgrav char *p; 67207350d12SDag-Erling Smørgrav FILE *f; 67307350d12SDag-Erling Smørgrav 67407350d12SDag-Erling Smørgrav if ((p = getenv("NETRC")) != NULL) { 675930105c1SDag-Erling Smørgrav if (snprintf(fn, sizeof(fn), "%s", p) >= (int)sizeof(fn)) { 676a1b37df2SDag-Erling Smørgrav fetch_info("$NETRC specifies a file name " 67707350d12SDag-Erling Smørgrav "longer than PATH_MAX"); 67807350d12SDag-Erling Smørgrav return (-1); 67907350d12SDag-Erling Smørgrav } 68007350d12SDag-Erling Smørgrav } else { 68107350d12SDag-Erling Smørgrav if ((p = getenv("HOME")) != NULL) { 68207350d12SDag-Erling Smørgrav struct passwd *pwd; 68307350d12SDag-Erling Smørgrav 68407350d12SDag-Erling Smørgrav if ((pwd = getpwuid(getuid())) == NULL || 68507350d12SDag-Erling Smørgrav (p = pwd->pw_dir) == NULL) 68607350d12SDag-Erling Smørgrav return (-1); 68707350d12SDag-Erling Smørgrav } 688930105c1SDag-Erling Smørgrav if (snprintf(fn, sizeof(fn), "%s/.netrc", p) >= (int)sizeof(fn)) 68907350d12SDag-Erling Smørgrav return (-1); 69007350d12SDag-Erling Smørgrav } 69107350d12SDag-Erling Smørgrav 69207350d12SDag-Erling Smørgrav if ((f = fopen(fn, "r")) == NULL) 69307350d12SDag-Erling Smørgrav return (-1); 694a1b37df2SDag-Erling Smørgrav while ((word = fetch_read_word(f)) != NULL) { 69507350d12SDag-Erling Smørgrav if (strcmp(word, "default") == 0) { 696a1b37df2SDag-Erling Smørgrav DEBUG(fetch_info("Using default .netrc settings")); 69707350d12SDag-Erling Smørgrav break; 69807350d12SDag-Erling Smørgrav } 69907350d12SDag-Erling Smørgrav if (strcmp(word, "machine") == 0 && 700a1b37df2SDag-Erling Smørgrav (word = fetch_read_word(f)) != NULL && 70107350d12SDag-Erling Smørgrav strcasecmp(word, url->host) == 0) { 702a1b37df2SDag-Erling Smørgrav DEBUG(fetch_info("Using .netrc settings for %s", word)); 70307350d12SDag-Erling Smørgrav break; 70407350d12SDag-Erling Smørgrav } 70507350d12SDag-Erling Smørgrav } 70607350d12SDag-Erling Smørgrav if (word == NULL) 70707350d12SDag-Erling Smørgrav goto ferr; 708a1b37df2SDag-Erling Smørgrav while ((word = fetch_read_word(f)) != NULL) { 70907350d12SDag-Erling Smørgrav if (strcmp(word, "login") == 0) { 710a1b37df2SDag-Erling Smørgrav if ((word = fetch_read_word(f)) == NULL) 71107350d12SDag-Erling Smørgrav goto ferr; 712930105c1SDag-Erling Smørgrav if (snprintf(url->user, sizeof(url->user), 7139015b953SJohn W. De Boskey "%s", word) > (int)sizeof(url->user)) { 714a1b37df2SDag-Erling Smørgrav fetch_info("login name in .netrc is too long"); 71507350d12SDag-Erling Smørgrav url->user[0] = '\0'; 71607350d12SDag-Erling Smørgrav } 71707350d12SDag-Erling Smørgrav } else if (strcmp(word, "password") == 0) { 718a1b37df2SDag-Erling Smørgrav if ((word = fetch_read_word(f)) == NULL) 71907350d12SDag-Erling Smørgrav goto ferr; 720930105c1SDag-Erling Smørgrav if (snprintf(url->pwd, sizeof(url->pwd), 7219015b953SJohn W. De Boskey "%s", word) > (int)sizeof(url->pwd)) { 722a1b37df2SDag-Erling Smørgrav fetch_info("password in .netrc is too long"); 72307350d12SDag-Erling Smørgrav url->pwd[0] = '\0'; 72407350d12SDag-Erling Smørgrav } 72507350d12SDag-Erling Smørgrav } else if (strcmp(word, "account") == 0) { 726a1b37df2SDag-Erling Smørgrav if ((word = fetch_read_word(f)) == NULL) 72707350d12SDag-Erling Smørgrav goto ferr; 72807350d12SDag-Erling Smørgrav /* XXX not supported! */ 72907350d12SDag-Erling Smørgrav } else { 73007350d12SDag-Erling Smørgrav break; 73107350d12SDag-Erling Smørgrav } 73207350d12SDag-Erling Smørgrav } 73307350d12SDag-Erling Smørgrav fclose(f); 73407350d12SDag-Erling Smørgrav return (0); 73507350d12SDag-Erling Smørgrav ferr: 73607350d12SDag-Erling Smørgrav fclose(f); 73707350d12SDag-Erling Smørgrav return (-1); 73807350d12SDag-Erling Smørgrav } 73962a2681cSDag-Erling Smørgrav 74062a2681cSDag-Erling Smørgrav /* 74162a2681cSDag-Erling Smørgrav * The no_proxy environment variable specifies a set of domains for 74262a2681cSDag-Erling Smørgrav * which the proxy should not be consulted; the contents is a comma-, 74362a2681cSDag-Erling Smørgrav * or space-separated list of domain names. A single asterisk will 74462a2681cSDag-Erling Smørgrav * override all proxy variables and no transactions will be proxied 74562a2681cSDag-Erling Smørgrav * (for compatability with lynx and curl, see the discussion at 74662a2681cSDag-Erling Smørgrav * <http://curl.haxx.se/mail/archive_pre_oct_99/0009.html>). 74762a2681cSDag-Erling Smørgrav */ 74862a2681cSDag-Erling Smørgrav int 74962a2681cSDag-Erling Smørgrav fetch_no_proxy_match(const char *host) 75062a2681cSDag-Erling Smørgrav { 75162a2681cSDag-Erling Smørgrav const char *no_proxy, *p, *q; 75262a2681cSDag-Erling Smørgrav size_t h_len, d_len; 75362a2681cSDag-Erling Smørgrav 75462a2681cSDag-Erling Smørgrav if ((no_proxy = getenv("NO_PROXY")) == NULL && 75562a2681cSDag-Erling Smørgrav (no_proxy = getenv("no_proxy")) == NULL) 75662a2681cSDag-Erling Smørgrav return (0); 75762a2681cSDag-Erling Smørgrav 75862a2681cSDag-Erling Smørgrav /* asterisk matches any hostname */ 75962a2681cSDag-Erling Smørgrav if (strcmp(no_proxy, "*") == 0) 76062a2681cSDag-Erling Smørgrav return (1); 76162a2681cSDag-Erling Smørgrav 76262a2681cSDag-Erling Smørgrav h_len = strlen(host); 76362a2681cSDag-Erling Smørgrav p = no_proxy; 76462a2681cSDag-Erling Smørgrav do { 76562a2681cSDag-Erling Smørgrav /* position p at the beginning of a domain suffix */ 766facd9827SDag-Erling Smørgrav while (*p == ',' || isspace((unsigned char)*p)) 76762a2681cSDag-Erling Smørgrav p++; 76862a2681cSDag-Erling Smørgrav 76962a2681cSDag-Erling Smørgrav /* position q at the first separator character */ 77062a2681cSDag-Erling Smørgrav for (q = p; *q; ++q) 771facd9827SDag-Erling Smørgrav if (*q == ',' || isspace((unsigned char)*q)) 77262a2681cSDag-Erling Smørgrav break; 77362a2681cSDag-Erling Smørgrav 77462a2681cSDag-Erling Smørgrav d_len = q - p; 775c0d2581bSFabien Thomas if (d_len > 0 && h_len >= d_len && 77662a2681cSDag-Erling Smørgrav strncasecmp(host + h_len - d_len, 77762a2681cSDag-Erling Smørgrav p, d_len) == 0) { 77862a2681cSDag-Erling Smørgrav /* domain name matches */ 77962a2681cSDag-Erling Smørgrav return (1); 78062a2681cSDag-Erling Smørgrav } 78162a2681cSDag-Erling Smørgrav 78262a2681cSDag-Erling Smørgrav p = q + 1; 78362a2681cSDag-Erling Smørgrav } while (*q); 78462a2681cSDag-Erling Smørgrav 78562a2681cSDag-Erling Smørgrav return (0); 78662a2681cSDag-Erling Smørgrav } 787