1 /* $NetBSD: common.c,v 1.21 2009/10/15 12:36:57 joerg Exp $ */
3 * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav
4 * Copyright (c) 2008 Joerg Sonnenberger <joerg@NetBSD.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
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
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.
30 * $FreeBSD: common.c,v 1.53 2007/12/19 00:26:36 des Exp $
40 #include <sys/types.h>
41 #include <sys/socket.h>
45 #include <netinet/in.h>
46 #include <arpa/inet.h>
50 #if defined(HAVE_INTTYPES_H) || defined(NETBSD)
54 #include <nbcompat/netdb.h>
68 #define DECONST(x,y) ((x)(uintptr_t)(y))
71 /*** Local data **************************************************************/
74 * Error messages for resolver errors
76 static struct fetcherr netdb_errlist
[] = {
78 { EAI_NODATA
, FETCH_RESOLV
, "Host not found" },
80 { EAI_AGAIN
, FETCH_TEMP
, "Transient resolver failure" },
81 { EAI_FAIL
, FETCH_RESOLV
, "Non-recoverable resolver failure" },
82 { EAI_NONAME
, FETCH_RESOLV
, "No address record" },
83 { -1, FETCH_UNKNOWN
, "Unknown resolver error" }
87 static const char ENDL
[2] = "\r\n";
90 /*** Error-reporting functions ***********************************************/
93 * Map error code to string
95 static struct fetcherr
*
96 fetch_finderr(struct fetcherr
*p
, int e
)
98 while (p
->num
!= -1 && p
->num
!= e
)
107 fetch_seterr(struct fetcherr
*p
, int e
)
109 p
= fetch_finderr(p
, e
);
110 fetchLastErrCode
= p
->cat
;
111 snprintf(fetchLastErrString
, MAXERRSTRING
, "%s", p
->string
);
115 * Set error code according to errno
122 fetchLastErrCode
= FETCH_OK
;
133 fetchLastErrCode
= FETCH_AUTH
;
136 case EISDIR
: /* XXX */
137 fetchLastErrCode
= FETCH_UNAVAIL
;
140 fetchLastErrCode
= FETCH_MEMORY
;
144 fetchLastErrCode
= FETCH_TEMP
;
147 fetchLastErrCode
= FETCH_EXISTS
;
150 fetchLastErrCode
= FETCH_FULL
;
158 fetchLastErrCode
= FETCH_NETWORK
;
162 fetchLastErrCode
= FETCH_ABORT
;
165 fetchLastErrCode
= FETCH_TIMEOUT
;
169 fetchLastErrCode
= FETCH_DOWN
;
172 fetchLastErrCode
= FETCH_UNKNOWN
;
174 snprintf(fetchLastErrString
, MAXERRSTRING
, "%s", strerror(errno
));
179 * Emit status message
182 fetch_info(const char *fmt
, ...)
187 vfprintf(stderr
, fmt
, ap
);
193 /*** Network-related utility functions ***************************************/
196 * Return the default port for a scheme
199 fetch_default_port(const char *scheme
)
203 if ((se
= getservbyname(scheme
, "tcp")) != NULL
)
204 return (ntohs(se
->s_port
));
205 if (strcasecmp(scheme
, SCHEME_FTP
) == 0)
206 return (FTP_DEFAULT_PORT
);
207 if (strcasecmp(scheme
, SCHEME_HTTP
) == 0)
208 return (HTTP_DEFAULT_PORT
);
213 * Return the default proxy port for a scheme
216 fetch_default_proxy_port(const char *scheme
)
218 if (strcasecmp(scheme
, SCHEME_FTP
) == 0)
219 return (FTP_DEFAULT_PROXY_PORT
);
220 if (strcasecmp(scheme
, SCHEME_HTTP
) == 0)
221 return (HTTP_DEFAULT_PROXY_PORT
);
227 * Create a connection for an existing descriptor.
234 /* allocate and fill connection structure */
235 if ((conn
= calloc(1, sizeof(*conn
))) == NULL
)
237 conn
->next_buf
= NULL
;
247 * Bump a connection's reference count.
250 fetch_ref(conn_t
*conn
)
259 * Bind a socket to a specific local address
262 fetch_bind(int sd
, int af
, const char *addr
)
264 struct addrinfo hints
, *res
, *res0
;
266 memset(&hints
, 0, sizeof(hints
));
267 hints
.ai_family
= af
;
268 hints
.ai_socktype
= SOCK_STREAM
;
269 hints
.ai_protocol
= 0;
270 if (getaddrinfo(addr
, NULL
, &hints
, &res0
))
272 for (res
= res0
; res
; res
= res
->ai_next
) {
273 if (bind(sd
, res
->ai_addr
, res
->ai_addrlen
) == 0)
281 * Establish a TCP connection to the specified port on the specified host.
284 fetch_connect(const char *host
, int port
, int af
, int verbose
)
288 const char *bindaddr
;
289 struct addrinfo hints
, *res
, *res0
;
293 fetch_info("looking up %s", host
);
295 /* look up host name and set up socket address structure */
296 snprintf(pbuf
, sizeof(pbuf
), "%d", port
);
297 memset(&hints
, 0, sizeof(hints
));
298 hints
.ai_family
= af
;
299 hints
.ai_socktype
= SOCK_STREAM
;
300 hints
.ai_protocol
= 0;
301 if ((error
= getaddrinfo(host
, pbuf
, &hints
, &res0
)) != 0) {
305 bindaddr
= getenv("FETCH_BIND_ADDRESS");
308 fetch_info("connecting to %s:%d", host
, port
);
311 for (sd
= -1, res
= res0
; res
; sd
= -1, res
= res
->ai_next
) {
312 if ((sd
= socket(res
->ai_family
, res
->ai_socktype
,
313 res
->ai_protocol
)) == -1)
315 if (bindaddr
!= NULL
&& *bindaddr
!= '\0' &&
316 fetch_bind(sd
, res
->ai_family
, bindaddr
) != 0) {
317 fetch_info("failed to bind to '%s'", bindaddr
);
321 if (connect(sd
, res
->ai_addr
, res
->ai_addrlen
) == 0)
331 if ((conn
= fetch_reopen(sd
)) == NULL
) {
340 * Enable SSL on a connection.
343 fetch_ssl(conn_t
*conn
, int verbose
)
347 /* Init the SSL library and context */
348 if (!SSL_library_init()){
349 fprintf(stderr
, "SSL library init failed\n");
353 SSL_load_error_strings();
355 conn
->ssl_meth
= SSLv23_client_method();
356 conn
->ssl_ctx
= SSL_CTX_new(conn
->ssl_meth
);
357 SSL_CTX_set_mode(conn
->ssl_ctx
, SSL_MODE_AUTO_RETRY
);
359 conn
->ssl
= SSL_new(conn
->ssl_ctx
);
360 if (conn
->ssl
== NULL
){
361 fprintf(stderr
, "SSL context creation failed\n");
364 SSL_set_fd(conn
->ssl
, conn
->sd
);
365 if (SSL_connect(conn
->ssl
) == -1){
366 ERR_print_errors_fp(stderr
);
374 fprintf(stderr
, "SSL connection established using %s\n",
375 SSL_get_cipher(conn
->ssl
));
376 conn
->ssl_cert
= SSL_get_peer_certificate(conn
->ssl
);
377 name
= X509_get_subject_name(conn
->ssl_cert
);
378 str
= X509_NAME_oneline(name
, 0, 0);
379 printf("Certificate subject: %s\n", str
);
381 name
= X509_get_issuer_name(conn
->ssl_cert
);
382 str
= X509_NAME_oneline(name
, 0, 0);
383 printf("Certificate issuer: %s\n", str
);
391 fprintf(stderr
, "SSL support disabled\n");
398 * Read a character from a connection w/ timeout
401 fetch_read(conn_t
*conn
, char *buf
, size_t len
)
403 struct timeval now
, timeout
, waittv
;
411 if (conn
->next_len
!= 0) {
412 if (conn
->next_len
< len
)
413 len
= conn
->next_len
;
414 memmove(buf
, conn
->next_buf
, len
);
415 conn
->next_len
-= len
;
416 conn
->next_buf
+= len
;
422 gettimeofday(&timeout
, NULL
);
423 timeout
.tv_sec
+= fetchTimeout
;
427 while (fetchTimeout
&& !FD_ISSET(conn
->sd
, &readfds
)) {
428 FD_SET(conn
->sd
, &readfds
);
429 gettimeofday(&now
, NULL
);
430 waittv
.tv_sec
= timeout
.tv_sec
- now
.tv_sec
;
431 waittv
.tv_usec
= timeout
.tv_usec
- now
.tv_usec
;
432 if (waittv
.tv_usec
< 0) {
433 waittv
.tv_usec
+= 1000000;
436 if (waittv
.tv_sec
< 0) {
442 r
= select(conn
->sd
+ 1, &readfds
, NULL
, NULL
, &waittv
);
444 if (errno
== EINTR
&& fetchRestartCalls
)
451 if (conn
->ssl
!= NULL
)
452 rlen
= SSL_read(conn
->ssl
, buf
, len
);
455 rlen
= read(conn
->sd
, buf
, len
);
459 if (errno
!= EINTR
|| !fetchRestartCalls
)
467 * Read a line of text from a connection w/ timeout
469 #define MIN_BUF_SIZE 1024
472 fetch_getln(conn_t
*conn
)
478 if (conn
->buf
== NULL
) {
479 if ((conn
->buf
= malloc(MIN_BUF_SIZE
)) == NULL
) {
483 conn
->bufsize
= MIN_BUF_SIZE
;
491 * conn->bufsize != conn->buflen at this point,
492 * so the buffer can be NUL-terminated below for
493 * the case of len == 0.
495 len
= fetch_read(conn
, conn
->buf
+ conn
->buflen
,
496 conn
->bufsize
- conn
->buflen
);
501 next
= memchr(conn
->buf
+ conn
->buflen
, '\n', len
);
503 if (conn
->buflen
== conn
->bufsize
&& next
== NULL
) {
505 tmpsize
= conn
->bufsize
* 2;
506 if (tmpsize
< conn
->bufsize
) {
510 if ((tmp
= realloc(tmp
, tmpsize
)) == NULL
) {
515 conn
->bufsize
= tmpsize
;
517 } while (next
== NULL
);
521 conn
->next_buf
= next
+ 1;
522 conn
->next_len
= conn
->buflen
- (conn
->next_buf
- conn
->buf
);
523 conn
->buflen
= next
- conn
->buf
;
525 conn
->buf
[conn
->buflen
] = '\0';
533 * Write to a connection w/ timeout
536 fetch_write(conn_t
*conn
, const char *buf
, size_t len
)
540 iov
.iov_base
= DECONST(char *, buf
);
542 return fetch_writev(conn
, &iov
, 1);
546 * Write a vector to a connection w/ timeout
547 * Note: can modify the iovec.
550 fetch_writev(conn_t
*conn
, struct iovec
*iov
, int iovcnt
)
552 struct timeval now
, timeout
, waittv
;
559 gettimeofday(&timeout
, NULL
);
560 timeout
.tv_sec
+= fetchTimeout
;
565 while (fetchTimeout
&& !FD_ISSET(conn
->sd
, &writefds
)) {
566 FD_SET(conn
->sd
, &writefds
);
567 gettimeofday(&now
, NULL
);
568 waittv
.tv_sec
= timeout
.tv_sec
- now
.tv_sec
;
569 waittv
.tv_usec
= timeout
.tv_usec
- now
.tv_usec
;
570 if (waittv
.tv_usec
< 0) {
571 waittv
.tv_usec
+= 1000000;
574 if (waittv
.tv_sec
< 0) {
580 r
= select(conn
->sd
+ 1, NULL
, &writefds
, NULL
, &waittv
);
582 if (errno
== EINTR
&& fetchRestartCalls
)
589 if (conn
->ssl
!= NULL
)
590 wlen
= SSL_write(conn
->ssl
,
591 iov
->iov_base
, iov
->iov_len
);
594 wlen
= writev(conn
->sd
, iov
, iovcnt
);
596 /* we consider a short write a failure */
602 if (errno
== EINTR
&& fetchRestartCalls
)
607 while (iovcnt
> 0 && wlen
>= (ssize_t
)iov
->iov_len
) {
608 wlen
-= iov
->iov_len
;
613 iov
->iov_len
-= wlen
;
614 iov
->iov_base
= DECONST(char *, iov
->iov_base
) + wlen
;
622 * Write a line of text to a connection w/ timeout
625 fetch_putln(conn_t
*conn
, const char *str
, size_t len
)
630 iov
[0].iov_base
= DECONST(char *, str
);
631 iov
[0].iov_len
= len
;
632 iov
[1].iov_base
= DECONST(char *, ENDL
);
633 iov
[1].iov_len
= sizeof(ENDL
);
635 ret
= fetch_writev(conn
, &iov
[1], 1);
637 ret
= fetch_writev(conn
, iov
, 2);
648 fetch_close(conn_t
*conn
)
654 ret
= close(conn
->sd
);
661 /*** Directory-related utility functions *************************************/
664 fetch_add_entry(struct url_list
*ue
, struct url
*base
, const char *name
,
669 size_t base_doc_len
, name_len
, i
;
672 if (strchr(name
, '/') != NULL
||
673 strcmp(name
, "..") == 0 ||
674 strcmp(name
, ".") == 0)
677 if (strcmp(base
->doc
, "/") == 0)
680 base_doc_len
= strlen(base
->doc
);
683 for (i
= 0; name
[i
] != '\0'; ++i
) {
684 if ((!pre_quoted
&& name
[i
] == '%') ||
685 !fetch_urlpath_safe(name
[i
]))
691 tmp_name
= malloc( base_doc_len
+ name_len
+ 1);
692 if (tmp_name
== NULL
) {
698 if (ue
->length
+ 1 >= ue
->alloc_size
) {
699 tmp
= realloc(ue
->urls
, (ue
->alloc_size
* 2 + 1) * sizeof(*tmp
));
706 ue
->alloc_size
= ue
->alloc_size
* 2 + 1;
710 tmp
= ue
->urls
+ ue
->length
;
711 strcpy(tmp
->scheme
, base
->scheme
);
712 strcpy(tmp
->user
, base
->user
);
713 strcpy(tmp
->pwd
, base
->pwd
);
714 strcpy(tmp
->host
, base
->host
);
715 tmp
->port
= base
->port
;
717 memcpy(tmp
->doc
, base
->doc
, base_doc_len
);
718 tmp
->doc
[base_doc_len
] = '/';
720 for (i
= base_doc_len
+ 1; *name
!= '\0'; ++name
) {
721 if ((!pre_quoted
&& *name
== '%') ||
722 !fetch_urlpath_safe(*name
)) {
724 c
= (unsigned char)*name
/ 16;
726 tmp
->doc
[i
++] = '0' + c
;
728 tmp
->doc
[i
++] = 'a' - 10 + c
;
729 c
= (unsigned char)*name
% 16;
731 tmp
->doc
[i
++] = '0' + c
;
733 tmp
->doc
[i
++] = 'a' - 10 + c
;
735 tmp
->doc
[i
++] = *name
;
742 tmp
->last_modified
= -1;
750 fetchInitURLList(struct url_list
*ue
)
752 ue
->length
= ue
->alloc_size
= 0;
757 fetchAppendURLList(struct url_list
*dst
, const struct url_list
*src
)
761 len
= dst
->length
+ src
->length
;
762 if (len
> dst
->alloc_size
) {
765 tmp
= realloc(dst
->urls
, len
* sizeof(*tmp
));
771 dst
->alloc_size
= len
;
775 for (i
= 0, j
= dst
->length
; i
< src
->length
; ++i
, ++j
) {
776 dst
->urls
[j
] = src
->urls
[i
];
777 dst
->urls
[j
].doc
= strdup(src
->urls
[i
].doc
);
778 if (dst
->urls
[j
].doc
== NULL
) {
780 free(dst
->urls
[j
].doc
);
791 fetchFreeURLList(struct url_list
*ue
)
795 for (i
= 0; i
< ue
->length
; ++i
)
796 free(ue
->urls
[i
].doc
);
798 ue
->length
= ue
->alloc_size
= 0;
802 /*** Authentication-related utility functions ********************************/
805 fetch_read_word(FILE *f
)
807 static char word
[1024];
809 if (fscanf(f
, " %1023s ", word
) != 1)
815 * Get authentication data for a URL from .netrc
818 fetch_netrc_auth(struct url
*url
)
825 if ((p
= getenv("NETRC")) != NULL
) {
826 if (snprintf(fn
, sizeof(fn
), "%s", p
) >= (int)sizeof(fn
)) {
827 fetch_info("$NETRC specifies a file name "
828 "longer than PATH_MAX");
832 if ((p
= getenv("HOME")) != NULL
) {
835 if ((pwd
= getpwuid(getuid())) == NULL
||
836 (p
= pwd
->pw_dir
) == NULL
)
839 if (snprintf(fn
, sizeof(fn
), "%s/.netrc", p
) >= (int)sizeof(fn
))
843 if ((f
= fopen(fn
, "r")) == NULL
)
845 while ((word
= fetch_read_word(f
)) != NULL
) {
846 if (strcmp(word
, "default") == 0)
848 if (strcmp(word
, "machine") == 0 &&
849 (word
= fetch_read_word(f
)) != NULL
&&
850 strcasecmp(word
, url
->host
) == 0) {
856 while ((word
= fetch_read_word(f
)) != NULL
) {
857 if (strcmp(word
, "login") == 0) {
858 if ((word
= fetch_read_word(f
)) == NULL
)
860 if (snprintf(url
->user
, sizeof(url
->user
),
861 "%s", word
) > (int)sizeof(url
->user
)) {
862 fetch_info("login name in .netrc is too long");
865 } else if (strcmp(word
, "password") == 0) {
866 if ((word
= fetch_read_word(f
)) == NULL
)
868 if (snprintf(url
->pwd
, sizeof(url
->pwd
),
869 "%s", word
) > (int)sizeof(url
->pwd
)) {
870 fetch_info("password in .netrc is too long");
873 } else if (strcmp(word
, "account") == 0) {
874 if ((word
= fetch_read_word(f
)) == NULL
)
876 /* XXX not supported! */
889 * The no_proxy environment variable specifies a set of domains for
890 * which the proxy should not be consulted; the contents is a comma-,
891 * or space-separated list of domain names. A single asterisk will
892 * override all proxy variables and no transactions will be proxied
893 * (for compatability with lynx and curl, see the discussion at
894 * <http://curl.haxx.se/mail/archive_pre_oct_99/0009.html>).
897 fetch_no_proxy_match(const char *host
)
899 const char *no_proxy
, *p
, *q
;
902 if ((no_proxy
= getenv("NO_PROXY")) == NULL
&&
903 (no_proxy
= getenv("no_proxy")) == NULL
)
906 /* asterisk matches any hostname */
907 if (strcmp(no_proxy
, "*") == 0)
910 h_len
= strlen(host
);
913 /* position p at the beginning of a domain suffix */
914 while (*p
== ',' || isspace((unsigned char)*p
))
917 /* position q at the first separator character */
919 if (*q
== ',' || isspace((unsigned char)*q
))
923 if (d_len
> 0 && h_len
> d_len
&&
924 strncasecmp(host
+ h_len
- d_len
,
926 /* domain name matches */
938 ssize_t (*io_read
)(void *, void *, size_t);
939 ssize_t (*io_write
)(void *, const void *, size_t);
940 void (*io_close
)(void *);
944 fetchIO_close(fetchIO
*f
)
946 if (f
->io_close
!= NULL
)
947 (*f
->io_close
)(f
->io_cookie
);
953 fetchIO_unopen(void *io_cookie
, ssize_t (*io_read
)(void *, void *, size_t),
954 ssize_t (*io_write
)(void *, const void *, size_t),
955 void (*io_close
)(void *))
959 f
= malloc(sizeof(*f
));
963 f
->io_cookie
= io_cookie
;
964 f
->io_read
= io_read
;
965 f
->io_write
= io_write
;
966 f
->io_close
= io_close
;
972 fetchIO_read(fetchIO
*f
, void *buf
, size_t len
)
974 if (f
->io_read
== NULL
)
976 return (*f
->io_read
)(f
->io_cookie
, buf
, len
);
980 fetchIO_write(fetchIO
*f
, const void *buf
, size_t len
)
982 if (f
->io_read
== NULL
)
984 return (*f
->io_write
)(f
->io_cookie
, buf
, len
);