diff options
Diffstat (limited to 'usr.sbin/certctl/certctl.c')
-rw-r--r-- | usr.sbin/certctl/certctl.c | 75 |
1 files changed, 62 insertions, 13 deletions
diff --git a/usr.sbin/certctl/certctl.c b/usr.sbin/certctl/certctl.c index 365870167aeb..ed7f05126ca7 100644 --- a/usr.sbin/certctl/certctl.c +++ b/usr.sbin/certctl/certctl.c @@ -63,6 +63,7 @@ static bool verbose; static const char *localbase; static const char *destdir; +static const char *distbase; static const char *metalog; static const char *uname = "root"; @@ -100,6 +101,28 @@ static char *bundle_dest; static FILE *mlf; /* + * Remove duplicate and trailing slashes from a path. + */ +static char * +normalize_path(const char *str) +{ + char *buf, *dst; + + if ((buf = malloc(strlen(str) + 1)) == NULL) + err(1, NULL); + for (dst = buf; *str != '\0'; dst++) { + if ((*dst = *str++) == '/') { + while (*str == '/') + str++; + if (*str == '\0') + break; + } + } + *dst = '\0'; + return (buf); +} + +/* * Split a colon-separated list into a NULL-terminated array. */ static char ** @@ -124,14 +147,14 @@ split_paths(const char *str) } /* - * Expand %L into LOCALBASE and prefix DESTDIR. + * Expand %L into LOCALBASE and prefix DESTDIR and DISTBASE as needed. */ static char * expand_path(const char *template) { if (template[0] == '%' && template[1] == 'L') return (xasprintf("%s%s%s", destdir, localbase, template + 2)); - return (xasprintf("%s%s", destdir, template)); + return (xasprintf("%s%s%s", destdir, distbase, template)); } /* @@ -155,6 +178,9 @@ expand_paths(const char *const *templates) /* * If destdir is a prefix of path, returns a pointer to the rest of path, * otherwise returns path. + * + * Note that this intentionally does not strip distbase from the path! + * Unlike destdir, distbase is expected to be included in the metalog. */ static const char * unexpand_path(const char *path) @@ -268,7 +294,7 @@ read_cert(const char *path, struct cert_tree *tree, struct cert_tree *exclude) X509_NAME *name; struct cert *cert; unsigned long hash; - int ni, no; + int len, ni, no; if ((f = fopen(path, "r")) == NULL) { warn("%s", path); @@ -293,11 +319,21 @@ read_cert(const char *path, struct cert_tree *tree, struct cert_tree *exclude) cert->x509 = x509; name = X509_get_subject_name(x509); cert->hash = X509_NAME_hash_ex(name, NULL, NULL, NULL); - cert->name = X509_NAME_oneline(name, NULL, 0); + len = X509_NAME_get_text_by_NID(name, NID_commonName, + NULL, 0); + if (len > 0) { + if ((cert->name = malloc(len + 1)) == NULL) + err(1, NULL); + X509_NAME_get_text_by_NID(name, NID_commonName, + cert->name, len + 1); + } else { + /* fallback for certificates without CN */ + cert->name = X509_NAME_oneline(name, NULL, 0); + } cert->path = xstrdup(unexpand_path(path)); if (RB_INSERT(cert_tree, tree, cert) != NULL) errx(1, "unexpected duplicate"); - info("%08lx: %s", cert->hash, strrchr(cert->name, '=') + 1); + info("%08lx: %s", cert->hash, cert->name); no++; } /* @@ -488,9 +524,10 @@ write_certs(const char *dir, struct cert_tree *tree) free(tmppath); tmppath = NULL; } + fflush(f); /* emit metalog */ if (mlf != NULL) { - fprintf(mlf, "%s/%s type=file " + fprintf(mlf, ".%s/%s type=file " "uname=%s gname=%s mode=%#o size=%ld\n", unexpand_path(dir), path, uname, gname, mode, ftell(f)); @@ -561,7 +598,7 @@ write_bundle(const char *dir, const char *file, struct cert_tree *tree) } if (ret == 0 && mlf != NULL) { fprintf(mlf, - "%s/%s type=file uname=%s gname=%s mode=%#o size=%ld\n", + ".%s/%s type=file uname=%s gname=%s mode=%#o size=%ld\n", unexpand_path(dir), file, uname, gname, mode, ftell(f)); } fclose(f); @@ -925,6 +962,14 @@ set_defaults(void) if (destdir == NULL && (destdir = getenv("DESTDIR")) == NULL) destdir = ""; + destdir = normalize_path(destdir); + + if (distbase == NULL && + (distbase = getenv("DISTBASE")) == NULL) + distbase = ""; + if (*distbase != '\0' && *distbase != '/') + errx(1, "DISTBASE=%s does not begin with a slash", distbase); + distbase = normalize_path(distbase); if (unprivileged && metalog == NULL && (metalog = getenv("METALOG")) == NULL) @@ -966,6 +1011,7 @@ set_defaults(void) info("localbase:\t%s", localbase); info("destdir:\t%s", destdir); + info("distbase:\t%s", distbase); info("unprivileged:\t%s", unprivileged ? "true" : "false"); info("verbose:\t%s", verbose ? "true" : "false"); } @@ -987,11 +1033,11 @@ static struct { static void usage(void) { - fprintf(stderr, "usage: certctl [-lv] [-D destdir] list\n" - " certctl [-lv] [-D destdir] untrusted\n" - " certctl [-BnUv] [-D destdir] [-M metalog] rehash\n" - " certctl [-nv] [-D destdir] untrust <file>\n" - " certctl [-nv] [-D destdir] trust <file>\n"); + fprintf(stderr, "usage: certctl [-lv] [-D destdir] [-d distbase] list\n" + " certctl [-lv] [-D destdir] [-d distbase] untrusted\n" + " certctl [-BnUv] [-D destdir] [-d distbase] [-M metalog] rehash\n" + " certctl [-nv] [-D destdir] [-d distbase] untrust <file>\n" + " certctl [-nv] [-D destdir] [-d distbase] trust <file>\n"); exit(1); } @@ -1001,7 +1047,7 @@ main(int argc, char *argv[]) const char *command; int opt; - while ((opt = getopt(argc, argv, "BcD:g:lL:M:no:Uv")) != -1) + while ((opt = getopt(argc, argv, "BcD:d:g:lL:M:no:Uv")) != -1) switch (opt) { case 'B': nobundle = true; @@ -1012,6 +1058,9 @@ main(int argc, char *argv[]) case 'D': destdir = optarg; break; + case 'd': + distbase = optarg; + break; case 'g': gname = optarg; break; |