[BACK]Return to fetch.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / ftp

Diff for /src/usr.bin/ftp/fetch.c between version 1.60 and 1.61

version 1.60, 2006/04/25 05:45:20 version 1.61, 2006/05/16 16:20:42
Line 63 
Line 63 
 #include <fcntl.h>  #include <fcntl.h>
 #include <signal.h>  #include <signal.h>
 #include <stdio.h>  #include <stdio.h>
   #include <stdarg.h>
 #include <errno.h>  #include <errno.h>
 #include <stdlib.h>  #include <stdlib.h>
 #include <string.h>  #include <string.h>
 #include <unistd.h>  #include <unistd.h>
 #include <util.h>  #include <util.h>
   
   #ifndef SMALL
   #include <openssl/ssl.h>
   #include <openssl/err.h>
   #else
   #define SSL void
   #endif
   
 #include "ftp_var.h"  #include "ftp_var.h"
   
 static int      url_get(const char *, const char *, const char *);  static int      url_get(const char *, const char *, const char *);
Line 76 
Line 84 
 void            abortfile(int);  void            abortfile(int);
 char            hextochar(const char *);  char            hextochar(const char *);
 char            *urldecode(const char *);  char            *urldecode(const char *);
   int             ftp_printf(FILE *, SSL *, const char *, ...) __attribute__((format(printf, 3, 4)));
   char            *ftp_readline(FILE *, SSL *, size_t *);
   int             ftp_read(FILE *, SSL *, char *, size_t);
   #ifndef SMALL
   int             proxy_connect(int, char *);
   int             SSL_vprintf(SSL *, const char *, va_list);
   char            *SSL_readline(SSL *, size_t *);
   #endif
   
 #define FTP_URL         "ftp://"        /* ftp URL prefix */  #define FTP_URL         "ftp://"        /* ftp URL prefix */
 #define HTTP_URL        "http://"       /* http URL prefix */  #define HTTP_URL        "http://"       /* http URL prefix */
   #define HTTPS_URL       "https://"      /* https URL prefix */
 #define FILE_URL        "file:"         /* file URL prefix */  #define FILE_URL        "file:"         /* file URL prefix */
 #define FTP_PROXY       "ftp_proxy"     /* env var with ftp proxy location */  #define FTP_PROXY       "ftp_proxy"     /* env var with ftp proxy location */
 #define HTTP_PROXY      "http_proxy"    /* env var with http proxy location */  #define HTTP_PROXY      "http_proxy"    /* env var with http proxy location */
Line 111 
Line 128 
         volatile sig_t oldintr;          volatile sig_t oldintr;
         FILE *fin = NULL;          FILE *fin = NULL;
         off_t hashbytes;          off_t hashbytes;
         size_t len;  
         const char *errstr;          const char *errstr;
           size_t len, wlen;
   #ifndef SMALL
           char *sslpath = NULL, *sslhost = NULL;
           int ishttpsurl = 0;
           SSL_CTX *ssl_ctx = NULL;
   #endif
           SSL *ssl = NULL;
   
         line = strdup(origline);          line = strdup(origline);
         if (line == NULL)          if (line == NULL)
Line 125 
Line 148 
         } else if (strncasecmp(line, FILE_URL, sizeof(FILE_URL) - 1) == 0) {          } else if (strncasecmp(line, FILE_URL, sizeof(FILE_URL) - 1) == 0) {
                 host = line + sizeof(FILE_URL) - 1;                  host = line + sizeof(FILE_URL) - 1;
                 isfileurl = 1;                  isfileurl = 1;
   #ifndef SMALL
           } else if (strncasecmp(line, HTTPS_URL, sizeof(HTTPS_URL) - 1) == 0) {
                   host = line + sizeof(HTTPS_URL) - 1;
                   ishttpsurl = 1;
   #endif
         } else          } else
                 errx(1, "url_get: Invalid URL '%s'", line);                  errx(1, "url_get: Invalid URL '%s'", line);
   
