based on information from the repository, a local path and the filename.
This simplifies some code both in the main process and the parser.
For this to work repositories are passed to the parser before any other
entity of this repository is passed. Struct entity is extended to include
the repoid and the path along the file(name).
Input and OK tb@ & job@
-/* $OpenBSD: extern.h,v 1.100 2021/12/29 11:37:57 claudio Exp $ */
+/* $OpenBSD: extern.h,v 1.101 2022/01/11 13:06:07 claudio Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
* manifest file.
*/
struct mft {
- char *file; /* full path of MFT file */
+ char *path; /* relative path to directory of the MFT */
struct mftfile *files; /* file and hash */
size_t filesz; /* number of filenames */
- int stale; /* if a stale manifest */
char *seqnum; /* manifestNumber */
char *aia; /* AIA */
char *aki; /* AKI */
char *ski; /* SKI */
+ unsigned int repoid;
+ int stale; /* if a stale manifest */
};
/*
RTYPE_CER,
RTYPE_CRL,
RTYPE_GBR,
+ RTYPE_REPO,
};
enum http_result {
*/
struct entity {
TAILQ_ENTRY(entity) entries;
- char *file; /* local path to file */
+ char *path; /* path relative to repository */
+ char *file; /* filename */
unsigned char *data; /* optional data blob */
size_t datasz; /* length of optional data blob */
+ unsigned int repoid; /* repository identifier */
int talid; /* tal identifier */
enum rtype type; /* type of entity (not RTYPE_EOF) */
};
void rrdp_save_state(unsigned int, struct rrdp_session *);
int rrdp_handle_file(unsigned int, enum publish_type, char *,
char *, size_t, char *, size_t);
-char *repo_filename(const struct repo *, const char *);
+char *repo_basedir(const struct repo *);
+unsigned int repo_id(const struct repo *);
+const char *repo_uri(const struct repo *);
struct repo *ta_lookup(int, struct tal *);
struct repo *repo_lookup(int, const char *, const char *);
+struct repo *repo_byid(unsigned int);
int repo_queued(struct repo *, struct entity *);
void repo_cleanup(struct filepath_tree *);
void repo_free(void);
-/* $OpenBSD: main.c,v 1.172 2022/01/06 16:06:30 claudio Exp $ */
+/* $OpenBSD: main.c,v 1.173 2022/01/11 13:06:07 claudio Exp $ */
/*
* Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
if (ent == NULL)
return;
- free(ent->data);
+ free(ent->path);
free(ent->file);
+ free(ent->data);
free(ent);
}
entity_read_req(struct ibuf *b, struct entity *ent)
{
io_read_buf(b, &ent->type, sizeof(ent->type));
+ io_read_buf(b, &ent->repoid, sizeof(ent->repoid));
io_read_buf(b, &ent->talid, sizeof(ent->talid));
+ io_read_str(b, &ent->path);
io_read_str(b, &ent->file);
io_read_buf_alloc(b, (void **)&ent->data, &ent->datasz);
}
b = io_new_buffer();
io_simple_buffer(b, &ent->type, sizeof(ent->type));
+ io_simple_buffer(b, &ent->repoid, sizeof(ent->repoid));
io_simple_buffer(b, &ent->talid, sizeof(ent->talid));
+ io_str_buffer(b, ent->path);
io_str_buffer(b, ent->file);
io_buf_buffer(b, ent->data, ent->datasz);
io_close_buffer(&procq, b);
}
+static void
+entity_write_repo(struct repo *rp)
+{
+ struct ibuf *b;
+ enum rtype type = RTYPE_REPO;
+ unsigned int repoid;
+ char *path;
+ int talid = 0;
+
+ repoid = repo_id(rp);
+ path = repo_basedir(rp);
+ b = io_new_buffer();
+ io_simple_buffer(b, &type, sizeof(type));
+ io_simple_buffer(b, &repoid, sizeof(repoid));
+ io_simple_buffer(b, &talid, sizeof(talid));
+ io_str_buffer(b, path);
+ io_str_buffer(b, NULL);
+ io_buf_buffer(b, NULL, 0);
+ io_close_buffer(&procq, b);
+ free(path);
+}
+
/*
* Scan through all queued requests and see which ones are in the given
* repo, then flush those into the parser process.
{
struct entity *p, *np;
- TAILQ_FOREACH_SAFE(p, q, entries, np) {
- char *file = p->file;
-
- /*
- * XXX fixup path here since the repo may change
- * during load because of fallback. In that case
- * the file path changes as well since RRDP and RSYNC
- * can not share a common repo.
- */
- p->file = repo_filename(rp, file);
- if (p->file == NULL)
- err(1, "can't construct repo filename");
- free(file);
+ entity_write_repo(rp);
+ TAILQ_FOREACH_SAFE(p, q, entries, np) {
entity_write_req(p);
TAILQ_REMOVE(q, p, entries);
entity_free(p);
* Add the heap-allocated file to the queue for processing.
*/
static void
-entityq_add(char *file, enum rtype type, struct repo *rp,
+entityq_add(char *path, char *file, enum rtype type, struct repo *rp,
unsigned char *data, size_t datasz, int talid)
{
struct entity *p;
p->type = type;
p->talid = talid;
+ p->path = path;
+ if (rp != NULL)
+ p->repoid = repo_id(rp);
p->file = file;
p->data = data;
p->datasz = (data != NULL) ? datasz : 0;
*/
if (rp == NULL || !repo_queued(rp, p)) {
- /*
- * XXX fixup path here since for repo path the
- * file path has not yet been fixed here.
- * This is a quick way to make this work but in
- * the long run repos need to be passed to the parser.
- */
- if (rp != NULL) {
- file = p->file;
- p->file = repo_filename(rp, file);
- if (p->file == NULL)
- err(1, "can't construct repo filename from %s",
- file);
- free(file);
- }
entity_write_req(p);
entity_free(p);
}
* These are always relative to the directory in which "mft" sits.
*/
static void
-queue_add_from_mft(const char *mft, const struct mftfile *file, enum rtype type)
+queue_add_from_mft(const char *path, const struct mftfile *file,
+ enum rtype type, struct repo *rp)
{
- char *cp, *nfile;
+ char *nfile, *npath = NULL;
- /* Construct local path from filename. */
- cp = strrchr(mft, '/');
- assert(cp != NULL);
- assert(cp - mft < INT_MAX);
- if (asprintf(&nfile, "%.*s/%s", (int)(cp - mft), mft, file->file) == -1)
+ if (path != NULL)
+ if ((npath = strdup(path)) == NULL)
+ err(1, NULL);
+ if ((nfile = strdup(file->file)) == NULL)
err(1, NULL);
- /*
- * Since we're from the same directory as the MFT file, we know
- * that the repository has already been loaded.
- */
-
- entityq_add(nfile, type, NULL, NULL, 0, -1);
+ entityq_add(npath, nfile, type, rp, NULL, 0, -1);
}
/*
* check the suffix anyway).
*/
static void
-queue_add_from_mft_set(const struct mft *mft)
+queue_add_from_mft_set(const struct mft *mft, const char *name, struct repo *rp)
{
size_t i, sz;
const struct mftfile *f;
assert(sz > 4);
if (strcasecmp(f->file + sz - 4, ".crl") != 0)
continue;
- queue_add_from_mft(mft->file, f, RTYPE_CRL);
+ queue_add_from_mft(mft->path, f, RTYPE_CRL, rp);
}
for (i = 0; i < mft->filesz; i++) {
if (strcasecmp(f->file + sz - 4, ".crl") == 0)
continue;
else if (strcasecmp(f->file + sz - 4, ".cer") == 0)
- queue_add_from_mft(mft->file, f, RTYPE_CER);
+ queue_add_from_mft(mft->path, f, RTYPE_CER, rp);
else if (strcasecmp(f->file + sz - 4, ".roa") == 0)
- queue_add_from_mft(mft->file, f, RTYPE_ROA);
+ queue_add_from_mft(mft->path, f, RTYPE_ROA, rp);
else if (strcasecmp(f->file + sz - 4, ".gbr") == 0)
- queue_add_from_mft(mft->file, f, RTYPE_GBR);
+ queue_add_from_mft(mft->path, f, RTYPE_GBR, rp);
else
- logx("%s: unsupported file type: %s", mft->file,
+ logx("%s: unsupported file type: %s", name,
f->file);
}
}
if ((nfile = strdup(file)) == NULL)
err(1, NULL);
/* Not in a repository, so directly add to queue. */
- entityq_add(nfile, RTYPE_TAL, NULL, buf, len, talid);
+ entityq_add(NULL, nfile, RTYPE_TAL, NULL, buf, len, talid);
}
/*
{
struct repo *repo;
unsigned char *data;
+ char *nfile;
assert(tal->urisz);
if ((taldescs[tal->id] = strdup(tal->descr)) == NULL)
err(1, NULL);
+ /* figure out the TA filename, must be done before repo lookup */
+ nfile = strrchr(tal->uri[0], '/');
+ assert(nfile != NULL);
+ if ((nfile = strdup(nfile + 1)) == NULL)
+ err(1, NULL);
+
/* Look up the repository. */
repo = ta_lookup(tal->id, tal);
if (repo == NULL)
/* steal the pkey from the tal structure */
data = tal->pkey;
tal->pkey = NULL;
- entityq_add(NULL, RTYPE_CER, repo, data, tal->pkeysz, tal->id);
+ entityq_add(NULL, nfile, RTYPE_CER, repo, data, tal->pkeysz, tal->id);
}
/*
queue_add_from_cert(const struct cert *cert)
{
struct repo *repo;
- char *nfile;
+ char *nfile, *npath;
+ const char *uri, *repouri, *file;
+ size_t repourisz;
repo = repo_lookup(cert->talid, cert->repo,
rrdpon ? cert->notify : NULL);
if (repo == NULL)
return;
- if ((nfile = strdup(cert->mft)) == NULL)
- err(1, NULL);
- entityq_add(nfile, RTYPE_MFT, repo, NULL, 0, -1);
+ /*
+ * Figure out the cert filename and path by chopping up the
+ * MFT URI in the cert based on the repo base URI.
+ */
+ uri = cert->mft;
+ repouri = repo_uri(repo);
+ repourisz = strlen(repouri);
+ if (strncmp(repouri, cert->mft, repourisz) != 0) {
+ warnx("%s: URI %s outside of repository", repouri, uri);
+ return;
+ }
+ uri += repourisz + 1; /* skip base and '/' */
+ file = strrchr(uri, '/');
+ if (file == NULL) {
+ npath = NULL;
+ if ((nfile = strdup(uri)) == NULL)
+ err(1, NULL);
+ } else {
+ if ((npath = strndup(uri, file - uri)) == NULL)
+ err(1, NULL);
+ if ((nfile = strdup(file + 1)) == NULL)
+ err(1, NULL);
+ }
+
+ entityq_add(npath, nfile, RTYPE_MFT, repo, NULL, 0, -1);
}
/*
}
mft = mft_read(b);
if (!mft->stale)
- queue_add_from_mft_set(mft);
+ queue_add_from_mft_set(mft, file,
+ repo_byid(mft->repoid));
else
st->mfts_stale++;
mft_free(mft);
-/* $OpenBSD: mft.c,v 1.43 2022/01/06 16:06:30 claudio Exp $ */
+/* $OpenBSD: mft.c,v 1.44 2022/01/11 13:06:07 claudio Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
if ((p.res = calloc(1, sizeof(struct mft))) == NULL)
err(1, NULL);
- if ((p.res->file = strdup(fn)) == NULL)
- err(1, NULL);
p.res->aia = x509_get_aia(*x509, fn);
p.res->aki = x509_get_aki(*x509, 0, fn);
free(p->aia);
free(p->aki);
free(p->ski);
- free(p->file);
+ free(p->path);
free(p->files);
free(p->seqnum);
free(p);
{
size_t i;
- io_simple_buffer(b, &p->stale, sizeof(int));
- io_str_buffer(b, p->file);
- io_simple_buffer(b, &p->filesz, sizeof(size_t));
+ io_simple_buffer(b, &p->stale, sizeof(p->stale));
+ io_simple_buffer(b, &p->repoid, sizeof(p->repoid));
+ io_str_buffer(b, p->path);
+
+ io_str_buffer(b, p->aia);
+ io_str_buffer(b, p->aki);
+ io_str_buffer(b, p->ski);
+ io_simple_buffer(b, &p->filesz, sizeof(size_t));
for (i = 0; i < p->filesz; i++) {
io_str_buffer(b, p->files[i].file);
io_simple_buffer(b, p->files[i].hash, SHA256_DIGEST_LENGTH);
}
-
- io_str_buffer(b, p->aia);
- io_str_buffer(b, p->aki);
- io_str_buffer(b, p->ski);
}
/*
if ((p = calloc(1, sizeof(struct mft))) == NULL)
err(1, NULL);
- io_read_buf(b, &p->stale, sizeof(int));
- io_read_str(b, &p->file);
- io_read_buf(b, &p->filesz, sizeof(size_t));
+ io_read_buf(b, &p->stale, sizeof(p->stale));
+ io_read_buf(b, &p->repoid, sizeof(p->repoid));
+ io_read_str(b, &p->path);
- assert(p->file);
+ io_read_str(b, &p->aia);
+ io_read_str(b, &p->aki);
+ io_read_str(b, &p->ski);
+ assert(p->aia && p->aki && p->ski);
+
+ io_read_buf(b, &p->filesz, sizeof(size_t));
if ((p->files = calloc(p->filesz, sizeof(struct mftfile))) == NULL)
err(1, NULL);
io_read_buf(b, p->files[i].hash, SHA256_DIGEST_LENGTH);
}
- io_read_str(b, &p->aia);
- io_read_str(b, &p->aki);
- io_read_str(b, &p->ski);
- assert(p->aia && p->aki && p->ski);
-
return p;
}
-/* $OpenBSD: parser.c,v 1.33 2022/01/05 11:07:35 claudio Exp $ */
+/* $OpenBSD: parser.c,v 1.34 2022/01/11 13:06:07 claudio Exp $ */
/*
* Copyright (c) 2019 Claudio Jeker <claudio@openbsd.org>
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
static struct auth_tree auths = RB_INITIALIZER(&auths);
static struct crl_tree crlt = RB_INITIALIZER(&crlt);
+struct parse_repo {
+ RB_ENTRY(parse_repo) entry;
+ char *path;
+ unsigned int id;
+};
+
+static RB_HEAD(repo_tree, parse_repo) repos = RB_INITIALIZER(&repos);
+
+static inline int
+repocmp(struct parse_repo *a, struct parse_repo *b)
+{
+ return a->id - b->id;
+}
+
+RB_GENERATE_STATIC(repo_tree, parse_repo, entry, repocmp);
+
+static struct parse_repo *
+repo_get(unsigned int id)
+{
+ struct parse_repo needle = { .id = id };
+
+ return RB_FIND(repo_tree, &repos, &needle);
+}
+
+static void
+repo_add(unsigned int id, char *path)
+{
+ struct parse_repo *rp;
+
+ if ((rp = malloc(sizeof(*rp))) == NULL)
+ err(1, NULL);
+ rp->id = id;
+ if ((rp->path = strdup(path)) == NULL)
+ err(1, NULL);
+
+ if (RB_INSERT(repo_tree, &repos, rp) != NULL)
+ errx(1, "repository already added: id %d, %s", id, path);
+}
+
static int
verify_cb(int ok, X509_STORE_CTX *store_ctx)
{
* Return the mft on success or NULL on failure.
*/
static struct mft *
-proc_parser_mft(char *file, const unsigned char *der, size_t len)
+proc_parser_mft(char *file, const unsigned char *der, size_t len,
+ const char *path, unsigned int repoid)
{
struct mft *mft;
X509 *x509;
return NULL;
}
+ if (path != NULL)
+ if ((mft->path = strdup(path)) == NULL)
+ err(1, NULL);
+ mft->repoid = repoid;
return mft;
}
err(1, "sk_X509_CRL_push");
}
+static char *
+parse_filepath(struct entity *entp)
+{
+ struct parse_repo *rp;
+ char *file;
+
+ /* build file path based on repoid, entity path and filename */
+ rp = repo_get(entp->repoid);
+ if (rp == NULL) {
+ if (entp->path == NULL) {
+ if ((file = strdup(entp->file)) == NULL)
+ err(1, NULL);
+ } else {
+ if (asprintf(&file, "%s/%s", entp->path,
+ entp->file) == -1)
+ err(1, NULL);
+ }
+ } else {
+ if (entp->path == NULL) {
+ if (asprintf(&file, "%s/%s", rp->path,
+ entp->file) == -1)
+ err(1, NULL);
+ } else {
+ if (asprintf(&file, "%s/%s/%s", rp->path,
+ entp->path, entp->file) == -1)
+ err(1, NULL);
+ }
+ }
+ return file;
+}
+
static void
parse_entity(struct entityq *q, struct msgbuf *msgq)
{
struct ibuf *b;
unsigned char *f;
size_t flen;
+ char *file;
int c;
while ((entp = TAILQ_FIRST(q)) != NULL) {
TAILQ_REMOVE(q, entp, entries);
- b = io_new_buffer();
+ /* handle RTYPE_REPO first */
+ if (entp->type == RTYPE_REPO) {
+ repo_add(entp->repoid, entp->path);
+ entity_free(entp);
+ continue;
+ }
f = NULL;
+ file = parse_filepath(entp);
if (entp->type != RTYPE_TAL) {
- f = load_file(entp->file, &flen);
+ f = load_file(file, &flen);
if (f == NULL)
- warn("%s", entp->file);
+ warn("%s", file);
}
/* pass back at least type and filename */
+ b = io_new_buffer();
io_simple_buffer(b, &entp->type, sizeof(entp->type));
- io_str_buffer(b, entp->file);
+ io_str_buffer(b, file);
switch (entp->type) {
case RTYPE_TAL:
break;
case RTYPE_CER:
if (entp->data != NULL)
- cert = proc_parser_root_cert(entp->file,
+ cert = proc_parser_root_cert(file,
f, flen, entp->data, entp->datasz,
entp->talid);
else
- cert = proc_parser_cert(entp->file, f, flen);
+ cert = proc_parser_cert(file, f, flen);
c = (cert != NULL);
io_simple_buffer(b, &c, sizeof(int));
if (cert != NULL)
*/
break;
case RTYPE_CRL:
- proc_parser_crl(entp->file, f, flen);
+ proc_parser_crl(file, f, flen);
break;
case RTYPE_MFT:
- mft = proc_parser_mft(entp->file, f, flen);
+ mft = proc_parser_mft(file, f, flen,
+ entp->path, entp->repoid);
c = (mft != NULL);
io_simple_buffer(b, &c, sizeof(int));
if (mft != NULL)
mft_free(mft);
break;
case RTYPE_ROA:
- roa = proc_parser_roa(entp->file, f, flen);
+ roa = proc_parser_roa(file, f, flen);
c = (roa != NULL);
io_simple_buffer(b, &c, sizeof(int));
if (roa != NULL)
roa_free(roa);
break;
case RTYPE_GBR:
- proc_parser_gbr(entp->file, f, flen);
+ proc_parser_gbr(file, f, flen);
break;
default:
- abort();
+ errx(1, "unhandled entity type %d", entp->type);
}
free(f);
+ free(file);
io_close_buffer(msgq, b);
entity_free(entp);
}
-/* $OpenBSD: repo.c,v 1.19 2022/01/04 18:16:09 claudio Exp $ */
+/* $OpenBSD: repo.c,v 1.20 2022/01/11 13:06:07 claudio Exp $ */
/*
* Copyright (c) 2021 Claudio Jeker <claudio@openbsd.org>
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
unsigned int id;
enum repo_state state;
};
-SLIST_HEAD(, rrdprepo) rrdprepos = SLIST_HEAD_INITIALIZER(rrdprepos);
+static SLIST_HEAD(, rrdprepo) rrdprepos = SLIST_HEAD_INITIALIZER(rrdprepos);
struct rsyncrepo {
SLIST_ENTRY(rsyncrepo) entry;
unsigned int id;
enum repo_state state;
};
-SLIST_HEAD(, rsyncrepo) rsyncrepos = SLIST_HEAD_INITIALIZER(rsyncrepos);
+static SLIST_HEAD(, rsyncrepo) rsyncrepos = SLIST_HEAD_INITIALIZER(rsyncrepos);
struct tarepo {
SLIST_ENTRY(tarepo) entry;
unsigned int id;
enum repo_state state;
};
-SLIST_HEAD(, tarepo) tarepos = SLIST_HEAD_INITIALIZER(tarepos);
+static SLIST_HEAD(, tarepo) tarepos = SLIST_HEAD_INITIALIZER(tarepos);
struct repo {
SLIST_ENTRY(repo) entry;
int talid;
unsigned int id; /* identifier */
};
-SLIST_HEAD(, repo) repos = SLIST_HEAD_INITIALIZER(repos);
+static SLIST_HEAD(, repo) repos = SLIST_HEAD_INITIALIZER(repos);
/* counter for unique repo id */
unsigned int repoid;
static struct filepath *
filepath_find(struct filepath_tree *tree, char *file)
{
- struct filepath needle;
+ struct filepath needle = { .file = file };
- needle.file = file;
return RB_FIND(filepath_tree, tree, &needle);
}
if (rp->rrdp == NULL)
rp->rsync = rsync_get(uri, nofetch);
+ if (repo_state(rp) != REPO_LOADING)
+ entityq_flush(&rp->queue, rp);
+
return rp;
}
/*
- * Build local file name base on the URI and the repo info.
+ * Find repository by identifier.
*/
-char *
-repo_filename(const struct repo *rp, const char *uri)
+struct repo *
+repo_byid(unsigned int id)
{
- char *nfile;
- char *dir, *repouri;
+ struct repo *rp;
- if (uri == NULL && rp->ta)
- return ta_filename(rp->ta, 0);
+ SLIST_FOREACH(rp, &repos, entry) {
+ if (rp->id == id)
+ return rp;
+ }
+ return NULL;
+}
- assert(uri != NULL);
- if (rp->rrdp)
- return rrdp_filename(rp->rrdp, uri, 0);
+/*
+ * Return the repository base directory.
+ * Returned string must be freed by caller.
+ */
+char *
+repo_basedir(const struct repo *rp)
+{
+ char *path;
- /* must be rsync */
- dir = rp->rsync->basedir;
- repouri = rp->rsync->repouri;
+ if (rp->ta) {
+ if ((path = strdup(rp->ta->basedir)) == NULL)
+ err(1, NULL);
+ } else if (rp->rsync) {
+ if ((path = strdup(rp->rsync->basedir)) == NULL)
+ err(1, NULL);
+ } else if (rp->rrdp) {
+ path = rrdp_filename(rp->rrdp, rp->repouri, 0);
+ } else
+ errx(1, "%s: bad repo", rp->repouri);
- if (strstr(uri, repouri) != uri) {
- warnx("%s: URI %s outside of repository", repouri, uri);
- return NULL;
- }
+ return path;
+}
- uri += strlen(repouri) + 1; /* skip base and '/' */
+/*
+ * Return the repository identifier.
+ */
+unsigned int
+repo_id(const struct repo *rp)
+{
+ return rp->id;
+}
- if (asprintf(&nfile, "%s/%s", dir, uri) == -1)
- err(1, NULL);
- return nfile;
+/*
+ * Return the repository URI.
+ */
+const char *
+repo_uri(const struct repo *rp)
+{
+ return rp->repouri;
}
int
if (rp->ta)
http_finish(rp->ta->id, HTTP_FAILED, NULL);
- else if (rp->rrdp)
- rrdp_finish(rp->rrdp->id, 0);
else if (rp->rsync)
rsync_finish(rp->rsync->id, 0);
+ else if (rp->rrdp)
+ rrdp_finish(rp->rrdp->id, 0);
else
errx(1, "%s: bad repo", rp->repouri);
}