version 1.133, 2014/10/30 15:50:50 |
version 1.134, 2014/10/31 13:48:21 |
|
|
#include <resolv.h> |
#include <resolv.h> |
|
|
#ifndef SMALL |
#ifndef SMALL |
#include <ressl.h> |
#include <tls.h> |
#else /* !SMALL */ |
#else /* !SMALL */ |
struct ressl; |
struct tls; |
#endif /* !SMALL */ |
#endif /* !SMALL */ |
|
|
#include "ftp_var.h" |
#include "ftp_var.h" |
|
|
char hextochar(const char *); |
char hextochar(const char *); |
char *urldecode(const char *); |
char *urldecode(const char *); |
char *recode_credentials(const char *_userinfo); |
char *recode_credentials(const char *_userinfo); |
int ftp_printf(FILE *, struct ressl *, const char *, ...) __attribute__((format(printf, 3, 4))); |
int ftp_printf(FILE *, struct tls *, const char *, ...) __attribute__((format(printf, 3, 4))); |
char *ftp_readline(FILE *, struct ressl *, size_t *); |
char *ftp_readline(FILE *, struct tls *, size_t *); |
size_t ftp_read(FILE *, struct ressl *, 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 *); |
int SSL_vprintf(struct ressl *, const char *, va_list); |
int SSL_vprintf(struct tls *, const char *, va_list); |
char *SSL_readline(struct ressl *, size_t *); |
char *SSL_readline(struct tls *, size_t *); |
#endif /* !SMALL */ |
#endif /* !SMALL */ |
|
|
#define FTP_URL "ftp://" /* ftp URL prefix */ |
#define FTP_URL "ftp://" /* ftp URL prefix */ |
|
|
const char *scheme; |
const char *scheme; |
int ishttpurl = 0, ishttpsurl = 0; |
int ishttpurl = 0, ishttpsurl = 0; |
#endif /* !SMALL */ |
#endif /* !SMALL */ |
struct ressl *ssl = NULL; |
struct tls *tls = NULL; |
int status; |
int status; |
int save_errno; |
int save_errno; |
const size_t buflen = 128 * 1024; |
const size_t buflen = 128 * 1024; |
|
|
if (sslhost == NULL) |
if (sslhost == NULL) |
errx(1, "Can't allocate memory for https host."); |
errx(1, "Can't allocate memory for https host."); |
} |
} |
if (ressl_init() != 0) { |
if (tls_init() != 0) { |
fprintf(ttyout, "SSL initialisation failed\n"); |
fprintf(ttyout, "SSL initialisation failed\n"); |
goto cleanup_url_get; |
goto cleanup_url_get; |
} |
} |
if ((ssl = ressl_client()) == NULL) { |
if ((tls = tls_client()) == NULL) { |
fprintf(ttyout, "failed to create SSL client\n"); |
fprintf(ttyout, "failed to create SSL client\n"); |
goto cleanup_url_get; |
goto cleanup_url_get; |
} |
} |
if (ressl_configure(ssl, ressl_config) != 0) { |
if (tls_configure(tls, tls_config) != 0) { |
fprintf(ttyout, "SSL configuration failure: %s\n", |
fprintf(ttyout, "SSL configuration failure: %s\n", |
ressl_error(ssl)); |
tls_error(tls)); |
goto cleanup_url_get; |
goto cleanup_url_get; |
} |
} |
if (ressl_connect_socket(ssl, s, sslhost) != 0) { |
if (tls_connect_socket(tls, s, sslhost) != 0) { |
fprintf(ttyout, "SSL failure: %s\n", ressl_error(ssl)); |
fprintf(ttyout, "SSL failure: %s\n", tls_error(tls)); |
goto cleanup_url_get; |
goto cleanup_url_get; |
} |
} |
} else { |
} else { |
|
|
* the original URI (path). We do not attach it at this moment. |
* the original URI (path). We do not attach it at this moment. |
*/ |
*/ |
if (credentials) |
if (credentials) |
ftp_printf(fin, ssl, "GET %s HTTP/1.0\r\n" |
ftp_printf(fin, tls, "GET %s HTTP/1.0\r\n" |
"Proxy-Authorization: Basic %s%s\r\n%s\r\n\r\n", |
"Proxy-Authorization: Basic %s%s\r\n%s\r\n\r\n", |
epath, credentials, buf ? buf : "", |
epath, credentials, buf ? buf : "", |
httpuseragent); |
httpuseragent); |
else |
else |
ftp_printf(fin, ssl, "GET %s HTTP/1.0\r\n%s%s\r\n\r\n", |
ftp_printf(fin, tls, "GET %s HTTP/1.0\r\n%s%s\r\n\r\n", |
epath, buf ? buf : "", httpuseragent); |
epath, buf ? buf : "", httpuseragent); |
|
|
} else { |
} else { |
|
|
restart_point = 0; |
restart_point = 0; |
} |
} |
if (credentials) { |
if (credentials) { |
ftp_printf(fin, ssl, |
ftp_printf(fin, tls, |
"GET /%s %s\r\nAuthorization: Basic %s\r\nHost: ", |
"GET /%s %s\r\nAuthorization: Basic %s\r\nHost: ", |
epath, restart_point ? |
epath, restart_point ? |
"HTTP/1.1\r\nConnection: close" : "HTTP/1.0", |
"HTTP/1.1\r\nConnection: close" : "HTTP/1.0", |
|
|
credentials = NULL; |
credentials = NULL; |
} else |
} else |
#endif /* SMALL */ |
#endif /* SMALL */ |
ftp_printf(fin, ssl, "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" : |
#endif /* !SMALL */ |
#endif /* !SMALL */ |
|
|
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'; |
ftp_printf(fin, ssl, "[%s]", h); |
ftp_printf(fin, tls, "[%s]", h); |
free(h); |
free(h); |
} else |
} else |
ftp_printf(fin, ssl, "%s", host); |
ftp_printf(fin, tls, "%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 |
|
|
*/ |
*/ |
#ifndef SMALL |
#ifndef SMALL |
if (port && strcmp(port, (ishttpsurl ? "443" : "80")) != 0) |
if (port && strcmp(port, (ishttpsurl ? "443" : "80")) != 0) |
ftp_printf(fin, ssl, ":%s", port); |
ftp_printf(fin, tls, ":%s", port); |
if (restart_point) |
if (restart_point) |
ftp_printf(fin, ssl, "\r\nRange: bytes=%lld-", |
ftp_printf(fin, tls, "\r\nRange: bytes=%lld-", |
(long long)restart_point); |
(long long)restart_point); |
#else /* !SMALL */ |
#else /* !SMALL */ |
if (port && strcmp(port, "80") != 0) |
if (port && strcmp(port, "80") != 0) |
ftp_printf(fin, ssl, ":%s", port); |
ftp_printf(fin, tls, ":%s", port); |
#endif /* !SMALL */ |
#endif /* !SMALL */ |
ftp_printf(fin, ssl, "\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); |
if (verbose) |
if (verbose) |
fprintf(ttyout, "\n"); |
fprintf(ttyout, "\n"); |
|
|
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 = ftp_readline(fin, tls, &len)) == NULL) { |
warn("Receiving HTTP reply"); |
warn("Receiving HTTP reply"); |
goto cleanup_url_get; |
goto cleanup_url_get; |
} |
} |
|
|
filesize = -1; |
filesize = -1; |
|
|
for (;;) { |
for (;;) { |
if ((buf = ftp_readline(fin, ssl, &len)) == NULL) { |
if ((buf = ftp_readline(fin, tls, &len)) == NULL) { |
warn("Receiving HTTP reply"); |
warn("Receiving HTTP reply"); |
goto cleanup_url_get; |
goto cleanup_url_get; |
} |
} |
|
|
len = 1; |
len = 1; |
oldinti = signal(SIGINFO, psummary); |
oldinti = signal(SIGINFO, psummary); |
while (len > 0) { |
while (len > 0) { |
len = ftp_read(fin, ssl, buf, buflen); |
len = ftp_read(fin, tls, buf, buflen); |
bytes += len; |
bytes += len; |
for (cp = buf, wlen = len; wlen > 0; wlen -= i, cp += i) { |
for (cp = buf, wlen = len; wlen > 0; wlen -= i, cp += i) { |
if ((i = write(out, cp, wlen)) == -1) { |
if ((i = write(out, cp, wlen)) == -1) { |
|
|
|
|
cleanup_url_get: |
cleanup_url_get: |
#ifndef SMALL |
#ifndef SMALL |
if (ssl != NULL) { |
if (tls != NULL) { |
ressl_close(ssl); |
tls_close(tls); |
ressl_free(ssl); |
tls_free(tls); |
} |
} |
free(full_host); |
free(full_host); |
free(sslhost); |
free(sslhost); |
|
|
} |
} |
|
|
char * |
char * |
ftp_readline(FILE *fp, struct ressl *ssl, size_t *lenp) |
ftp_readline(FILE *fp, struct tls *tls, size_t *lenp) |
{ |
{ |
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 SMALL |
else if (ssl != NULL) |
else if (tls != NULL) |
return SSL_readline(ssl, lenp); |
return SSL_readline(tls, lenp); |
#endif /* !SMALL */ |
#endif /* !SMALL */ |
else |
else |
return NULL; |
return NULL; |
} |
} |
|
|
size_t |
size_t |
ftp_read(FILE *fp, struct ressl *ssl, char *buf, size_t len) |
ftp_read(FILE *fp, struct tls *tls, char *buf, size_t len) |
{ |
{ |
size_t ret; |
size_t ret; |
if (fp != NULL) |
if (fp != NULL) |
ret = fread(buf, sizeof(char), len, fp); |
ret = fread(buf, sizeof(char), len, fp); |
#ifndef SMALL |
#ifndef SMALL |
else if (ssl != NULL) { |
else if (tls!= NULL) { |
size_t nr; |
size_t nr; |
|
|
if ((ret = ressl_read(ssl, buf, len, &nr)) != 0) |
if ((ret = tls_read(tls, buf, len, &nr)) != 0) |
ret = 0; |
ret = 0; |
else |
else |
ret = nr; |
ret = nr; |
|
|
} |
} |
|
|
int |
int |
ftp_printf(FILE *fp, struct ressl *ssl, const char *fmt, ...) |
ftp_printf(FILE *fp, struct tls *tls, const char *fmt, ...) |
{ |
{ |
int ret; |
int ret; |
va_list ap; |
va_list ap; |
|
|
if (fp != NULL) |
if (fp != NULL) |
ret = vfprintf(fp, fmt, ap); |
ret = vfprintf(fp, fmt, ap); |
#ifndef SMALL |
#ifndef SMALL |
else if (ssl != NULL) |
else if (tls != NULL) |
ret = SSL_vprintf(ssl, fmt, ap); |
ret = SSL_vprintf(tls, fmt, ap); |
#endif /* !SMALL */ |
#endif /* !SMALL */ |
else |
else |
ret = 0; |
ret = 0; |
|
|
|
|
#ifndef SMALL |
#ifndef SMALL |
int |
int |
SSL_vprintf(struct ressl *ssl, const char *fmt, va_list ap) |
SSL_vprintf(struct tls *tls, const char *fmt, va_list ap) |
{ |
{ |
char *string; |
char *string; |
size_t nw; |
size_t nw; |
|
|
|
|
if ((ret = vasprintf(&string, fmt, ap)) == -1) |
if ((ret = vasprintf(&string, fmt, ap)) == -1) |
return ret; |
return ret; |
ret = ressl_write(ssl, string, ret, &nw); |
ret = tls_write(tls, string, ret, &nw); |
free(string); |
free(string); |
return ret; |
return ret; |
} |
} |
|
|
char * |
char * |
SSL_readline(struct ressl *ssl, size_t *lenp) |
SSL_readline(struct tls *tls, size_t *lenp) |
{ |
{ |
size_t i, len, nr; |
size_t i, len, nr; |
char *buf, *q, c; |
char *buf, *q, c; |
|
|
len *= 2; |
len *= 2; |
} |
} |
again: |
again: |
ret = ressl_read(ssl, &c, 1, &nr); |
ret = tls_read(tls, &c, 1, &nr); |
if (ret == RESSL_READ_AGAIN) |
if (ret == TLS_READ_AGAIN) |
goto again; |
goto again; |
if (ret != 0) |
if (ret != 0) |
errx(1, "SSL read error: %u", ret); |
errx(1, "SSL read error: %u", ret); |