aboutsummaryrefslogtreecommitdiff
path: root/usr.sbin/certctl/certctl.c
diff options
context:
space:
mode:
Diffstat (limited to 'usr.sbin/certctl/certctl.c')
-rw-r--r--usr.sbin/certctl/certctl.c75
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;