X-Git-Url: https://pd.if.org/git/?p=zpackage;a=blobdiff_plain;f=zpm-fetchurl.c;h=1b337244421df9f0f74b7aa5a2d99186670ecd60;hp=4ffca2333b8cd16f994fcddef20fdd4e490073f5;hb=28c32424d04f982985b685ce891ed7db6237504e;hpb=4b448fbc77510c589cc7f367c05bef63acc07858 diff --git a/zpm-fetchurl.c b/zpm-fetchurl.c index 4ffca23..1b33724 100644 --- a/zpm-fetchurl.c +++ b/zpm-fetchurl.c @@ -15,6 +15,7 @@ #include #include "tlse.h" +#define MARK fprintf(stderr, "%s %s:%d\n", __FILE__, __func__, __LINE__) struct tls_uri { char *scheme; @@ -132,29 +133,38 @@ int verify_first(struct TLSContext *context, struct TLSCertificate **chain, int if (geteuid() == 0) { trustfile = "/var/lib/zpm/known_hosts"; } else { - homedir = getenv("HOME"); - if (!homedir) { + /* we could do this with a series of + * openat() calls instead of building + * up a string + */ + trustfile = getenv("HOME"); + if (!trustfile) { + fprintf(stderr, "home = %s\n", trustfile); return 1; } - len = snprintf(homedir, 0, "%s/.zpm/known_hosts", homedir); + len = snprintf(homedir, 0, "%s/.zpm/known_hosts", trustfile); homedir = malloc(len+1); if (!homedir) { return 1; } - len = snprintf(homedir, len+1, "%s/.zpm/known_hosts", homedir); + len = snprintf(homedir, len+1, "%s/.zpm/known_hosts", trustfile); trustfile = homedir; } } /* cert is valid on its face, so check against the trust db */ trustdb = open(trustfile, O_RDWR|O_CREAT, 0600); - if (homedir) { - free(homedir); - } if (trustdb == -1) { - fprintf(stderr, "cannot open trustdb: %s\n", strerror(errno)); + fprintf(stderr, "cannot open trustdb %s: %s\n", trustfile, strerror(errno)); + if (homedir) { + free(homedir); + } return 1; } + if (homedir) { + free(homedir); + } + len = 0; tls_buffer_init(&tbuf, 128); do { @@ -205,10 +215,17 @@ int verify_first(struct TLSContext *context, struct TLSCertificate **chain, int /* got here, so we should be at EOF, so add this host to trust db */ lseek(trustdb, 0, SEEK_END); - write(trustdb, certhash, 64); - write(trustdb, ":", 1); - write(trustdb, context->sni, strlen(context->sni)); - write(trustdb, "\n", 1); + + /* re-use the buffer so we only do one write */ + /* ignore errors, the cert is fine, we just can't update + * the trustdb if there's errors here + */ + tbuf.len = 0; + tls_buffer_append(&tbuf, certhash, 64); + tls_buffer_append_byte(&tbuf, ':'); + tls_buffer_append(&tbuf, context->sni, strlen(context->sni)); + tls_buffer_append_byte(&tbuf, '\n'); + write(trustdb, tbuf.buffer, tbuf.len); close(trustdb); tls_buffer_free(&tbuf); @@ -222,17 +239,13 @@ int verify_roots(struct TLSContext *context, struct TLSCertificate **chain, int if (chain) { for (i = 0; i < len; i++) { struct TLSCertificate *certificate = chain[i]; - // check validity date err = tls_certificate_is_valid(certificate); if (err) { return err; } - // check certificate in certificate->bytes of length - // certificate->len the certificate is in ASN.1 DER - // format } } - // check if chain is valid + err = tls_certificate_chain_is_valid(chain, len); if (err) { return err; @@ -280,11 +293,9 @@ int month(char *m) { /* Wed, 06 Feb 2019 10:06:05 GMT */ time_t parse_date(char *d) { - //static const char format[] = "%a, %d %b %Y %H:%M:%S %Z"; // rfc 1123 struct tm tm = { 0 }; int rv; - //char *data = "Tue, 13 Dec 2011 16:08:21 GMT"; int h, m, s, dom, Y; char M[4]; rv = sscanf(d, "%*[a-zA-Z,] %d %s %d %d:%d:%d", &dom, M, &Y, &h, &m, &s); @@ -425,6 +436,16 @@ void append_header(struct tls_buffer *buf, char *header, char *val) { tls_buffer_append(buf, "\r\n", 2); } +void append_timeheader(struct tls_buffer *buf, char *header, time_t ts) { + char timestr[80]; + struct tm *tm; + + tm = gmtime(&ts); + + strftime(timestr, sizeof timestr, "%a, %d %b %Y %H:%M:%S GMT", tm); + append_header(buf, header, timestr); +} + static void pdots(int len, int ch, unsigned long was, unsigned long now, unsigned long total) { was = len * was / total; @@ -437,6 +458,56 @@ static void pdots(int len, int ch, unsigned long was, unsigned long now, } } +static void fake_header(struct io *io, int fd) { + struct stat st; + int code = 200, rv; + char *message, codestr[5], length[32]; + struct tls_buffer *hdr = &io->response; + + if (fd == -1) { + switch (errno) { + case EACCES: code = 403; break; + case ENOENT: code = 404; break; + default: code = 500; break; + } + } else { + rv = fstat(fd, &st); + if (rv == -1) { + code = 500; + } + } + + if (io->last_modified >= st.st_mtime) { + code = 304; + } + + switch (code) { + case 200: message = "OK"; break; + case 304: message = "Not Modified"; break; + case 403: message = "Forbidden"; break; + case 404: message = "Not Found"; break; + case 500: message = "Internal Server Error"; break; + default: break; + } + sprintf(codestr, "%0.3d ", code); + tls_buffer_append(hdr, "HTTP/1.1 ", 9); + tls_buffer_append(hdr, codestr, 4); + tls_buffer_append_str(hdr, message); + tls_buffer_append(hdr, "\r\n", 2); + + append_timeheader(hdr, "Date", time(NULL)); + append_header(hdr, "Server", "zpm-fetchurl/0.9"); + if (code < 400) { + append_timeheader(hdr, "Last-Modified", st.st_mtime); + sprintf(length, "%zu", st.st_size); + append_header(hdr, "Content-Length", length); + } + + append_header(hdr, "Connection", "close"); + append_header(hdr, "Content-Type", "application/octet-stream"); + tls_buffer_append(hdr, "\r\n", 2); +} + int main(int ac, char *av[]) { int sockfd, port = -1, rv; ssize_t ret; @@ -492,6 +563,7 @@ int main(int ac, char *av[]) { exit(EXIT_FAILURE); } + io.last_modified = 0; if (lmfile) { struct stat st; int rv; @@ -504,6 +576,7 @@ int main(int ac, char *av[]) { exit(EXIT_FAILURE); } ts = st.st_mtime; + io.last_modified = ts; mtime = gmtime(&ts); strftime(lmtime, sizeof lmtime, "%a, %d %b %Y %H:%M:%S GMT", mtime); } @@ -543,8 +616,7 @@ int main(int ac, char *av[]) { tls_buffer_append(&request, "GET ", 4); } tls_buffer_append(&request, uri.path, strlen(uri.path)); - tls_buffer_append(&request, " HTTP/1.1", 9); - tls_buffer_append(&request, "\r\n", 2); + tls_buffer_append(&request, " HTTP/1.1\r\n", 11); append_header(&request, "Host", host); append_header(&request, "Connection", "close"); @@ -552,7 +624,6 @@ int main(int ac, char *av[]) { append_header(&request, "If-Modified-Since", lmtime); } tls_buffer_append(&request, "\r\n", 2); - //fprintf(stderr, "msg =\n%.*s", (int)request.len, request.buffer); if (!strcmp(uri.scheme, "https")) { use_tls = 1; @@ -589,41 +660,49 @@ int main(int ac, char *av[]) { tls_sni_set(clientssl, uri.host); clientssl->sync = 1; io.tls = clientssl; - } - - sockfd = open_tcp_connection(host, port); - io.socket = sockfd; - - if (sockfd < 0) { - exit(EXIT_FAILURE); - } - - if (use_tls) { + sockfd = open_tcp_connection(host, port); + if (sockfd < 0) { + perror("can't open connection"); + exit(EXIT_FAILURE); + } tls_set_fd(clientssl, sockfd); - if ((rv = tls_connect(clientssl)) != 1) { fprintf(stderr, "Handshake Error %i\n", rv); - return -5; + return 1; } - ret = tls_write(clientssl, request.buffer, request.len); + } else if (!strcmp(uri.scheme, "http")) { + sockfd = open_tcp_connection(host, port); + if (sockfd < 0) { + perror("can't open connection"); + exit(EXIT_FAILURE); + } + ret = write(sockfd, request.buffer, request.len); + } else if (!strcmp(uri.scheme, "file")) { + sockfd = open(uri.path, O_RDONLY); + fake_header(&io, sockfd); + ret = 0; } else { - ret = write(io.socket, request.buffer, request.len); + fprintf(stderr, "scheme %s unknown\n", uri.scheme); + exit(EXIT_FAILURE); } - if (ret < 0) { - fprintf(stderr, "write error %zd\n", ret); - return -6; + if (ret == -1) { + fprintf(stderr, "unable to write http request: %s\n", strerror(errno)); + exit(EXIT_FAILURE); } + io.socket = sockfd; + do { - ret = fill_buffer(&io); - if (ret < 0) { - break; + if (io.response.len >= 4) { + eoh = strstr(io.response.buffer, "\r\n\r\n"); } - eoh = strstr(io.response.buffer, "\r\n\r\n"); - if (ret == 0) { - break; + if (!eoh) { + ret = fill_buffer(&io); + if (ret <= 0) { + break; + } } } while (!eoh); @@ -652,10 +731,6 @@ int main(int ac, char *av[]) { break; } - if (io.status_code != 200) { - break; - } - if (!raw) { tls_buffer_shift(&io.response, header_len); } @@ -687,6 +762,9 @@ int main(int ac, char *av[]) { } total += ret; } + if (head) { + break; + } ret = fill_buffer(&io); } while (ret > 0);