Line 160 
Line 188 
         }          }
   
         if (!isfileurl && proxyenv != NULL) {           /* use proxy */          if (!isfileurl && proxyenv != NULL) {           /* use proxy */
   #ifndef SMALL
                   if (ishttpsurl) {
                           sslpath = strdup(path);
                           sslhost = strdup(host);
                           if (! sslpath || ! sslhost)
                                   errx(1, "Can't allocate memory for https path/host.");
                   }
   #endif
                 proxy = strdup(proxyenv);                  proxy = strdup(proxyenv);
                 if (proxy == NULL)                  if (proxy == NULL)
                         errx(1, "Can't allocate memory for proxy URL.");                          errx(1, "Can't allocate memory for proxy URL.");
Line 280 
Line 316 
         memset(&hints, 0, sizeof(hints));          memset(&hints, 0, sizeof(hints));
         hints.ai_family = family;          hints.ai_family = family;
         hints.ai_socktype = SOCK_STREAM;          hints.ai_socktype = SOCK_STREAM;
   #ifndef SMALL
           port = portnum ? portnum : (ishttpsurl ? httpsport : httpport);
   #else
         port = portnum ? portnum : httpport;          port = portnum ? portnum : httpport;
   #endif
         error = getaddrinfo(host, port, &hints, &res0);          error = getaddrinfo(host, port, &hints, &res0);
           /*
            * If the services file is corrupt/missing, fall back
            * on our hard-coded defines.
            */
         if (error == EAI_SERVICE && port == httpport) {          if (error == EAI_SERVICE && port == httpport) {
                 /*  
                  * If the services file is corrupt/missing, fall back  
                  * on our hard-coded defines.  
                  */  
                 snprintf(pbuf, sizeof(pbuf), "%d", HTTP_PORT);                  snprintf(pbuf, sizeof(pbuf), "%d", HTTP_PORT);
                 error = getaddrinfo(host, pbuf, &hints, &res0);                  error = getaddrinfo(host, pbuf, &hints, &res0);
   #ifndef SMALL
           } else if (error == EAI_SERVICE && port == httpsport) {
                   snprintf(pbuf, sizeof(pbuf), "%d", HTTPS_PORT);
                   error = getaddrinfo(host, pbuf, &hints, &res0);
   #endif
         }          }
         if (error) {          if (error) {
                 warnx("%s: %s", gai_strerror(error), host);                  warnx("%s: %s", gai_strerror(error), host);
Line 330 
Line 375 
                 else                  else
                         port = NULL;                          port = NULL;
   
   #ifndef SMALL
                   if (proxyenv && sslhost)
                           proxy_connect(s, sslhost);
   #endif
                 break;                  break;
         }          }
         freeaddrinfo(res0);          freeaddrinfo(res0);
Line 338 
Line 387 
                 goto cleanup_url_get;                  goto cleanup_url_get;
         }          }
   
   #ifndef SMALL
           if (ishttpsurl) {
                   if (proxyenv && sslpath) {
                           ishttpsurl = 0;
                           proxy = NULL;
                           path = sslpath;
                   }
                   SSL_library_init();
                   SSL_load_error_strings();
                   SSLeay_add_ssl_algorithms();
                   ssl_ctx = SSL_CTX_new(SSLv23_client_method());
                   ssl = SSL_new(ssl_ctx);
                   if (ssl == NULL || ssl_ctx == NULL) {
                           ERR_print_errors_fp(ttyout);
                           goto cleanup_url_get;
                   }
                   if (SSL_set_fd(ssl, s) == 0) {
                           ERR_print_errors_fp(ttyout);
                           goto cleanup_url_get;
                   }
                   if (SSL_connect(ssl) <= 0) {
                           ERR_print_errors_fp(ttyout);
                           goto cleanup_url_get;;
                   }
           } else {
                   fin = fdopen(s, "r+");
           }
   #else
         fin = fdopen(s, "r+");          fin = fdopen(s, "r+");
   #endif
   
         if (verbose)          if (verbose)
                 fprintf(ttyout, "Requesting %s", origline);                  fprintf(ttyout, "Requesting %s", origline);
