1 /*- 2 * Copyright (c) 1998 Dag-Erling Co�dan Sm�rgrav 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 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 16 * 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. 27 */ 28 29 #include <sys/cdefs.h> 30 __FBSDID("$FreeBSD$"); 31 32 #include <sys/param.h> 33 #include <sys/socket.h> 34 #include <sys/time.h> 35 #include <sys/uio.h> 36 #include <netinet/in.h> 37 38 #include <errno.h> 39 #include <netdb.h> 40 #include <pwd.h> 41 #include <stdarg.h> 42 #include <stdlib.h> 43 #include <stdio.h> 44 #include <string.h> 45 #include <unistd.h> 46 47 #include "fetch.h" 48 #include "common.h" 49 50 51 /*** Local data **************************************************************/ 52 53 /* 54 * Error messages for resolver errors 55 */ 56 static struct fetcherr _netdb_errlist[] = { 57 { EAI_NODATA, FETCH_RESOLV, "Host not found" }, 58 { EAI_AGAIN, FETCH_TEMP, "Transient resolver failure" }, 59 { EAI_FAIL, FETCH_RESOLV, "Non-recoverable resolver failure" }, 60 { EAI_NONAME, FETCH_RESOLV, "No address record" }, 61 { -1, FETCH_UNKNOWN, "Unknown resolver error" } 62 }; 63 64 /* End-of-Line */ 65 static const char ENDL[2] = "\r\n"; 66 67 68 /*** Error-reporting functions ***********************************************/ 69 70 /* 71 * Map error code to string 72 */ 73 static struct fetcherr * 74 _fetch_finderr(struct fetcherr *p, int e) 75 { 76 while (p->num != -1 && p->num != e) 77 p++; 78 return (p); 79 } 80 81 /* 82 * Set error code 83 */ 84 void 85 _fetch_seterr(struct fetcherr *p, int e) 86 { 87 p = _fetch_finderr(p, e); 88 fetchLastErrCode = p->cat; 89 snprintf(fetchLastErrString, MAXERRSTRING, "%s", p->string); 90 } 91 92 /* 93 * Set error code according to errno 94 */ 95 void 96 _fetch_syserr(void) 97 { 98 switch (errno) { 99 case 0: 100 fetchLastErrCode = FETCH_OK; 101 break; 102 case EPERM: 103 case EACCES: 104 case EROFS: 105 case EAUTH: 106 case ENEEDAUTH: 107 fetchLastErrCode = FETCH_AUTH; 108 break; 109 case ENOENT: 110 case EISDIR: /* XXX */ 111 fetchLastErrCode = FETCH_UNAVAIL; 112 break; 113 case ENOMEM: 114 fetchLastErrCode = FETCH_MEMORY; 115 break; 116 case EBUSY: 117 case EAGAIN: 118 fetchLastErrCode = FETCH_TEMP; 119 break; 120 case EEXIST: 121 fetchLastErrCode = FETCH_EXISTS; 122 break; 123 case ENOSPC: 124 fetchLastErrCode = FETCH_FULL; 125 break; 126 case EADDRINUSE: 127 case EADDRNOTAVAIL: 128 case ENETDOWN: 129 case ENETUNREACH: 130 case ENETRESET: 131 case EHOSTUNREACH: 132 fetchLastErrCode = FETCH_NETWORK; 133 break; 134 case ECONNABORTED: 135 case ECONNRESET: 136 fetchLastErrCode = FETCH_ABORT; 137 break; 138 case ETIMEDOUT: 139 fetchLastErrCode = FETCH_TIMEOUT; 140 break; 141 case ECONNREFUSED: 142 case EHOSTDOWN: 143 fetchLastErrCode = FETCH_DOWN; 144 break; 145 default: 146 fetchLastErrCode = FETCH_UNKNOWN; 147 } 148 snprintf(fetchLastErrString, MAXERRSTRING, "%s", strerror(errno)); 149 } 150 151 152 /* 153 * Emit status message 154 */ 155 void 156 _fetch_info(const char *fmt, ...) 157 { 158 va_list ap; 159 160 va_start(ap, fmt); 161 vfprintf(stderr, fmt, ap); 162 va_end(ap); 163 fputc('\n', stderr); 164 } 165 166 167 /*** Network-related utility functions ***************************************/ 168 169 /* 170 * Return the default port for a scheme 171 */ 172 int 173 _fetch_default_port(const char *scheme) 174 { 175 struct servent *se; 176 177 if ((se = getservbyname(scheme, "tcp")) != NULL) 178 return (ntohs(se->s_port)); 179 if (strcasecmp(scheme, SCHEME_FTP) == 0) 180 return (FTP_DEFAULT_PORT); 181 if (strcasecmp(scheme, SCHEME_HTTP) == 0) 182 return (HTTP_DEFAULT_PORT); 183 return (0); 184 } 185 186 /* 187 * Return the default proxy port for a scheme 188 */ 189 int 190 _fetch_default_proxy_port(const char *scheme) 191 { 192 if (strcasecmp(scheme, SCHEME_FTP) == 0) 193 return (FTP_DEFAULT_PROXY_PORT); 194 if (strcasecmp(scheme, SCHEME_HTTP) == 0) 195 return (HTTP_DEFAULT_PROXY_PORT); 196 return (0); 197 } 198 199 200 /* 201 * Create a connection for an existing descriptor. 202 */ 203 conn_t * 204 _fetch_reopen(int sd) 205 { 206 conn_t *conn; 207 208 /* allocate and fill connection structure */ 209 if ((conn = calloc(1, sizeof(*conn))) == NULL) 210 return (NULL); 211 conn->sd = sd; 212 ++conn->ref; 213 return (conn); 214 } 215 216 217 /* 218 * Bump a connection's reference count. 219 */ 220 conn_t * 221 _fetch_ref(conn_t *conn) 222 { 223 224 ++conn->ref; 225 return (conn); 226 } 227 228 229 /* 230 * Bind a socket to a specific local address 231 */ 232 int 233 _fetch_bind(int sd, int af, const char *addr) 234 { 235 struct addrinfo hints, *res, *res0; 236 int err; 237 238 memset(&hints, 0, sizeof(hints)); 239 hints.ai_family = af; 240 hints.ai_socktype = SOCK_STREAM; 241 hints.ai_protocol = 0; 242 if ((err = getaddrinfo(addr, NULL, &hints, &res0)) != 0) 243 return (-1); 244 for (res = res0; res; res = res->ai_next) 245 if (bind(sd, res->ai_addr, res->ai_addrlen) == 0) 246 return (0); 247 return (-1); 248 } 249 250 251 /* 252 * Establish a TCP connection to the specified port on the specified host. 253 */ 254 conn_t * 255 _fetch_connect(const char *host, int port, int af, int verbose) 256 { 257 conn_t *conn; 258 char pbuf[10]; 259 const char *bindaddr; 260 struct addrinfo hints, *res, *res0; 261 int sd, err; 262 263 DEBUG(fprintf(stderr, "---> %s:%d\n", host, port)); 264 265 if (verbose) 266 _fetch_info("looking up %s", host); 267 268 /* look up host name and set up socket address structure */ 269 snprintf(pbuf, sizeof(pbuf), "%d", port); 270 memset(&hints, 0, sizeof(hints)); 271 hints.ai_family = af; 272 hints.ai_socktype = SOCK_STREAM; 273 hints.ai_protocol = 0; 274 if ((err = getaddrinfo(host, pbuf, &hints, &res0)) != 0) { 275 _netdb_seterr(err); 276 return (NULL); 277 } 278 bindaddr = getenv("FETCH_BIND_ADDRESS"); 279 280 if (verbose) 281 _fetch_info("connecting to %s:%d", host, port); 282 283 /* try to connect */ 284 for (sd = -1, res = res0; res; sd = -1, res = res->ai_next) { 285 if ((sd = socket(res->ai_family, res->ai_socktype, 286 res->ai_protocol)) == -1) 287 continue; 288 if (bindaddr != NULL && *bindaddr != '\0' && 289 _fetch_bind(sd, res->ai_family, bindaddr) != 0) { 290 _fetch_info("failed to bind to '%s'", bindaddr); 291 close(sd); 292 continue; 293 } 294 if (connect(sd, res->ai_addr, res->ai_addrlen) == 0) 295 break; 296 close(sd); 297 } 298 freeaddrinfo(res0); 299 if (sd == -1) { 300 _fetch_syserr(); 301 return (NULL); 302 } 303 304 if ((conn = _fetch_reopen(sd)) == NULL) { 305 _fetch_syserr(); 306 close(sd); 307 } 308 return (conn); 309 } 310 311 312 /* 313 * Enable SSL on a connection. 314 */ 315 int 316 _fetch_ssl(conn_t *conn, int verbose) 317 { 318 319 #ifdef WITH_SSL 320 /* Init the SSL library and context */ 321 if (!SSL_library_init()){ 322 fprintf(stderr, "SSL library init failed\n"); 323 return (-1); 324 } 325 326 SSL_load_error_strings(); 327 328 conn->ssl_meth = SSLv23_client_method(); 329 conn->ssl_ctx = SSL_CTX_new(conn->ssl_meth); 330 SSL_CTX_set_mode(conn->ssl_ctx, SSL_MODE_AUTO_RETRY); 331 332 conn->ssl = SSL_new(conn->ssl_ctx); 333 if (conn->ssl == NULL){ 334 fprintf(stderr, "SSL context creation failed\n"); 335 return (-1); 336 } 337 SSL_set_fd(conn->ssl, conn->sd); 338 if (SSL_connect(conn->ssl) == -1){ 339 ERR_print_errors_fp(stderr); 340 return (-1); 341 } 342 343 if (verbose) { 344 X509_NAME *name; 345 char *str; 346 347 fprintf(stderr, "SSL connection established using %s\n", 348 SSL_get_cipher(conn->ssl)); 349 conn->ssl_cert = SSL_get_peer_certificate(conn->ssl); 350 name = X509_get_subject_name(conn->ssl_cert); 351 str = X509_NAME_oneline(name, 0, 0); 352 printf("Certificate subject: %s\n", str); 353 free(str); 354 name = X509_get_issuer_name(conn->ssl_cert); 355 str = X509_NAME_oneline(name, 0, 0); 356 printf("Certificate issuer: %s\n", str); 357 free(str); 358 } 359 360 return (0); 361 #else 362 (void)conn; 363 (void)verbose; 364 fprintf(stderr, "SSL support disabled\n"); 365 return (-1); 366 #endif 367 } 368 369 370 /* 371 * Read a character from a connection w/ timeout 372 */ 373 ssize_t 374 _fetch_read(conn_t *conn, char *buf, size_t len) 375 { 376 struct timeval now, timeout, wait; 377 fd_set readfds; 378 ssize_t rlen, total; 379 int r; 380 381 if (fetchTimeout) { 382 FD_ZERO(&readfds); 383 gettimeofday(&timeout, NULL); 384 timeout.tv_sec += fetchTimeout; 385 } 386 387 total = 0; 388 while (len > 0) { 389 while (fetchTimeout && !FD_ISSET(conn->sd, &readfds)) { 390 FD_SET(conn->sd, &readfds); 391 gettimeofday(&now, NULL); 392 wait.tv_sec = timeout.tv_sec - now.tv_sec; 393 wait.tv_usec = timeout.tv_usec - now.tv_usec; 394 if (wait.tv_usec < 0) { 395 wait.tv_usec += 1000000; 396 wait.tv_sec--; 397 } 398 if (wait.tv_sec < 0) { 399 errno = ETIMEDOUT; 400 _fetch_syserr(); 401 return (-1); 402 } 403 errno = 0; 404 r = select(conn->sd + 1, &readfds, NULL, NULL, &wait); 405 if (r == -1) { 406 if (errno == EINTR && fetchRestartCalls) 407 continue; 408 _fetch_syserr(); 409 return (-1); 410 } 411 } 412 #ifdef WITH_SSL 413 if (conn->ssl != NULL) 414 rlen = SSL_read(conn->ssl, buf, len); 415 else 416 #endif 417 rlen = read(conn->sd, buf, len); 418 if (rlen == 0) 419 break; 420 if (rlen < 0) { 421 if (errno == EINTR && fetchRestartCalls) 422 continue; 423 return (-1); 424 } 425 len -= rlen; 426 buf += rlen; 427 total += rlen; 428 } 429 return (total); 430 } 431 432 433 /* 434 * Read a line of text from a connection w/ timeout 435 */ 436 #define MIN_BUF_SIZE 1024 437 438 int 439 _fetch_getln(conn_t *conn) 440 { 441 char *tmp; 442 size_t tmpsize; 443 ssize_t len; 444 char c; 445 446 if (conn->buf == NULL) { 447 if ((conn->buf = malloc(MIN_BUF_SIZE)) == NULL) { 448 errno = ENOMEM; 449 return (-1); 450 } 451 conn->bufsize = MIN_BUF_SIZE; 452 } 453 454 conn->buf[0] = '\0'; 455 conn->buflen = 0; 456 457 do { 458 len = _fetch_read(conn, &c, 1); 459 if (len == -1) 460 return (-1); 461 if (len == 0) 462 break; 463 conn->buf[conn->buflen++] = c; 464 if (conn->buflen == conn->bufsize) { 465 tmp = conn->buf; 466 tmpsize = conn->bufsize * 2 + 1; 467 if ((tmp = realloc(tmp, tmpsize)) == NULL) { 468 errno = ENOMEM; 469 return (-1); 470 } 471 conn->buf = tmp; 472 conn->bufsize = tmpsize; 473 } 474 } while (c != '\n'); 475 476 conn->buf[conn->buflen] = '\0'; 477 DEBUG(fprintf(stderr, "<<< %s", conn->buf)); 478 return (0); 479 } 480 481 482 /* 483 * Write to a connection w/ timeout 484 */ 485 ssize_t 486 _fetch_write(conn_t *conn, const char *buf, size_t len) 487 { 488 struct iovec iov; 489 490 iov.iov_base = __DECONST(char *, buf); 491 iov.iov_len = len; 492 return _fetch_writev(conn, &iov, 1); 493 } 494 495 /* 496 * Write a vector to a connection w/ timeout 497 * Note: can modify the iovec. 498 */ 499 ssize_t 500 _fetch_writev(conn_t *conn, struct iovec *iov, int iovcnt) 501 { 502 struct timeval now, timeout, wait; 503 fd_set writefds; 504 ssize_t wlen, total; 505 int r; 506 507 if (fetchTimeout) { 508 FD_ZERO(&writefds); 509 gettimeofday(&timeout, NULL); 510 timeout.tv_sec += fetchTimeout; 511 } 512 513 total = 0; 514 while (iovcnt > 0) { 515 while (fetchTimeout && !FD_ISSET(conn->sd, &writefds)) { 516 FD_SET(conn->sd, &writefds); 517 gettimeofday(&now, NULL); 518 wait.tv_sec = timeout.tv_sec - now.tv_sec; 519 wait.tv_usec = timeout.tv_usec - now.tv_usec; 520 if (wait.tv_usec < 0) { 521 wait.tv_usec += 1000000; 522 wait.tv_sec--; 523 } 524 if (wait.tv_sec < 0) { 525 errno = ETIMEDOUT; 526 _fetch_syserr(); 527 return (-1); 528 } 529 errno = 0; 530 r = select(conn->sd + 1, NULL, &writefds, NULL, &wait); 531 if (r == -1) { 532 if (errno == EINTR && fetchRestartCalls) 533 continue; 534 return (-1); 535 } 536 } 537 errno = 0; 538 #ifdef WITH_SSL 539 if (conn->ssl != NULL) 540 wlen = SSL_write(conn->ssl, 541 iov->iov_base, iov->iov_len); 542 else 543 #endif 544 wlen = writev(conn->sd, iov, iovcnt); 545 if (wlen == 0) { 546 /* we consider a short write a failure */ 547 errno = EPIPE; 548 _fetch_syserr(); 549 return (-1); 550 } 551 if (wlen < 0) { 552 if (errno == EINTR && fetchRestartCalls) 553 continue; 554 return (-1); 555 } 556 total += wlen; 557 while (iovcnt > 0 && wlen >= (ssize_t)iov->iov_len) { 558 wlen -= iov->iov_len; 559 iov++; 560 iovcnt--; 561 } 562 if (iovcnt > 0) { 563 iov->iov_len -= wlen; 564 iov->iov_base = __DECONST(char *, iov->iov_base) + wlen; 565 } 566 } 567 return (total); 568 } 569 570 571 /* 572 * Write a line of text to a connection w/ timeout 573 */ 574 int 575 _fetch_putln(conn_t *conn, const char *str, size_t len) 576 { 577 struct iovec iov[2]; 578 int ret; 579 580 DEBUG(fprintf(stderr, ">>> %s\n", str)); 581 iov[0].iov_base = __DECONST(char *, str); 582 iov[0].iov_len = len; 583 iov[1].iov_base = __DECONST(char *, ENDL); 584 iov[1].iov_len = sizeof(ENDL); 585 if (len == 0) 586 ret = _fetch_writev(conn, &iov[1], 1); 587 else 588 ret = _fetch_writev(conn, iov, 2); 589 if (ret == -1) 590 return (-1); 591 return (0); 592 } 593 594 595 /* 596 * Close connection 597 */ 598 int 599 _fetch_close(conn_t *conn) 600 { 601 int ret; 602 603 if (--conn->ref > 0) 604 return (0); 605 ret = close(conn->sd); 606 free(conn); 607 return (ret); 608 } 609 610 611 /*** Directory-related utility functions *************************************/ 612 613 int 614 _fetch_add_entry(struct url_ent **p, int *size, int *len, 615 const char *name, struct url_stat *us) 616 { 617 struct url_ent *tmp; 618 619 if (*p == NULL) { 620 *size = 0; 621 *len = 0; 622 } 623 624 if (*len >= *size - 1) { 625 tmp = realloc(*p, (*size * 2 + 1) * sizeof(**p)); 626 if (tmp == NULL) { 627 errno = ENOMEM; 628 _fetch_syserr(); 629 return (-1); 630 } 631 *size = (*size * 2 + 1); 632 *p = tmp; 633 } 634 635 tmp = *p + *len; 636 snprintf(tmp->name, PATH_MAX, "%s", name); 637 bcopy(us, &tmp->stat, sizeof(*us)); 638 639 (*len)++; 640 (++tmp)->name[0] = 0; 641 642 return (0); 643 } 644 645 646 /*** Authentication-related utility functions ********************************/ 647 648 static const char * 649 _fetch_read_word(FILE *f) 650 { 651 static char word[1024]; 652 653 if (fscanf(f, " %1024s ", word) != 1) 654 return (NULL); 655 return (word); 656 } 657 658 /* 659 * Get authentication data for a URL from .netrc 660 */ 661 int 662 _fetch_netrc_auth(struct url *url) 663 { 664 char fn[PATH_MAX]; 665 const char *word; 666 char *p; 667 FILE *f; 668 669 if ((p = getenv("NETRC")) != NULL) { 670 if (snprintf(fn, sizeof(fn), "%s", p) >= (int)sizeof(fn)) { 671 _fetch_info("$NETRC specifies a file name " 672 "longer than PATH_MAX"); 673 return (-1); 674 } 675 } else { 676 if ((p = getenv("HOME")) != NULL) { 677 struct passwd *pwd; 678 679 if ((pwd = getpwuid(getuid())) == NULL || 680 (p = pwd->pw_dir) == NULL) 681 return (-1); 682 } 683 if (snprintf(fn, sizeof(fn), "%s/.netrc", p) >= (int)sizeof(fn)) 684 return (-1); 685 } 686 687 if ((f = fopen(fn, "r")) == NULL) 688 return (-1); 689 while ((word = _fetch_read_word(f)) != NULL) { 690 if (strcmp(word, "default") == 0) { 691 DEBUG(_fetch_info("Using default .netrc settings")); 692 break; 693 } 694 if (strcmp(word, "machine") == 0 && 695 (word = _fetch_read_word(f)) != NULL && 696 strcasecmp(word, url->host) == 0) { 697 DEBUG(_fetch_info("Using .netrc settings for %s", word)); 698 break; 699 } 700 } 701 if (word == NULL) 702 goto ferr; 703 while ((word = _fetch_read_word(f)) != NULL) { 704 if (strcmp(word, "login") == 0) { 705 if ((word = _fetch_read_word(f)) == NULL) 706 goto ferr; 707 if (snprintf(url->user, sizeof(url->user), 708 "%s", word) > (int)sizeof(url->user)) { 709 _fetch_info("login name in .netrc is too long"); 710 url->user[0] = '\0'; 711 } 712 } else if (strcmp(word, "password") == 0) { 713 if ((word = _fetch_read_word(f)) == NULL) 714 goto ferr; 715 if (snprintf(url->pwd, sizeof(url->pwd), 716 "%s", word) > (int)sizeof(url->pwd)) { 717 _fetch_info("password in .netrc is too long"); 718 url->pwd[0] = '\0'; 719 } 720 } else if (strcmp(word, "account") == 0) { 721 if ((word = _fetch_read_word(f)) == NULL) 722 goto ferr; 723 /* XXX not supported! */ 724 } else { 725 break; 726 } 727 } 728 fclose(f); 729 return (0); 730 ferr: 731 fclose(f); 732 return (-1); 733 } 734