1 #define _POSIX_C_SOURCE 200809L
5 #include <sys/socket.h>
6 #include <netinet/in.h>
19 #define DEBUG(lvl, ...) if (debuglevel >= lvl ) { fprintf(stderr, __VA_ARGS__); }
33 int tls_parse_uri(char *, struct tls_uri *);
34 void tls_free_uri(struct tls_uri *);
36 int open_tcp_connection(char *host, int port);
38 /* if trustpolicy is 0, we just accept anything */
39 int verify_trust(struct TLSContext *context, struct TLSCertificate **chain, int
42 if (context || chain || len) {
49 static char hexchars[] = "0123456789abcdefABCDEF";
51 static void hex(char *dst, uint8_t *src, size_t len) {
53 dst[0] = hexchars[(src[0]>>4)&0xf];
54 dst[1] = hexchars[src[0]&0xf];
60 static int debuglevel = 0;
63 static void hexbin(uint8_t *dst, unsigned char *src, size_t len) {
67 for (i=0; i<len; i+=2) {
68 sscanf((const char *)src+i, "%02x", &x);
74 char *my_getline(struct tls_buffer *b, int fd, size_t *size) {
79 while (b->error == 0) {
80 loc = memchr(b->buffer, '\n', b->len);
82 *size = loc - b->buffer + 1;
85 rv = read(fd, buf, sizeof buf);
92 tls_buffer_append(b, buf, rv);
103 * We use a trust on first use policy. The trust DB is a simple
104 * file in /var/lib/zpm/known_hosts, or ~/.zpm/known_hosts, or ZPM_KNOWNHOSTS.
105 * if -k is given, no verification is done
107 int verify_first(struct TLSContext *context, struct TLSCertificate **chain, int
110 char *trustfile, *homedir = 0, *host, *fp;
111 unsigned char certhash[65];
113 struct tls_buffer tbuf;
118 if (certs == 0 || chain == 0) {
122 err = tls_certificate_is_valid(chain[0]);
128 err = tls_certificate_valid_subject(chain[0], context->sni);
134 hex(certhash, chain[0]->fp, 32);
137 trustfile = getenv("ZPM_KNOWNHOSTS");
139 if (geteuid() == 0) {
140 trustfile = "/var/lib/zpm/known_hosts";
142 /* we could do this with a series of
143 * openat() calls instead of building
146 trustfile = getenv("HOME");
148 fprintf(stderr, "home = %s\n", trustfile);
151 len = snprintf(homedir, 0, "%s/.zpm/known_hosts", trustfile);
152 homedir = malloc(len+1);
156 len = snprintf(homedir, len+1, "%s/.zpm/known_hosts", trustfile);
160 /* cert is valid on its face, so check against the trust db */
161 trustdb = open(trustfile, O_RDWR|O_CREAT, 0600);
163 fprintf(stderr, "cannot open trustdb %s: %s\n", trustfile, strerror(errno));
175 tls_buffer_init(&tbuf, 128);
179 tls_buffer_shift(&tbuf, len);
180 line = my_getline(&tbuf, trustdb, &len);
187 while (isspace(*fp)) {
193 off = strchr(line, ':');
199 if (line[len-1] == '\n') {
203 if (strlen(fp) != 64) {
207 if (len && line[len-1] == '\n') {
211 if (strcmp(context->sni, host) != 0) {
215 int match = (memcmp(certhash, fp, 64) == 0);
217 fprintf(stderr, "host %s certificate changed\n", host);
218 fprintf(stderr, "was %.64s\n", fp);
219 fprintf(stderr, "now %.64s\n", certhash);
223 tls_buffer_free(&tbuf);
224 return match ? no_error : bad_certificate;
225 } while (!tbuf.error);
227 /* got here, so we should be at EOF, so add this host to trust db */
228 lseek(trustdb, 0, SEEK_END);
230 /* re-use the buffer so we only do one write */
231 /* ignore errors, the cert is fine, we just can't update
232 * the trustdb if there's errors here
235 tls_buffer_append(&tbuf, certhash, 64);
236 tls_buffer_append_byte(&tbuf, ':');
237 tls_buffer_append(&tbuf, context->sni, strlen(context->sni));
238 tls_buffer_append_byte(&tbuf, '\n');
239 write(trustdb, tbuf.buffer, tbuf.len);
241 tls_buffer_free(&tbuf);
246 int verify_roots(struct TLSContext *context, struct TLSCertificate **chain, int
251 for (i = 0; i < len; i++) {
252 struct TLSCertificate *certificate = chain[i];
253 err = tls_certificate_is_valid(certificate);
260 err = tls_certificate_chain_is_valid(chain, len);
265 if (len > 0 && context->sni) {
266 err = tls_certificate_valid_subject(chain[0], context->sni);
272 /* Perform certificate validation against ROOT CA */
273 err = tls_certificate_chain_is_valid_root(context, chain, len);
282 struct tls_buffer response;
283 struct tls_buffer chunkbuf;
284 struct TLSContext *tls;
291 size_t chunkbytesread;
293 time_t last_modified;
295 size_t content_length;
299 ssize_t unchunk(struct io *io);
302 char *months[] = {"Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul",
303 "Aug", "Sep", "Oct", "Nov", "Dec" };
306 for (i=0; i < 12; i++) {
307 if (!strncasecmp(m, months[i], 3)) {
314 /* Wed, 06 Feb 2019 10:06:05 GMT */
315 time_t parse_date(char *d) {
316 struct tm tm = { 0 };
321 rv = sscanf(d, "%*[a-zA-Z,] %d %s %d %d:%d:%d", &dom, M, &Y, &h, &m, &s);
323 tm.tm_year = Y - 1900;
327 tm.tm_mon = month(M)-1;
335 char *find_header(struct io *io, char *header, size_t *len) {
341 hlen = strlen(header);
343 /* TODO can't do this, buffer may not be zero terminated */
344 eoh = strstr(io->response.buffer, "\r\n\r\n");
349 soh = io->response.buffer;
351 /* skip the first line for some reason */
352 soh = strstr(soh, "\r\n");
357 /* done if not enough room */
358 if (hlen > (size_t)(eoh - soh)) {
361 if (!strncasecmp(soh, header, hlen)) {
369 eoh = strstr(soh, "\r\n");
371 while (soh < eoh && isspace(*soh)) {
378 void parse_header(struct io *io) {
379 char *s = io->response.buffer;
384 while (!isspace(*s)) {
387 while (isspace(*s)) {
390 code = strtol(s, 0, 10);
391 io->status_code = code;
393 hval = find_header(io, "Date:", &hlen);
396 io->date = parse_date(hval);
399 hval = find_header(io, "Last-Modified:", &hlen);
402 io->last_modified = parse_date(hval);
406 hval = find_header(io, "Content-Length:", &hlen);
409 io->content_length = strtoul(hval, 0, 10);
413 hval = find_header(io, "Transfer-Encoding:", &hlen);
416 io->content_length = strtoul(hval, 0, 10);
417 if (!strcmp(hval, "chunked")) {
428 DEBUG(1, "looking for Location header\n");
429 hval = find_header(io, "Location:", &hlen);
431 io->redirect = strndup(hval, hlen);
440 /* fill buffer needs to put bytes into the response buffer
441 * if the transfer encoding is chunked, it will need to
442 * put the bytes into the chunkbuf first, then call
443 * unchunk. if unchunk return 0, then it needs more data,
444 * otherwise unchunk returns the number of bytes transferred
447 ssize_t fill_buffer(struct io *io) {
448 unsigned char buffer[4096];
455 ret = tls_read(io->tls, buffer, sizeof buffer);
457 ret = read(io->socket, buffer, sizeof buffer);
465 tls_buffer_append(&io->chunkbuf, buffer, ret);
466 //fwrite(buffer, ret, 1, stderr);
468 if (ret != 0 || io->chunksize == 0) {
472 tls_buffer_append(&io->response, buffer, ret);
480 /* essentially memmem */
481 void *lookfor(const void *buf, size_t buflen, const void *pattern, size_t len) {
482 const char *bf = buf;
483 const char *pt = pattern;
486 while (len <= (buflen - (p - bf))) {
487 if ((p = memchr(p, *pt, buflen - (p - bf))) != 0) {
488 if (memcmp(p, pattern, len) == 0) {
500 /* returns read chunksize, unshifts the line */
501 ssize_t read_chunksize(struct io *io) {
505 //fwrite(io->chunkbuf.buffer, io->chunkbuf.len, 1, stderr);
507 /* there could be up to two leading bytes */
508 if (io->chunkbuf.len >= 2 && io->chunkbuf.buffer[0] == '\r' && io->chunkbuf.buffer[1] == '\n') {
509 tls_buffer_shift(&io->chunkbuf, 2);
512 cr = lookfor(io->chunkbuf.buffer, io->chunkbuf.len, "\r\n", 2);
518 cs = strtol(io->chunkbuf.buffer, 0, 16);
519 tls_buffer_shift(&io->chunkbuf, cr - io->chunkbuf.buffer + 2);
524 /* unchunk's job is to move bytes from the chunk buf to the response buf */
525 /* return bytes from chunk, 0 if unable. once last chunk, changed chunked
528 ssize_t unchunk(struct io *io) {
529 ssize_t bytes_to_move = 0;
532 if (!io || !io->chunked) {
536 if (io->chunkleft == 0) {
537 chunksize = read_chunksize(io);
538 if (chunksize == -1) {
541 io->chunksize = chunksize;
542 if (io->chunksize == 0) {
543 /* end of chunked data */
548 io->chunkleft = io->chunksize;
549 io->chunktotal += io->chunksize;
552 if (io->chunkbuf.len == 0) {
553 /* need more bytes */
557 bytes_to_move = io->chunkbuf.len < io->chunkleft ? io->chunkbuf.len : io->chunkleft;
559 tls_buffer_append(&io->response, io->chunkbuf.buffer, bytes_to_move);
560 io->chunkleft -= bytes_to_move;
561 io->chunkbytesread += bytes_to_move;
563 /* chunk is terminated with a crlf */
564 //tls_buffer_shift(&io->chunkbuf, bytes_to_move + io->chunkleft ? 0 : 2);
565 tls_buffer_shift(&io->chunkbuf, bytes_to_move);
567 return bytes_to_move;
571 char *nextline(struct io *io) {
574 eol = memchr(io->response.buffer, '\n', io.response.size);
577 eol = memchr(io->response.buffer, '\n', io.response.size);
584 void append_header(struct tls_buffer *buf, char *header, char *val) {
585 tls_buffer_append(buf, header, strlen(header));
586 tls_buffer_append(buf, ": ", 2);
587 tls_buffer_append(buf, val, strlen(val));
588 tls_buffer_append(buf, "\r\n", 2);
591 void append_timeheader(struct tls_buffer *buf, char *header, time_t ts) {
597 strftime(timestr, sizeof timestr, "%a, %d %b %Y %H:%M:%S GMT", tm);
598 append_header(buf, header, timestr);
601 static void pdots(int len, int ch, unsigned long was, unsigned long now,
602 unsigned long total) {
603 was = len * was / total;
607 now = len * now / total;
608 while (was++ < now) {
613 static void fake_header(struct io *io, int fd) {
616 char *message, codestr[5], length[32];
617 struct tls_buffer *hdr = &io->response;
621 case EACCES: code = 403; break;
622 case ENOENT: code = 404; break;
623 default: code = 500; break;
632 if (io->last_modified >= st.st_mtime) {
637 case 200: message = "OK"; break;
638 case 304: message = "Not Modified"; break;
639 case 403: message = "Forbidden"; break;
640 case 404: message = "Not Found"; break;
641 case 500: message = "Internal Server Error"; break;
644 sprintf(codestr, "%0.3d ", code);
645 tls_buffer_append(hdr, "HTTP/1.1 ", 9);
646 tls_buffer_append(hdr, codestr, 4);
647 tls_buffer_append_str(hdr, message);
648 tls_buffer_append(hdr, "\r\n", 2);
650 append_timeheader(hdr, "Date", time(NULL));
651 append_header(hdr, "Server", "zpm-fetchurl/0.9");
653 append_timeheader(hdr, "Last-Modified", st.st_mtime);
654 sprintf(length, "%zu", st.st_size);
655 append_header(hdr, "Content-Length", length);
658 append_header(hdr, "Connection", "close");
659 append_header(hdr, "Content-Type", "application/octet-stream");
660 tls_buffer_append(hdr, "\r\n", 2);
663 char *pathlast(char *path) {
671 while (*path == '/') {
678 while (*path && *path != '/') {
682 while (*path == '/') {
691 return strndup(last, len);
694 static time_t file_mtime(char *path) {
698 rv = stat(path, &st);
700 if (errno == ENOENT) {
703 perror("stat failed:");
710 int main(int ac, char *av[]) {
711 int sockfd, port = -1, rv;
715 char msg[] = "GET %s HTTP/1.1\r\nHost: %s:%i\r\nConnection: close\r\n\r\n";
716 char msg2[] = "GET %s HTTP/1.1\r\nHost: %s:%i\r\nLast-Modified: %s\r\nConnection: close\r\n\r\n";
717 char msg_buffer[1024];
721 struct tls_uri uri = { 0 };
723 int raw = 0, head = 0;
724 int out = 1; /* output file descriptor */
726 struct io io = { {0}, {0}, 0, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
727 struct TLSContext *clientssl = 0;
731 struct tls_buffer request;
734 char *user_agent = 0;
738 int redirs = 0, redirlimit = 50, printstatus = 0, showreq = 0;
739 int verifypolicy = 1, calcoutfile = 0, ifnewer = 0;
743 while ((option = getopt(ac, av, "do:OrIfz:np#RL:SkKU:")) != -1) {
745 case 'd': debuglevel++; break;
746 case 'o': outfile = optarg; break;
747 case 'O': calcoutfile = 1; break;
748 case 'S': printstatus = 1; head = 1; break;
749 case 'k': verifypolicy = 0; break;
750 case 'K': verifypolicy = 2; break;
751 case 'U': user_agent = optarg; break;
753 case 'r': raw = 1; break;
754 case 'R': showreq = 1; break;
755 case 'f': failsilent = 1; break;
756 case 'z': lmfile = optarg; break;
757 case 'n': ifnewer = 1; break;
758 case 'L': redirlimit = strtol(optarg, 0, 10); break;
760 case '#': progressbar = 1; break;
768 fprintf(stderr, "Usage: %s uri\n", av[0]);
772 url = strdup(av[optind]);
777 io.last_modified = 0;
779 if (calcoutfile && !outfile) {
780 tls_parse_uri(url, &uri);
781 outfile = pathlast(uri.path);
782 /* outfile leaks memory here, so if this
783 * were turned into a library function,
784 * we'd need to track it
787 fprintf(stderr, "unable to determine outfile\n");
792 if (ifnewer && outfile && !lmfile) {
800 ts = file_mtime(lmfile);
804 } else if (ts != 0) {
805 io.last_modified = ts;
807 strftime(lmtime, sizeof lmtime, "%a, %d %b %Y %H:%M:%S GMT", mtime);
813 signal(SIGPIPE, SIG_IGN);
815 tls_buffer_init(&io.response, 0);
816 tls_buffer_init(&request, 128);
818 while (redirs++ <= redirlimit) {
825 tls_parse_uri(url, &uri);
827 port = atoi(uri.port);
830 /* construct request */
832 tls_buffer_append(&request, "HEAD ", 5);
834 tls_buffer_append(&request, "GET ", 4);
836 tls_buffer_append(&request, uri.encoded_path, strlen(uri.encoded_path));
837 if (uri.encoded_query) {
838 tls_buffer_append(&request, "?", 1);
839 tls_buffer_append(&request, uri.encoded_query, strlen(uri.encoded_query));
841 tls_buffer_append(&request, " HTTP/1.1\r\n", 11);
843 append_header(&request, "Host", host);
845 append_header(&request, "User-Agent", user_agent);
847 append_header(&request, "Accept", "*/*");
848 //append_header(&request, "Accept-Encoding", "chunked, identity;q=0.5");
849 append_header(&request, "Connection", "close");
851 append_header(&request, "If-Modified-Since", lmtime);
853 tls_buffer_append(&request, "\r\n", 2);
855 if (!strcmp(uri.scheme, "https")) {
858 DEBUG(1, "creating tls context\n");
859 clientssl = tls_create_context(TLS_CLIENT, TLS_V12);
861 /* optionally, we can set a certificate validation
862 * callback function if set_verify is not called, and
863 * root ca is set, `tls_default_verify` will be used
864 * (does exactly what `verify` does in this example)
866 if (verifypolicy == 2) {
868 cert_path = getenv("ZPM_CERTFILE");
870 cert_path = "/var/lib/zpm/roots.pem";
872 rv = tls_load_root_file(clientssl, cert_path);
874 fprintf(stderr, "Error loading root certs\n");
877 DEBUG(1, "verifying ssl cert via roots\n");
878 tls_set_verify(clientssl, verify_roots);
879 } else if (verifypolicy == 1) {
880 DEBUG(1, "verifying ssl cert via first use\n");
881 tls_set_verify(clientssl, verify_first);
882 DEBUG(1, "verified ssl cert via first use\n");
884 DEBUG(1, "verifying ssl cert via trust\n");
885 tls_set_verify(clientssl, verify_trust);
889 fprintf(stderr, "Error initializing client context\n");
892 tls_sni_set(clientssl, uri.host);
893 DEBUG(1, "set sni to %s\n", uri.host);
896 sockfd = open_tcp_connection(host, port);
897 DEBUG(1, "opened tcp socket fd %d\n", sockfd);
899 perror("can't open connection");
902 tls_set_fd(clientssl, sockfd);
903 if ((rv = tls_connect(clientssl)) != 1) {
904 fprintf(stderr, "Handshake Error %i\n", rv);
907 ret = tls_write(clientssl, request.buffer, request.len);
908 } else if (!strcmp(uri.scheme, "http")) {
909 sockfd = open_tcp_connection(host, port);
911 perror("can't open connection");
914 ret = write(sockfd, request.buffer, request.len);
915 } else if (!strcmp(uri.scheme, "file")) {
916 sockfd = open(uri.path, O_RDONLY);
917 fake_header(&io, sockfd);
920 fprintf(stderr, "scheme %s unknown\n", uri.scheme);
924 DEBUG(1, "wrote http request\n");
926 fprintf(stderr, "unable to write http request: %s\n", strerror(errno));
934 if (io.response.len >= 4) {
935 eoh = strstr(io.response.buffer, "\r\n\r\n");
938 DEBUG(1, "filling buffer\n");
939 ret = fill_buffer(&io);
945 DEBUG(1, "got response\n");
948 /* never got (complete) header */
949 fprintf(stderr, "incomplete response (ret = %zd) to %s\n", ret, url);
950 fprintf(stderr, "have:\n");
951 fwrite(io.response.buffer, io.response.len, 1, stderr);
955 header_len = (size_t)(eoh - io.response.buffer) + 4;
958 DEBUG(1, "parsed response header, code %d\n", io.status_code);
960 switch (io.status_code) {
968 DEBUG(1, "redirecting to %s\n", io.redirect);
970 url = strdup(io.redirect);
971 DEBUG(1, "redirecting to %s\n", url);
978 printf("%d\n", io.status_code);
982 fwrite(request.buffer, request.len, 1, stderr);
986 io.response.len -= 2;
987 write(out, io.response.buffer, io.response.len);
991 if (io.status_code == 304) {
996 out = open(outfile, O_WRONLY|O_CREAT|O_TRUNC, 0600);
998 perror("can't open output file:");
1004 if (io.content_length) {
1005 fprintf(stderr, "(%lu) ", io.content_length);
1010 write(out, io.response.buffer, header_len);
1012 tls_buffer_shift(&io.response, header_len);
1015 /* we've written out the head if needed, so
1016 * what's in the response buffer is the
1017 * chunked encoding, so just reassign that
1018 * to the chunkbuf and reinit */
1019 io.chunkbuf = io.response;
1020 tls_buffer_init(&io.response, 0);
1021 /* and put whatever we've got into the response
1022 * buffer, may not be needed, fill buffer
1029 size_t before = io.received;
1030 if (io.response.len) {
1031 if (io.content_length && io.response.len + io.received > io.content_length) {
1032 io.response.len = io.content_length - io.received;
1033 /* we just ignore trailing garbage */
1035 write(out, io.response.buffer, io.response.len);
1036 io.received += io.response.len;
1037 ret = io.response.len;
1038 io.response.len = 0;
1042 if (io.content_length) {
1043 pdots(50, '.', before, io.received,
1047 fprintf(stderr, "%zu", io.received);
1054 if (io.content_length && io.received >= io.content_length) {
1057 ret = fill_buffer(&io);
1060 //fprintf(stderr, "total received: %zu/%zu\n", io.received, io.content_length);
1062 fprintf(stderr, "%s read error %zd\n", uri.scheme, ret);
1064 if (io.last_modified != 0) {
1065 struct timespec ts[2];
1066 ts[0].tv_sec = 0; ts[0].tv_nsec = UTIME_OMIT;
1067 ts[1].tv_sec = io.last_modified;
1072 tls_buffer_free(&io.response);
1077 tls_shutdown(clientssl);
1078 tls_free(clientssl);
1082 if (progressbar && io.status_code == 200) {
1083 if (io.received == io.content_length || io.content_length == 0) {
1084 fprintf(stderr, " done\n");
1085 } else if (io.content_length != io.received) {
1086 fprintf(stderr, "failed (%zu bytes read)\n", total);
1087 io.status_code = 531; /* non official code */
1091 return io.status_code < 400 ? 0 : EXIT_FAILURE;