Line 352 
Line 430 
                  * Host: directive must use the destination host address for                   * Host: directive must use the destination host address for
                  * the original URI (path).  We do not attach it at this moment.                   * the original URI (path).  We do not attach it at this moment.
                  */                   */
                 fprintf(fin, "GET %s HTTP/1.0\r\n%s\r\n\r\n", path,                  ftp_printf(fin, ssl, "GET %s HTTP/1.0\r\n%s\r\n\r\n", path,
                     HTTP_USER_AGENT);                      HTTP_USER_AGENT);
         } else {          } else {
                 fprintf(fin, "GET /%s HTTP/1.0\r\nHost: ", path);                  ftp_printf(fin, ssl, "GET /%s HTTP/1.0\r\nHost: ", path);
                 if (strchr(host, ':')) {                  if (strchr(host, ':')) {
                         char *h, *p;                          char *h, *p;
   
Line 368 
Line 446 
                                 errx(1, "Can't allocate memory.");                                  errx(1, "Can't allocate memory.");
                         if ((p = strchr(h, '%')) != NULL)                          if ((p = strchr(h, '%')) != NULL)
                                 *p = '\0';                                  *p = '\0';
                         fprintf(fin, "[%s]", h);                          ftp_printf(fin, ssl, "[%s]", h);
                         free(h);                          free(h);
                 } else                  } else
                         fprintf(fin, "%s", host);                          ftp_printf(fin, ssl, "%s", host);
   
                 /*                  /*
                  * Send port number only if it's specified and does not equal                   * Send port number only if it's specified and does not equal
                  * 80. Some broken HTTP servers get confused if you explicitly                   * 80. Some broken HTTP servers get confused if you explicitly
                  * send them the port number.                   * send them the port number.
                  */                   */
   #ifndef SMALL
                   if (port && strcmp(port, (ishttpsurl ? "443" : "80")) != 0)
                           ftp_printf(fin, ssl, ":%s", port);
   #else
                 if (port && strcmp(port, "80") != 0)                  if (port && strcmp(port, "80") != 0)
                         fprintf(fin, ":%s", port);                          ftp_printf(fin, ssl, ":%s", port);
                 fprintf(fin, "\r\n%s\r\n\r\n", HTTP_USER_AGENT);  #endif
                   ftp_printf(fin, ssl, "\r\n%s\r\n\r\n", HTTP_USER_AGENT);
                 if (verbose)                  if (verbose)
                         fprintf(ttyout, "\n");                          fprintf(ttyout, "\n");
         }          }
         if (fflush(fin) == EOF) {          if (fin != NULL && fflush(fin) == EOF) {
                 warn("Writing HTTP request");                  warn("Writing HTTP request");
                 goto cleanup_url_get;                  goto cleanup_url_get;
         }          }
           if ((buf = ftp_readline(fin, ssl, &len)) == NULL) {
         if ((buf = fparseln(fin, &len, NULL, "\0\0\0", 0)) == NULL) {  
                 warn("Receiving HTTP reply");                  warn("Receiving HTTP reply");
                 goto cleanup_url_get;                  goto cleanup_url_get;
         }          }
