2 * Copyright (c) 1998-2004 Dag-Erling Coïdan Smørgrav
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer
10 * in this position and unchanged.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * 3. The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 #include <sys/cdefs.h>
32 __FBSDID("$FreeBSD: src/lib/libfetch/common.c,v 1.48.4.2 2006/11/11 00:16:07 des Exp $");
34 #include <sys/param.h>
35 #include <sys/socket.h>
38 #include <netinet/in.h>
53 /*** Local data **************************************************************/
56 * Error messages for resolver errors
58 static struct fetcherr _netdb_errlist
[] = {
60 { EAI_NODATA
, FETCH_RESOLV
, "Host not found" },
62 { EAI_AGAIN
, FETCH_TEMP
, "Transient resolver failure" },
63 { EAI_FAIL
, FETCH_RESOLV
, "Non-recoverable resolver failure" },
64 { EAI_NONAME
, FETCH_RESOLV
, "No address record" },
65 { -1, FETCH_UNKNOWN
, "Unknown resolver error" }
69 static const char ENDL
[2] = "\r\n";
72 /*** Error-reporting functions ***********************************************/
75 * Map error code to string
77 static struct fetcherr
*
78 _fetch_finderr(struct fetcherr
*p
, int e
)
80 while (p
->num
!= -1 && p
->num
!= e
)
89 _fetch_seterr(struct fetcherr
*p
, int e
)
91 p
= _fetch_finderr(p
, e
);
92 fetchLastErrCode
= p
->cat
;
93 snprintf(fetchLastErrString
, MAXERRSTRING
, "%s", p
->string
);
97 * Set error code according to errno
104 fetchLastErrCode
= FETCH_OK
;
111 fetchLastErrCode
= FETCH_AUTH
;
114 case EISDIR
: /* XXX */
115 fetchLastErrCode
= FETCH_UNAVAIL
;
118 fetchLastErrCode
= FETCH_MEMORY
;
122 fetchLastErrCode
= FETCH_TEMP
;
125 fetchLastErrCode
= FETCH_EXISTS
;
128 fetchLastErrCode
= FETCH_FULL
;
136 fetchLastErrCode
= FETCH_NETWORK
;
140 fetchLastErrCode
= FETCH_ABORT
;
143 fetchLastErrCode
= FETCH_TIMEOUT
;
147 fetchLastErrCode
= FETCH_DOWN
;
150 fetchLastErrCode
= FETCH_UNKNOWN
;
152 snprintf(fetchLastErrString
, MAXERRSTRING
, "%s", strerror(errno
));
157 * Emit status message
160 _fetch_info(const char *fmt
, ...)
165 vfprintf(stderr
, fmt
, ap
);
171 /*** Network-related utility functions ***************************************/
174 * Return the default port for a scheme
177 _fetch_default_port(const char *scheme
)
181 if ((se
= getservbyname(scheme
, "tcp")) != NULL
)
182 return (ntohs(se
->s_port
));
183 if (strcasecmp(scheme
, SCHEME_FTP
) == 0)
184 return (FTP_DEFAULT_PORT
);
185 if (strcasecmp(scheme
, SCHEME_HTTP
) == 0)
186 return (HTTP_DEFAULT_PORT
);
191 * Return the default proxy port for a scheme
194 _fetch_default_proxy_port(const char *scheme
)
196 if (strcasecmp(scheme
, SCHEME_FTP
) == 0)
197 return (FTP_DEFAULT_PROXY_PORT
);
198 if (strcasecmp(scheme
, SCHEME_HTTP
) == 0)
199 return (HTTP_DEFAULT_PROXY_PORT
);
205 * Create a connection for an existing descriptor.
208 _fetch_reopen(int sd
)
212 /* allocate and fill connection structure */
213 if ((conn
= calloc(1, sizeof(*conn
))) == NULL
)
222 * Bump a connection's reference count.
225 _fetch_ref(conn_t
*conn
)
234 * Bind a socket to a specific local address
237 _fetch_bind(int sd
, int af
, const char *addr
)
239 struct addrinfo hints
, *res
, *res0
;
241 memset(&hints
, 0, sizeof(hints
));
242 hints
.ai_family
= af
;
243 hints
.ai_socktype
= SOCK_STREAM
;
244 hints
.ai_protocol
= 0;
245 if (getaddrinfo(addr
, NULL
, &hints
, &res0
) != 0)
247 for (res
= res0
; res
; res
= res
->ai_next
)
248 if (bind(sd
, res
->ai_addr
, res
->ai_addrlen
) == 0)
255 * Establish a TCP connection to the specified port on the specified host.
258 _fetch_connect(const char *host
, int port
, int af
, int verbose
)
262 const char *bindaddr
;
263 struct addrinfo hints
, *res
, *res0
;
266 DEBUG(fprintf(stderr
, "---> %s:%d\n", host
, port
));
269 _fetch_info("looking up %s", host
);
271 /* look up host name and set up socket address structure */
272 snprintf(pbuf
, sizeof(pbuf
), "%d", port
);
273 memset(&hints
, 0, sizeof(hints
));
274 hints
.ai_family
= af
;
275 hints
.ai_socktype
= SOCK_STREAM
;
276 hints
.ai_protocol
= 0;
277 if ((err
= getaddrinfo(host
, pbuf
, &hints
, &res0
)) != 0) {
281 bindaddr
= getenv("FETCH_BIND_ADDRESS");
284 _fetch_info("connecting to %s:%d", host
, port
);
287 for (sd
= -1, res
= res0
; res
; sd
= -1, res
= res
->ai_next
) {
288 if ((sd
= socket(res
->ai_family
, res
->ai_socktype
,
289 res
->ai_protocol
)) == -1)
291 if (bindaddr
!= NULL
&& *bindaddr
!= '\0' &&
292 _fetch_bind(sd
, res
->ai_family
, bindaddr
) != 0) {
293 _fetch_info("failed to bind to '%s'", bindaddr
);
297 if (connect(sd
, res
->ai_addr
, res
->ai_addrlen
) == 0)
307 if ((conn
= _fetch_reopen(sd
)) == NULL
) {
316 * Enable SSL on a connection.
319 _fetch_ssl(conn_t
*conn
, int verbose
)
323 /* Init the SSL library and context */
324 if (!SSL_library_init()){
325 fprintf(stderr
, "SSL library init failed\n");
329 SSL_load_error_strings();
331 conn
->ssl_meth
= SSLv23_client_method();
332 conn
->ssl_ctx
= SSL_CTX_new(conn
->ssl_meth
);
333 SSL_CTX_set_mode(conn
->ssl_ctx
, SSL_MODE_AUTO_RETRY
);
335 conn
->ssl
= SSL_new(conn
->ssl_ctx
);
336 if (conn
->ssl
== NULL
){
337 fprintf(stderr
, "SSL context creation failed\n");
340 SSL_set_fd(conn
->ssl
, conn
->sd
);
341 if (SSL_connect(conn
->ssl
) == -1){
342 ERR_print_errors_fp(stderr
);
350 fprintf(stderr
, "SSL connection established using %s\n",
351 SSL_get_cipher(conn
->ssl
));
352 conn
->ssl_cert
= SSL_get_peer_certificate(conn
->ssl
);
353 name
= X509_get_subject_name(conn
->ssl_cert
);
354 str
= X509_NAME_oneline(name
, 0, 0);
355 printf("Certificate subject: %s\n", str
);
357 name
= X509_get_issuer_name(conn
->ssl_cert
);
358 str
= X509_NAME_oneline(name
, 0, 0);
359 printf("Certificate issuer: %s\n", str
);
369 fprintf(stderr
, "SSL support disabled\n");
376 * Read a character from a connection w/ timeout
379 _fetch_read(conn_t
*conn
, char *buf
, size_t len
)
381 struct timeval now
, timeout
, wait
;
388 gettimeofday(&timeout
, NULL
);
389 timeout
.tv_sec
+= fetchTimeout
;
394 while (fetchTimeout
&& !FD_ISSET(conn
->sd
, &readfds
)) {
395 FD_SET(conn
->sd
, &readfds
);
396 gettimeofday(&now
, NULL
);
397 wait
.tv_sec
= timeout
.tv_sec
- now
.tv_sec
;
398 wait
.tv_usec
= timeout
.tv_usec
- now
.tv_usec
;
399 if (wait
.tv_usec
< 0) {
400 wait
.tv_usec
+= 1000000;
403 if (wait
.tv_sec
< 0) {
409 r
= select(conn
->sd
+ 1, &readfds
, NULL
, NULL
, &wait
);
411 if (errno
== EINTR
&& fetchRestartCalls
)
418 if (conn
->ssl
!= NULL
)
419 rlen
= SSL_read(conn
->ssl
, buf
, len
);
422 rlen
= read(conn
->sd
, buf
, len
);
426 if (errno
== EINTR
&& fetchRestartCalls
)
439 * Read a line of text from a connection w/ timeout
441 #define MIN_BUF_SIZE 1024
444 _fetch_getln(conn_t
*conn
)
451 if (conn
->buf
== NULL
) {
452 if ((conn
->buf
= malloc(MIN_BUF_SIZE
)) == NULL
) {
456 conn
->bufsize
= MIN_BUF_SIZE
;
463 len
= _fetch_read(conn
, &c
, 1);
468 conn
->buf
[conn
->buflen
++] = c
;
469 if (conn
->buflen
== conn
->bufsize
) {
471 tmpsize
= conn
->bufsize
* 2 + 1;
472 if ((tmp
= realloc(tmp
, tmpsize
)) == NULL
) {
477 conn
->bufsize
= tmpsize
;
481 conn
->buf
[conn
->buflen
] = '\0';
482 DEBUG(fprintf(stderr
, "<<< %s", conn
->buf
));
488 * Write to a connection w/ timeout
491 _fetch_write(conn_t
*conn
, const char *buf
, size_t len
)
495 iov
.iov_base
= __DECONST(char *, buf
);
497 return _fetch_writev(conn
, &iov
, 1);
501 * Write a vector to a connection w/ timeout
502 * Note: can modify the iovec.
505 _fetch_writev(conn_t
*conn
, struct iovec
*iov
, int iovcnt
)
507 struct timeval now
, timeout
, wait
;
514 gettimeofday(&timeout
, NULL
);
515 timeout
.tv_sec
+= fetchTimeout
;
520 while (fetchTimeout
&& !FD_ISSET(conn
->sd
, &writefds
)) {
521 FD_SET(conn
->sd
, &writefds
);
522 gettimeofday(&now
, NULL
);
523 wait
.tv_sec
= timeout
.tv_sec
- now
.tv_sec
;
524 wait
.tv_usec
= timeout
.tv_usec
- now
.tv_usec
;
525 if (wait
.tv_usec
< 0) {
526 wait
.tv_usec
+= 1000000;
529 if (wait
.tv_sec
< 0) {
535 r
= select(conn
->sd
+ 1, NULL
, &writefds
, NULL
, &wait
);
537 if (errno
== EINTR
&& fetchRestartCalls
)
544 if (conn
->ssl
!= NULL
)
545 wlen
= SSL_write(conn
->ssl
,
546 iov
->iov_base
, iov
->iov_len
);
549 wlen
= writev(conn
->sd
, iov
, iovcnt
);
551 /* we consider a short write a failure */
557 if (errno
== EINTR
&& fetchRestartCalls
)
562 while (iovcnt
> 0 && wlen
>= (ssize_t
)iov
->iov_len
) {
563 wlen
-= iov
->iov_len
;
568 iov
->iov_len
-= wlen
;
569 iov
->iov_base
= (__DECONST(char *, iov
->iov_base
)) + wlen
;
577 * Write a line of text to a connection w/ timeout
580 _fetch_putln(conn_t
*conn
, const char *str
, size_t len
)
585 DEBUG(fprintf(stderr
, ">>> %s\n", str
));
586 iov
[0].iov_base
= __DECONST(char *, str
);
587 iov
[0].iov_len
= len
;
588 iov
[1].iov_base
= __DECONST(char *, ENDL
);
589 iov
[1].iov_len
= sizeof(ENDL
);
591 ret
= _fetch_writev(conn
, &iov
[1], 1);
593 ret
= _fetch_writev(conn
, iov
, 2);
604 _fetch_close(conn_t
*conn
)
610 ret
= close(conn
->sd
);
617 /*** Directory-related utility functions *************************************/
620 _fetch_add_entry(struct url_ent
**p
, int *size
, int *len
,
621 const char *name
, struct url_stat
*us
)
630 if (*len
>= *size
- 1) {
631 tmp
= realloc(*p
, (*size
* 2 + 1) * sizeof(**p
));
637 *size
= (*size
* 2 + 1);
642 snprintf(tmp
->name
, PATH_MAX
, "%s", name
);
643 bcopy(us
, &tmp
->stat
, sizeof(*us
));
646 (++tmp
)->name
[0] = 0;
652 /*** Authentication-related utility functions ********************************/
655 _fetch_read_word(FILE *f
)
657 static char word
[1024];
659 if (fscanf(f
, " %1024s ", word
) != 1)
665 * Get authentication data for a URL from .netrc
668 _fetch_netrc_auth(struct url
*url
)
675 if ((p
= getenv("NETRC")) != NULL
) {
676 if (snprintf(fn
, sizeof(fn
), "%s", p
) >= (int)sizeof(fn
)) {
677 _fetch_info("$NETRC specifies a file name "
678 "longer than PATH_MAX");
682 if ((p
= getenv("HOME")) != NULL
) {
685 if ((pwd
= getpwuid(getuid())) == NULL
||
686 (p
= pwd
->pw_dir
) == NULL
)
689 if (snprintf(fn
, sizeof(fn
), "%s/.netrc", p
) >= (int)sizeof(fn
))
693 if ((f
= fopen(fn
, "r")) == NULL
)
695 while ((word
= _fetch_read_word(f
)) != NULL
) {
696 if (strcmp(word
, "default") == 0) {
697 DEBUG(_fetch_info("Using default .netrc settings"));
700 if (strcmp(word
, "machine") == 0 &&
701 (word
= _fetch_read_word(f
)) != NULL
&&
702 strcasecmp(word
, url
->host
) == 0) {
703 DEBUG(_fetch_info("Using .netrc settings for %s", word
));
709 while ((word
= _fetch_read_word(f
)) != NULL
) {
710 if (strcmp(word
, "login") == 0) {
711 if ((word
= _fetch_read_word(f
)) == NULL
)
713 if (snprintf(url
->user
, sizeof(url
->user
),
714 "%s", word
) > (int)sizeof(url
->user
)) {
715 _fetch_info("login name in .netrc is too long");
718 } else if (strcmp(word
, "password") == 0) {
719 if ((word
= _fetch_read_word(f
)) == NULL
)
721 if (snprintf(url
->pwd
, sizeof(url
->pwd
),
722 "%s", word
) > (int)sizeof(url
->pwd
)) {
723 _fetch_info("password in .netrc is too long");
726 } else if (strcmp(word
, "account") == 0) {
727 if ((word
= _fetch_read_word(f
)) == NULL
)
729 /* XXX not supported! */