version 1.175, 2019/10/23 16:47:53 |
version 1.176, 2019/11/03 19:26:15 |
|
|
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 tls *, const char *, ...) __attribute__((format(printf, 3, 4))); |
char *ftp_readline(FILE *, size_t *); |
char *ftp_readline(FILE *, struct tls *, size_t *); |
|
size_t ftp_read(FILE *, struct tls *, char *, size_t); |
|
void ftp_close(FILE **fin, struct tls **tls, volatile int *fd); |
void ftp_close(FILE **fin, struct tls **tls, volatile int *fd); |
|
const char *sockerror(struct tls *); |
#ifndef NOSSL |
#ifndef NOSSL |
int proxy_connect(int, char *, char *); |
int proxy_connect(int, char *, char *); |
int SSL_vprintf(struct tls *, const char *, va_list); |
int stdio_tls_write_wrapper(void *, const char *, int); |
char *SSL_readline(struct tls *, size_t *); |
int stdio_tls_read_wrapper(void *, char *, int); |
#endif /* !NOSSL */ |
#endif /* !NOSSL */ |
|
|
#define FTP_URL "ftp://" /* ftp URL prefix */ |
#define FTP_URL "ftp://" /* ftp URL prefix */ |
|
|
fprintf(ttyout, "SSL failure: %s\n", tls_error(tls)); |
fprintf(ttyout, "SSL failure: %s\n", tls_error(tls)); |
goto cleanup_url_get; |
goto cleanup_url_get; |
} |
} |
|
if (tls_handshake(tls) != 0) { |
|
fprintf(ttyout, "SSL failure: %s\n", tls_error(tls)); |
|
goto cleanup_url_get; |
|
} |
|
fin = funopen(tls, stdio_tls_read_wrapper, |
|
stdio_tls_write_wrapper, NULL, NULL); |
} else { |
} else { |
fin = fdopen(fd, "r+"); |
fin = fdopen(fd, "r+"); |
fd = -1; |
fd = -1; |
|
|
* the original URI (path). |
* the original URI (path). |
*/ |
*/ |
if (credentials) |
if (credentials) |
ftp_printf(fin, tls, "GET %s HTTP/1.0\r\n" |
fprintf(fin, "GET %s HTTP/1.0\r\n" |
"Proxy-Authorization: Basic %s\r\n" |
"Proxy-Authorization: Basic %s\r\n" |
"Host: %s\r\n%s%s\r\n\r\n", |
"Host: %s\r\n%s%s\r\n\r\n", |
epath, credentials, |
epath, credentials, |
proxyhost, buf ? buf : "", httpuseragent); |
proxyhost, buf ? buf : "", httpuseragent); |
else |
else |
ftp_printf(fin, tls, "GET %s HTTP/1.0\r\n" |
fprintf(fin, "GET %s HTTP/1.0\r\n" |
"Host: %s\r\n%s%s\r\n\r\n", |
"Host: %s\r\n%s%s\r\n\r\n", |
epath, proxyhost, buf ? buf : "", httpuseragent); |
epath, proxyhost, buf ? buf : "", httpuseragent); |
} else { |
} else { |
|
|
#endif /* SMALL */ |
#endif /* SMALL */ |
#ifndef NOSSL |
#ifndef NOSSL |
if (credentials) { |
if (credentials) { |
ftp_printf(fin, tls, |
fprintf(fin, |
"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 /* NOSSL */ |
#endif /* NOSSL */ |
ftp_printf(fin, tls, "GET /%s %s\r\nHost: ", epath, |
fprintf(fin, "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 */ |
"HTTP/1.0"); |
"HTTP/1.0"); |
if (proxyhost) { |
if (proxyhost) { |
ftp_printf(fin, tls, "%s", proxyhost); |
fprintf(fin, "%s", proxyhost); |
port = NULL; |
port = NULL; |
} else if (strchr(host, ':')) { |
} else if (strchr(host, ':')) { |
/* |
/* |
|
|
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, tls, "[%s]", h); |
fprintf(fin, "[%s]", h); |
free(h); |
free(h); |
} else |
} else |
ftp_printf(fin, tls, "%s", host); |
fprintf(fin, "%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 NOSSL |
#ifndef NOSSL |
if (port && strcmp(port, (ishttpsurl ? "443" : "80")) != 0) |
if (port && strcmp(port, (ishttpsurl ? "443" : "80")) != 0) |
ftp_printf(fin, tls, ":%s", port); |
fprintf(fin, ":%s", port); |
if (restart_point) |
if (restart_point) |
ftp_printf(fin, tls, "\r\nRange: bytes=%lld-", |
fprintf(fin, "\r\nRange: bytes=%lld-", |
(long long)restart_point); |
(long long)restart_point); |
#else /* !NOSSL */ |
#else /* !NOSSL */ |
if (port && strcmp(port, "80") != 0) |
if (port && strcmp(port, "80") != 0) |
ftp_printf(fin, tls, ":%s", port); |
fprintf(fin, ":%s", port); |
#endif /* !NOSSL */ |
#endif /* !NOSSL */ |
ftp_printf(fin, tls, "\r\n%s%s\r\n\r\n", |
fprintf(fin, "\r\n%s%s\r\n\r\n", |
buf ? buf : "", httpuseragent); |
buf ? buf : "", httpuseragent); |
} |
} |
free(epath); |
free(epath); |
|
|
#endif /* !NOSSL */ |
#endif /* !NOSSL */ |
buf = NULL; |
buf = NULL; |
|
|
if (fin != NULL && fflush(fin) == EOF) { |
if (fflush(fin) == EOF) { |
warn("Writing HTTP request"); |
warnx("Writing HTTP request: %s", sockerror(tls)); |
goto cleanup_url_get; |
goto cleanup_url_get; |
} |
} |
if ((buf = ftp_readline(fin, tls, &len)) == NULL) { |
if ((buf = ftp_readline(fin, &len)) == NULL) { |
warn("Receiving HTTP reply"); |
warnx("Receiving HTTP reply: %s", sockerror(tls)); |
goto cleanup_url_get; |
goto cleanup_url_get; |
} |
} |
|
|
|
|
filesize = -1; |
filesize = -1; |
|
|
for (;;) { |
for (;;) { |
if ((buf = ftp_readline(fin, tls, &len)) == NULL) { |
if ((buf = ftp_readline(fin, &len)) == NULL) { |
warn("Receiving HTTP reply"); |
warnx("Receiving HTTP reply: %s", sockerror(tls)); |
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, tls, buf, buflen); |
len = fread(buf, 1, buflen, fin); |
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) { |
|
|
(void)fflush(ttyout); |
(void)fflush(ttyout); |
} |
} |
if (len != 0) { |
if (len != 0) { |
warn("Reading from socket"); |
warnx("Reading from socket: %s", sockerror(tls)); |
goto cleanup_url_get; |
goto cleanup_url_get; |
} |
} |
progressmeter(1, NULL); |
progressmeter(1, NULL); |
|
|
} |
} |
|
|
char * |
char * |
ftp_readline(FILE *fp, struct tls *tls, size_t *lenp) |
ftp_readline(FILE *fp, size_t *lenp) |
{ |
{ |
if (fp != NULL) |
return fparseln(fp, lenp, NULL, "\0\0\0", 0); |
return fparseln(fp, lenp, NULL, "\0\0\0", 0); |
|
#ifndef NOSSL |
|
else if (tls != NULL) |
|
return SSL_readline(tls, lenp); |
|
#endif /* !NOSSL */ |
|
else |
|
return NULL; |
|
} |
} |
|
|
size_t |
|
ftp_read(FILE *fp, struct tls *tls, char *buf, size_t len) |
|
{ |
|
#ifndef NOSSL |
|
ssize_t tret; |
|
#endif |
|
size_t ret = 0; |
|
|
|
if (fp != NULL) |
|
ret = fread(buf, sizeof(char), len, fp); |
|
#ifndef NOSSL |
|
else if (tls != NULL) { |
|
do { |
|
tret = tls_read(tls, buf, len); |
|
} while (tret == TLS_WANT_POLLIN || tret == TLS_WANT_POLLOUT); |
|
if (tret == -1) |
|
errx(1, "SSL read error: %s", tls_error(tls)); |
|
ret = (size_t)tret; |
|
} |
|
#endif /* !NOSSL */ |
|
return (ret); |
|
} |
|
|
|
int |
|
ftp_printf(FILE *fp, struct tls *tls, const char *fmt, ...) |
|
{ |
|
int ret; |
|
va_list ap; |
|
|
|
va_start(ap, fmt); |
|
|
|
if (fp != NULL) |
|
ret = vfprintf(fp, fmt, ap); |
|
#ifndef NOSSL |
|
else if (tls != NULL) |
|
ret = SSL_vprintf(tls, fmt, ap); |
|
#endif /* !NOSSL */ |
|
else |
|
ret = 0; |
|
|
|
va_end(ap); |
|
#ifndef SMALL |
|
if (debug) { |
|
va_start(ap, fmt); |
|
ret = vfprintf(ttyout, fmt, ap); |
|
va_end(ap); |
|
} |
|
#endif /* !SMALL */ |
|
return (ret); |
|
} |
|
|
|
void |
void |
ftp_close(FILE **fin, struct tls **tls, volatile int *fd) |
ftp_close(FILE **fin, struct tls **tls, volatile int *fd) |
{ |
{ |
|
|
tls_free(*tls); |
tls_free(*tls); |
*tls = NULL; |
*tls = NULL; |
} |
} |
|
if (*fd != -1) { |
|
close(*fd); |
|
*fd = -1; |
|
} |
#endif |
#endif |
if (*fin != NULL) { |
if (*fin != NULL) { |
fclose(*fin); |
fclose(*fin); |
*fin = NULL; |
*fin = NULL; |
} |
} |
if (*fd != -1) { |
|
close(*fd); |
|
*fd = -1; |
|
} |
|
} |
} |
|
|
#ifndef NOSSL |
const char * |
int |
sockerror(struct tls *tls) |
SSL_vprintf(struct tls *tls, const char *fmt, va_list ap) |
|
{ |
{ |
char *string, *buf; |
int save_errno = errno; |
size_t len; |
#ifndef NOSSL |
int ret; |
if (tls != NULL) { |
|
const char *tlserr = tls_error(tls); |
if ((ret = vasprintf(&string, fmt, ap)) == -1) |
if (tlserr != NULL) |
return ret; |
return tlserr; |
buf = string; |
|
len = ret; |
|
while (len > 0) { |
|
ret = tls_write(tls, buf, len); |
|
if (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT) |
|
continue; |
|
if (ret == -1) |
|
errx(1, "SSL write error: %s", tls_error(tls)); |
|
buf += ret; |
|
len -= ret; |
|
} |
} |
free(string); |
#endif |
return ret; |
return strerror(save_errno); |
} |
} |
|
|
char * |
#ifndef NOSSL |
SSL_readline(struct tls *tls, size_t *lenp) |
|
{ |
|
size_t i, len; |
|
char *buf, *q, c; |
|
int ret; |
|
|
|
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 = reallocarray(buf, len, 2)) == NULL) |
|
errx(1, "Can't expand transfer buffer"); |
|
buf = q; |
|
len *= 2; |
|
} |
|
do { |
|
ret = tls_read(tls, &c, 1); |
|
} while (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT); |
|
if (ret == -1) |
|
errx(1, "SSL read error: %s", tls_error(tls)); |
|
|
|
buf[i] = c; |
|
if (c == '\n') { |
|
buf[i] = '\0'; |
|
break; |
|
} |
|
} |
|
*lenp = i; |
|
return (buf); |
|
} |
|
|
|
int |
int |
proxy_connect(int socket, char *host, char *cookie) |
proxy_connect(int socket, char *host, char *cookie) |
{ |
{ |
|
|
read(socket, &buf, sizeof(buf)); /* only proxy header XXX: error handling? */ |
read(socket, &buf, sizeof(buf)); /* only proxy header XXX: error handling? */ |
free(connstr); |
free(connstr); |
return(200); |
return(200); |
|
} |
|
|
|
int |
|
stdio_tls_write_wrapper(void *arg, const char *buf, int len) |
|
{ |
|
struct tls *tls = arg; |
|
ssize_t ret; |
|
|
|
do { |
|
ret = tls_write(tls, buf, len); |
|
} while (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT); |
|
|
|
return ret; |
|
} |
|
|
|
int |
|
stdio_tls_read_wrapper(void *arg, char *buf, int len) |
|
{ |
|
struct tls *tls = arg; |
|
ssize_t ret; |
|
|
|
do { |
|
ret = tls_read(tls, buf, len); |
|
} while (ret == TLS_WANT_POLLIN || ret == TLS_WANT_POLLOUT); |
|
|
|
return ret; |
} |
} |
#endif /* !NOSSL */ |
#endif /* !NOSSL */ |