PageRenderTime 65ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/lib/libfetch/common.c

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