diff --git a/gemi.c b/gemi.c index 4277cba..6f98d9f 100644 --- a/gemi.c +++ b/gemi.c @@ -1,10 +1,13 @@ -#define _POSIX_C_SOURCE 200809L /* getopt, scandir */ +#define _POSIX_C_SOURCE 200809L /* getopt, scandir, openat */ #include +#include #include #include #include #include #include +#include +#include #include "purr.h" #include "mmap_file.h" @@ -137,35 +140,57 @@ int main(int argc, char **argv) } const char *home = getenv("HOME"); - const char *config = ".config/gemi"; - const int path_max = PATH_MAX; - char config_tmp[PATH_MAX]; if (home) { - if (snprintf(config_tmp, path_max, "%s/%s", home, config) >= path_max) { - fputs("path is too long!\n", stderr); - goto early_out; + char config[PATH_MAX]; + if (snprintf(config, PATH_MAX, "%s/%s", home, ".config/gemi") >= PATH_MAX) { + fputs("HOME is too long!\n", stderr); + goto stop_search; } - config = config_tmp; + int config_fd = open(config, O_DIRECTORY | O_PATH | O_CLOEXEC); + if (config_fd < 0) { + perror("open()"); + goto stop_search; + } + + struct dirent **files = NULL; + // XXX: ideally, should use scandirat(2), but that's currently glibc only + int filenum = scandir(config, &files, dirfilter, alphasort); + if (filenum < 0) { + if (debug) { + perror("scandir()"); + fprintf(stderr, "error reading configuration directory '%s'\n", config); + } + goto stop_search; + } + for (int i = 0; i < filenum; i++) { + int file = openat(config_fd, files[i]->d_name, O_RDONLY | O_CLOEXEC); + if (file < 0) { + perror("openat()"); + goto loop_end; + } + + struct stat st; + fstat(file, &st); + if ((st.st_mode & S_IFMT) == S_IFREG) { + FILE *file_stream = fdopen(file, "re"); + if (file_stream == NULL) { + close(file); + goto loop_end; + } + + if (bearssl_read_certs(&btas, file_stream) == 0) { + if (debug) fprintf(stderr, "error reading cert file: '%s'\n", files[i]->d_name); + } + } else { + close(file); + } + + loop_end: + free(files[i]); + } + free(files); } - struct dirent **files = NULL; - int filenum = scandir(config, &files, dirfilter, alphasort); - if (filenum < 0) { - if (debug) { - perror("scandir()"); - fprintf(stderr, "error reading configuration directory '%s'\n", config); - } - } - for (int i = 0; i < filenum; i++) { - char filename_tmp[PATH_MAX]; - if (snprintf(filename_tmp, path_max, "%s/%s", config, files[i]->d_name) >= path_max) { - continue; - } - if (bearssl_read_certs(&btas, filename_tmp) == 0) { - if (debug) fprintf(stderr, "error reading cert file '%s'\n", filename_tmp); - } - free(files[i]); - } - free(files); + stop_search: br_ssl_client_init_full(&sc, &xc, btas.ta, btas.n); br_ssl_engine_set_buffer(&sc.eng, iobuf, sizeof iobuf, 1); diff --git a/read_certs.c b/read_certs.c index ccc3b37..2452830 100644 --- a/read_certs.c +++ b/read_certs.c @@ -4,7 +4,6 @@ #include #include "read_certs.h" -#include "mmap_file.h" struct append_dn_status { uint8_t *dn; @@ -104,21 +103,22 @@ static void push_x509(void *dest_ctx, const void *src, size_t len) /* * Reads certs from file if set, otherwise from default location. */ -size_t bearssl_read_certs(struct trust_anchors *tas, const char *file) +size_t bearssl_read_certs(struct trust_anchors *tas, FILE *file) { - const char *cert_path = file ? file : getenv("CA_CERT_SSL_FILE"); - if (cert_path == NULL) { - cert_path = "/etc/ssl/certs.pem"; - } + size_t rv = 0; - struct mmap_file cert_map = create_mmap_from_file(cert_path, PROT_READ); - if (ERROR_MMAP(cert_map)) { - perror("create_mmap_from_file()"); - return 0; - } + if (file == NULL) { + const char *cert_path = getenv("CA_CERT_SSL_FILE"); + if (cert_path == NULL) { + cert_path = "/etc/ssl/certs.pem"; + } - off_t len = cert_map.size; - uint8_t *data = cert_map.data; + file = fopen(cert_path, "re"); + if (file == NULL) { + perror("fopen()"); + return rv; + } + } br_pem_decoder_context pem; br_x509_decoder_context x509; @@ -127,10 +127,20 @@ size_t bearssl_read_certs(struct trust_anchors *tas, const char *file) struct append_dn_status dn_status; - while (len > 0) { - size_t pushed = br_pem_decoder_push(&pem, data, len); - data += pushed; + uint8_t data[512]; + uint8_t *datap; + size_t len = 0; + while (1) { + if (len == 0) { + len = fread(data, 1, 512, file); + if (len == 0) { + break; + } + datap = data; + } + size_t pushed = br_pem_decoder_push(&pem, datap, len); len -= pushed; + datap += pushed; switch(br_pem_decoder_event(&pem)) { const char *name; @@ -179,7 +189,7 @@ size_t bearssl_read_certs(struct trust_anchors *tas, const char *file) .e = malloc(k.elen), .elen = k.elen}; if (rsa.n == NULL || rsa.e == NULL) { perror("malloc()"); - return 0; + goto out; } memcpy(rsa.n, k.n, k.nlen); memcpy(rsa.e, k.e, k.elen); @@ -193,7 +203,7 @@ size_t bearssl_read_certs(struct trust_anchors *tas, const char *file) .q = malloc(k.qlen), .qlen = k.qlen}; if (ec.q == NULL) { perror("malloc()"); - return 0; + goto out; } memcpy(ec.q, k.q, k.qlen); @@ -205,12 +215,15 @@ size_t bearssl_read_certs(struct trust_anchors *tas, const char *file) ta.pkey = new_key; if (append_ta(tas, ta) == -1) { - return 0; + goto out; } } break; } } - return tas->n; + rv = tas->n; + out: + fclose(file); + return rv; } diff --git a/read_certs.h b/read_certs.h index 8f0e1e6..b087751 100644 --- a/read_certs.h +++ b/read_certs.h @@ -12,6 +12,6 @@ struct trust_anchors { void bearssl_read_certs_help(FILE *); void bearssl_free_certs(struct trust_anchors); -size_t bearssl_read_certs(struct trust_anchors *, const char *); +size_t bearssl_read_certs(struct trust_anchors *, FILE *); #endif // __READ_CERTS_H_