version 1.153, 2016/12/24 13:52:42 |
version 1.154, 2016/12/28 17:48:04 |
|
|
#include <util.h> |
#include <util.h> |
#include <resolv.h> |
#include <resolv.h> |
|
|
#ifndef SMALL |
#ifndef NOSSL |
#include <tls.h> |
#include <tls.h> |
#else /* !SMALL */ |
#else /* !NOSSL */ |
struct tls; |
struct tls; |
#endif /* !SMALL */ |
#endif /* !NOSSL */ |
|
|
#include "ftp_var.h" |
#include "ftp_var.h" |
#include "cmds.h" |
#include "cmds.h" |
|
|
size_t ftp_read(FILE *, struct tls *, char *, size_t); |
size_t ftp_read(FILE *, struct tls *, char *, size_t); |
#ifndef SMALL |
#ifndef SMALL |
int proxy_connect(int, char *, char *); |
int proxy_connect(int, char *, char *); |
|
#endif /* !SMALL */ |
|
#ifndef NOSSL |
int SSL_vprintf(struct tls *, const char *, va_list); |
int SSL_vprintf(struct tls *, const char *, va_list); |
char *SSL_readline(struct tls *, size_t *); |
char *SSL_readline(struct tls *, size_t *); |
#endif /* !SMALL */ |
#endif /* !SMALL */ |
|
|
const char *errstr; |
const char *errstr; |
ssize_t len, wlen; |
ssize_t len, wlen; |
char *proxyhost = NULL; |
char *proxyhost = NULL; |
#ifndef SMALL |
#ifndef NOSSL |
char *sslpath = NULL, *sslhost = NULL; |
char *sslpath = NULL, *sslhost = NULL; |
char *locbase, *full_host = NULL; |
char *locbase, *full_host = NULL; |
const char *scheme; |
const char *scheme; |
int ishttpurl = 0, ishttpsurl = 0; |
int ishttpurl = 0, ishttpsurl = 0; |
struct addrinfo *ares = NULL; |
struct addrinfo *ares = NULL; |
#endif /* !SMALL */ |
#endif /* !NOSSL */ |
struct tls *tls = NULL; |
struct tls *tls = NULL; |
int status; |
int status; |
int save_errno; |
int save_errno; |
|
|
} else if (strncasecmp(newline, FILE_URL, sizeof(FILE_URL) - 1) == 0) { |
} else if (strncasecmp(newline, FILE_URL, sizeof(FILE_URL) - 1) == 0) { |
host = newline + sizeof(FILE_URL) - 1; |
host = newline + sizeof(FILE_URL) - 1; |
isfileurl = 1; |
isfileurl = 1; |
#ifndef SMALL |
#ifndef NOSSL |
scheme = FILE_URL; |
scheme = FILE_URL; |
} else if (strncasecmp(newline, HTTPS_URL, sizeof(HTTPS_URL) - 1) == 0) { |
} else if (strncasecmp(newline, HTTPS_URL, sizeof(HTTPS_URL) - 1) == 0) { |
host = newline + sizeof(HTTPS_URL) - 1; |
host = newline + sizeof(HTTPS_URL) - 1; |
ishttpsurl = 1; |
ishttpsurl = 1; |
scheme = HTTPS_URL; |
scheme = HTTPS_URL; |
#endif /* !SMALL */ |
#endif /* !NOSSL */ |
} else |
} else |
errx(1, "url_get: Invalid URL '%s'", newline); |
errx(1, "url_get: Invalid URL '%s'", newline); |
|
|
|
|
|
|
noslash: |
noslash: |
|
|
#ifndef SMALL |
#ifndef NOSSL |
/* |
/* |
* Look for auth header in host, since now host does not |
* Look for auth header in host, since now host does not |
* contain the path. Basic auth from RFC 2617, valid |
* contain the path. Basic auth from RFC 2617, valid |
|
|
host = p + 1; |
host = p + 1; |
} |
} |
} |
} |
#endif /* SMALL */ |
#endif /* NOSSL */ |
|
|
if (outfile) |
if (outfile) |
savefile = outfile; |
savefile = outfile; |
|
|
#endif /* !SMALL */ |
#endif /* !SMALL */ |
|
|
if (!isfileurl && proxyenv != NULL) { /* use proxy */ |
if (!isfileurl && proxyenv != NULL) { /* use proxy */ |
#ifndef SMALL |
#ifndef NOSSL |
if (ishttpsurl) { |
if (ishttpsurl) { |
sslpath = strdup(path); |
sslpath = strdup(path); |
sslhost = strdup(host); |
sslhost = strdup(host); |
if (! sslpath || ! sslhost) |
if (! sslpath || ! sslhost) |
errx(1, "Can't allocate memory for https path/host."); |
errx(1, "Can't allocate memory for https path/host."); |
} |
} |
#endif /* !SMALL */ |
#endif /* !NOSSL */ |
proxyhost = strdup(host); |
proxyhost = strdup(host); |
if (proxyhost == NULL) |
if (proxyhost == NULL) |
errx(1, "Can't allocate memory for proxy host."); |
errx(1, "Can't allocate memory for proxy host."); |
|
|
portnum = strrchr(hosttail, ':'); /* find portnum */ |
portnum = strrchr(hosttail, ':'); /* find portnum */ |
if (portnum != NULL) |
if (portnum != NULL) |
*portnum++ = '\0'; |
*portnum++ = '\0'; |
#ifndef SMALL |
#ifndef NOSSL |
port = portnum ? portnum : (ishttpsurl ? httpsport : httpport); |
port = portnum ? portnum : (ishttpsurl ? httpsport : httpport); |
#else /* !SMALL */ |
#else /* !NOSSL */ |
port = portnum ? portnum : httpport; |
port = portnum ? portnum : httpport; |
#endif /* !SMALL */ |
#endif /* !NOSSL */ |
|
|
#ifndef SMALL |
#ifndef SMALL |
if (full_host == NULL) |
if (full_host == NULL) |
|
|
if (error == EAI_SERVICE && port == httpport) { |
if (error == EAI_SERVICE && port == httpport) { |
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 |
#ifndef NOSSL |
} else if (error == EAI_SERVICE && port == httpsport) { |
} else if (error == EAI_SERVICE && port == httpsport) { |
snprintf(pbuf, sizeof(pbuf), "%d", HTTPS_PORT); |
snprintf(pbuf, sizeof(pbuf), "%d", HTTPS_PORT); |
error = getaddrinfo(host, pbuf, &hints, &res0); |
error = getaddrinfo(host, pbuf, &hints, &res0); |
#endif /* !SMALL */ |
#endif /* !NOSSL */ |
} |
} |
if (error) { |
if (error) { |
warnx("%s: %s", host, gai_strerror(error)); |
warnx("%s: %s", host, gai_strerror(error)); |
|
|
goto cleanup_url_get; |
goto cleanup_url_get; |
} |
} |
|
|
#ifndef SMALL |
#ifndef NOSSL |
if (ishttpsurl) { |
if (ishttpsurl) { |
if (proxyenv && sslpath) { |
if (proxyenv && sslpath) { |
ishttpsurl = 0; |
ishttpsurl = 0; |
|
|
} else { |
} else { |
fin = fdopen(s, "r+"); |
fin = fdopen(s, "r+"); |
} |
} |
#else /* !SMALL */ |
#else /* !NOSSL */ |
fin = fdopen(s, "r+"); |
fin = fdopen(s, "r+"); |
#endif /* !SMALL */ |
#endif /* !NOSSL */ |
|
|
/* |
/* |
* Construct and send the request. Proxy requests don't want leading /. |
* Construct and send the request. Proxy requests don't want leading /. |
*/ |
*/ |
#ifndef SMALL |
#ifndef NOSSL |
cookie_get(host, path, ishttpsurl, &buf); |
cookie_get(host, path, ishttpsurl, &buf); |
#endif /* !SMALL */ |
#endif /* !NOSSL */ |
|
|
epath = url_encode(path); |
epath = url_encode(path); |
if (proxyurl) { |
if (proxyurl) { |
|
|
else |
else |
restart_point = 0; |
restart_point = 0; |
} |
} |
|
#endif /* SMALL */ |
|
#ifndef NOSSL |
if (credentials) { |
if (credentials) { |
ftp_printf(fin, tls, |
ftp_printf(fin, tls, |
"GET /%s %s\r\nAuthorization: Basic %s\r\nHost: ", |
"GET /%s %s\r\nAuthorization: Basic %s\r\nHost: ", |
|
|
free(credentials); |
free(credentials); |
credentials = NULL; |
credentials = NULL; |
} else |
} else |
#endif /* SMALL */ |
#endif /* NOSSL */ |
ftp_printf(fin, tls, "GET /%s %s\r\nHost: ", epath, |
ftp_printf(fin, tls, "GET /%s %s\r\nHost: ", epath, |
#ifndef SMALL |
#ifndef SMALL |
restart_point ? "HTTP/1.1\r\nConnection: close" : |
restart_point ? "HTTP/1.1\r\nConnection: close" : |
|
|
* 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 |
#ifndef NOSSL |
if (port && strcmp(port, (ishttpsurl ? "443" : "80")) != 0) |
if (port && strcmp(port, (ishttpsurl ? "443" : "80")) != 0) |
ftp_printf(fin, tls, ":%s", port); |
ftp_printf(fin, tls, ":%s", port); |
if (restart_point) |
if (restart_point) |
ftp_printf(fin, tls, "\r\nRange: bytes=%lld-", |
ftp_printf(fin, tls, "\r\nRange: bytes=%lld-", |
(long long)restart_point); |
(long long)restart_point); |
#else /* !SMALL */ |
#else /* !NOSSL */ |
if (port && strcmp(port, "80") != 0) |
if (port && strcmp(port, "80") != 0) |
ftp_printf(fin, tls, ":%s", port); |
ftp_printf(fin, tls, ":%s", port); |
#endif /* !SMALL */ |
#endif /* !NOSSL */ |
ftp_printf(fin, tls, "\r\n%s%s\r\n\r\n", |
ftp_printf(fin, tls, "\r\n%s%s\r\n\r\n", |
buf ? buf : "", httpuseragent); |
buf ? buf : "", httpuseragent); |
} |
} |
free(epath); |
free(epath); |
|
|
#ifndef SMALL |
#ifndef NOSSL |
free(buf); |
free(buf); |
#endif /* !SMALL */ |
#endif /* !SMALL */ |
buf = NULL; |
buf = NULL; |
|
|
warnx("Improper response from %s", host); |
warnx("Improper response from %s", host); |
|
|
cleanup_url_get: |
cleanup_url_get: |
#ifndef SMALL |
#ifndef NOSSL |
if (tls != NULL) { |
if (tls != NULL) { |
tls_close(tls); |
tls_close(tls); |
tls_free(tls); |
tls_free(tls); |
} |
} |
free(full_host); |
free(full_host); |
free(sslhost); |
free(sslhost); |
#endif /* !SMALL */ |
#endif /* !NOSSL */ |
if (fin != NULL) |
if (fin != NULL) |
fclose(fin); |
fclose(fin); |
else if (s != -1) |
else if (s != -1) |
|
|
* Try HTTP URL-style arguments first. |
* Try HTTP URL-style arguments first. |
*/ |
*/ |
if (strncasecmp(url, HTTP_URL, sizeof(HTTP_URL) - 1) == 0 || |
if (strncasecmp(url, HTTP_URL, sizeof(HTTP_URL) - 1) == 0 || |
#ifndef SMALL |
#ifndef NOSSL |
/* even if we compiled without SSL, url_get will check */ |
/* even if we compiled without SSL, url_get will check */ |
strncasecmp(url, HTTPS_URL, sizeof(HTTPS_URL) -1) == 0 || |
strncasecmp(url, HTTPS_URL, sizeof(HTTPS_URL) -1) == 0 || |
#endif /* !SMALL */ |
#endif /* !NOSSL */ |
strncasecmp(url, FILE_URL, sizeof(FILE_URL) - 1) == 0) { |
strncasecmp(url, FILE_URL, sizeof(FILE_URL) - 1) == 0) { |
redirect_loop = 0; |
redirect_loop = 0; |
if (url_get(url, httpproxy, outfile) == -1) |
if (url_get(url, httpproxy, outfile) == -1) |
|
|
|
|
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 |
#ifndef NOSSL |
strncasecmp(p, HTTPS_URL, sizeof(HTTPS_URL) - 1) == 0 || |
strncasecmp(p, HTTPS_URL, sizeof(HTTPS_URL) - 1) == 0 || |
#endif /* !SMALL */ |
#endif /* !NOSSL */ |
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); |
|
|
{ |
{ |
if (fp != NULL) |
if (fp != NULL) |
return fparseln(fp, lenp, NULL, "\0\0\0", 0); |
return fparseln(fp, lenp, NULL, "\0\0\0", 0); |
#ifndef SMALL |
#ifndef NOSSL |
else if (tls != NULL) |
else if (tls != NULL) |
return SSL_readline(tls, lenp); |
return SSL_readline(tls, lenp); |
#endif /* !SMALL */ |
#endif /* !NOSSL */ |
else |
else |
return NULL; |
return NULL; |
} |
} |
|
|
size_t |
size_t |
ftp_read(FILE *fp, struct tls *tls, char *buf, size_t len) |
ftp_read(FILE *fp, struct tls *tls, char *buf, size_t len) |
{ |
{ |
#ifndef SMALL |
#ifndef NOSSL |
ssize_t tls_ret; |
ssize_t tls_ret; |
#endif |
#endif |
size_t ret = 0; |
size_t ret = 0; |
|
|
if (fp != NULL) |
if (fp != NULL) |
ret = fread(buf, sizeof(char), len, fp); |
ret = fread(buf, sizeof(char), len, fp); |
#ifndef SMALL |
#ifndef NOSSL |
else if (tls != NULL) { |
else if (tls != NULL) { |
again: |
again: |
if ((tls_ret = tls_read(tls, buf, len)) >= 0) |
if ((tls_ret = tls_read(tls, buf, len)) >= 0) |
|
|
if (ret < 0) |
if (ret < 0) |
errx(1, "SSL read error: %s", tls_error(tls)); |
errx(1, "SSL read error: %s", tls_error(tls)); |
} |
} |
#endif /* !SMALL */ |
#endif /* !NOSSL */ |
return (ret); |
return (ret); |
} |
} |
|
|
|
|
|
|
if (fp != NULL) |
if (fp != NULL) |
ret = vfprintf(fp, fmt, ap); |
ret = vfprintf(fp, fmt, ap); |
#ifndef SMALL |
#ifndef NOSSL |
else if (tls != NULL) |
else if (tls != NULL) |
ret = SSL_vprintf(tls, fmt, ap); |
ret = SSL_vprintf(tls, fmt, ap); |
#endif /* !SMALL */ |
#endif /* !NOSSL */ |
else |
else |
ret = 0; |
ret = 0; |
|
|
|
|
return (ret); |
return (ret); |
} |
} |
|
|
#ifndef SMALL |
#ifndef NOSSL |
int |
int |
SSL_vprintf(struct tls *tls, const char *fmt, va_list ap) |
SSL_vprintf(struct tls *tls, const char *fmt, va_list ap) |
{ |
{ |