Line 422 
Line 504 
         filesize = -1;          filesize = -1;
   
         while (1) {          while (1) {
                 if ((buf = fparseln(fin, &len, NULL, "\0\0\0", 0)) == NULL) {                  if ((buf = ftp_readline(fin, ssl, &len)) == NULL) {
                         warn("Receiving HTTP reply");                          warn("Receiving HTTP reply");
                         goto cleanup_url_get;                          goto cleanup_url_get;
                 }                  }
   
                 while (len > 0 && (buf[len-1] == '\r' || buf[len-1] == '\n'))                  while (len > 0 && (buf[len-1] == '\r' || buf[len-1] == '\n'))
                         buf[--len] = '\0';                          buf[--len] = '\0';
                 if (len == 0)                  if (len == 0)
Line 490 
Line 573 
         if ((buf = malloc(4096)) == NULL)          if ((buf = malloc(4096)) == NULL)
                 errx(1, "Can't allocate memory for transfer buffer");                  errx(1, "Can't allocate memory for transfer buffer");
         i = 0;          i = 0;
         while ((len = fread(buf, sizeof(char), 4096, fin)) > 0) {          len = 1;
           while (len > 0) {
                   len = ftp_read(fin, ssl, buf, 4096);
                 bytes += len;                  bytes += len;
                 for (cp = buf; len > 0; len -= i, cp += i) {                  for (cp = buf, wlen = len; wlen > 0; wlen -= i, cp += i) {
                         if ((i = write(out, cp, len)) == -1) {                          if ((i = write(out, cp, wlen)) == -1) {
                                 warn("Writing %s", savefile);                                  warn("Writing %s", savefile);
                                 goto cleanup_url_get;                                  goto cleanup_url_get;
                         }                          }
Line 541 
Line 626 
         warnx("Improper response from %s", host);          warnx("Improper response from %s", host);
   
 cleanup_url_get:  cleanup_url_get:
   #ifndef SMALL
           if (ssl) {
                   SSL_shutdown(ssl);
                   SSL_free(ssl);
           }
   #endif
         if (fin != NULL)          if (fin != NULL)
                 fclose(fin);                  fclose(fin);
         else if (s != -1)          else if (s != -1)
Line 641 
Line 732 
                  * Try HTTP URL-style arguments first.                   * Try HTTP URL-style arguments first.
                  */                   */
                 if (strncasecmp(line, HTTP_URL, sizeof(HTTP_URL) - 1) == 0 ||                  if (strncasecmp(line, HTTP_URL, sizeof(HTTP_URL) - 1) == 0 ||
   #ifndef SMALL
                       /* even if we compiled without SSL, url_get will check */
                       strncasecmp(line, HTTPS_URL, sizeof(HTTPS_URL) -1) == 0 ||
   #endif
                     strncasecmp(line, FILE_URL, sizeof(FILE_URL) - 1) == 0) {                      strncasecmp(line, FILE_URL, sizeof(FILE_URL) - 1) == 0) {
                         redirect_loop = 0;                          redirect_loop = 0;
                         if (url_get(line, httpproxy, outfile) == -1)                          if (url_get(line, httpproxy, outfile) == -1)
Line 881 
Line 976 
                         *ret = ' ';                          *ret = ' ';
                         continue;                          continue;
                 }                  }
                 /* Can't use strtol here because next char after %xx may be  
                  * a digit. */                  /* Cannot use strtol here because next char
                    * after %xx may be a digit.
                    */
                 if (c == '%' && isxdigit(str[i+1]) && isxdigit(str[i+2])) {                  if (c == '%' && isxdigit(str[i+1]) && isxdigit(str[i+2])) {
                         *ret = hextochar(&str[i+1]);                          *ret = hextochar(&str[i+1]);
                         i+=2;                          i+=2;
Line 923 
Line 1020 
   
         if (strncasecmp(p, FTP_URL, sizeof(FTP_URL) - 1) == 0 ||          if (strncasecmp(p, FTP_URL, sizeof(FTP_URL) - 1) == 0 ||
             strncasecmp(p, HTTP_URL, sizeof(HTTP_URL) - 1) == 0 ||              strncasecmp(p, HTTP_URL, sizeof(HTTP_URL) - 1) == 0 ||
   #ifndef SMALL
               strncasecmp(p, HTTPS_URL, sizeof(HTTPS_URL) - 1) == 0 ||
   #endif
             strncasecmp(p, FILE_URL, sizeof(FILE_URL) - 1) == 0 ||              strncasecmp(p, FILE_URL, sizeof(FILE_URL) - 1) == 0 ||
             strstr(p, ":/"))              strstr(p, ":/"))
                 return (1);                  return (1);
         return (0);          return (0);
 }  }
   
   char *
   ftp_readline(FILE *fp, SSL *ssl, size_t *lenp)
   {
           if (fp != NULL)
                   return fparseln(fp, lenp, NULL, "\0\0\0", 0);
   #ifndef SMALL
           else if (ssl != NULL)
                   return SSL_readline(ssl, lenp);
   #endif
           else
                   return NULL;
   }
   
   int
   ftp_read(FILE *fp, SSL *ssl, char *buf, size_t len)
   {
           int ret;
           if (fp != NULL)
                   ret = fread(buf, sizeof(char), len, fp);
   #ifndef SMALL
           else if (ssl != NULL)
                   ret = SSL_read(ssl, buf, (int)len);
   #endif
           else
                   ret = 0;
           return (ret);
   }
   
   int
   ftp_printf(FILE *fp, SSL *ssl, const char *fmt, ...)
   {
           int ret;
           va_list ap;
   
           va_start(ap, fmt);
   
           if (fp != NULL)
                   ret = vfprintf(fp, fmt, ap);
   #ifndef SMALL
           else if (ssl != NULL)
                   ret = SSL_vprintf((SSL*)ssl, fmt, ap);
   #endif
           else
                   ret = NULL;
   
           va_end(ap);
           return (ret);
   }
   
   #ifndef SMALL
   int
   SSL_vprintf(SSL *ssl, const char *fmt, va_list ap)
   {
           int ret;
           char *string;
   
           if ((ret = vasprintf(&string, fmt, ap)) == -1)
                   return ret;
           ret = SSL_write(ssl, (void *)string, (int)strlen(string));
           free(string);
           return ret;
   }
   
   char *
   SSL_readline(SSL *ssl, size_t *lenp)
   {
           int i;
           size_t len;
           char *buf, *q, c;
   
           len = 128;
           if ((buf = malloc(len)) == NULL)
                   errx(1, "Can't allocate memory for transfer buffer");
           for (i = 0; ; i++) {
                   if (i >= len - 1) {
                           if ((q = realloc(buf, 2 * len)) == NULL)
                                   errx(1, "Can't expand transfer buffer");
                           buf = q;
                           len *= 2;
                   }
                   if (SSL_read(ssl, &c, 1) <= 0)
                           break;
                   buf[i] = c;
                   if (c == '\n')
                           break;
           }
           *lenp = i;
           return (buf);
   }
   
   int
   proxy_connect(int socket, char *host)
   {
           char buf[1024];
           char *connstr, *hosttail, *port;
   
           if (*host == '[' && (hosttail = strrchr(host, ']')) != NULL &&
                   (hosttail[1] == '\0' || hosttail[1] == ':')) {
                   host++;
                   *hosttail++ = '\0';
           } else
                   hosttail = host;
   
           port = strrchr(hosttail, ':');               /* find portnum */
           if (port != NULL)
                   *port++ = '\0';
           if (!port)
                   port = "443";
   
           if (debug)
                   printf("CONNECT %s:%s HTTP/1.1\n\n", host, port);
           asprintf(&connstr, "CONNECT %s:%s HTTP/1.1\n\n", host, port);
           if (!connstr)
                   errx(1, "Could not allocate memory to assemble connect string!");
           if (write(socket, connstr, strlen(connstr)) != strlen(connstr))
                    errx(1, "Could not send connect string: %s", strerror(errno));
           read(socket, &buf, sizeof(buf)); /* only proxy header XXX: error handling? */
           return(200);
   }
   #endif

Legend:
Removed from v.1.60  
changed lines
  Added in v.1.61