-/* $OpenBSD: main.c,v 1.118 2021/03/11 11:57:45 claudio Exp $ */
+/* $OpenBSD: main.c,v 1.119 2021/03/15 08:56:31 claudio Exp $ */
/*
* Copyright (c) 2019 Kristaps Dzonsons <kristaps@bsd.lv>
*
*/
#define REPO_MAX_URI 2
struct repo {
+ SLIST_ENTRY(repo) entry;
char *repouri; /* CA repository base URI */
char *local; /* local path name */
char *temp; /* temporary file / dir */
char *uris[REPO_MAX_URI]; /* URIs to fetch from */
+ struct entityq queue; /* files waiting for this repo */
size_t id; /* identifier (array index) */
int uriidx; /* which URI is fetched */
int loaded; /* whether loaded or not */
/*
* Table of all known repositories.
*/
-static struct repotab {
- struct repo *repos; /* repositories */
- size_t reposz; /* number of repos */
-} rt;
+SLIST_HEAD(, repo) repos = SLIST_HEAD_INITIALIZER(repos);
+size_t repoid;
/*
* Database of all file path accessed during a run.
* repo, then flush those into the parser process.
*/
static void
-entityq_flush(struct entityq *q, const struct repo *repo)
+entityq_flush(struct repo *repo)
{
struct entity *p, *np;
- TAILQ_FOREACH_SAFE(p, q, entries, np) {
- if (p->repo < 0 || repo->id != (size_t)p->repo)
- continue;
+ TAILQ_FOREACH_SAFE(p, &repo->queue, entries, np) {
entity_write_req(p);
- TAILQ_REMOVE(q, p, entries);
+ TAILQ_REMOVE(&repo->queue, p, entries);
entity_free(p);
}
}
* Add the heap-allocated file to the queue for processing.
*/
static void
-entityq_add(struct entityq *q, char *file, enum rtype type,
- const struct repo *rp, const unsigned char *pkey, size_t pkeysz,
- char *descr)
+entityq_add(char *file, enum rtype type, struct repo *rp,
+ const unsigned char *pkey, size_t pkeysz, char *descr)
{
struct entity *p;
p->type = type;
p->file = file;
- p->repo = (rp != NULL) ? (ssize_t)rp->id : -1;
p->has_pkey = pkey != NULL;
if (p->has_pkey) {
p->pkeysz = pkeysz;
entity_write_req(p);
entity_free(p);
} else
- TAILQ_INSERT_TAIL(q, p, entries);
+ TAILQ_INSERT_TAIL(&rp->queue, p, entries);
}
/*
- * Allocat a new repository be extending the repotable.
+ * Allocate and insert a new repository.
*/
static struct repo *
repo_alloc(void)
{
struct repo *rp;
- rt.repos = recallocarray(rt.repos, rt.reposz, rt.reposz + 1,
- sizeof(struct repo));
- if (rt.repos == NULL)
+ if ((rp = calloc(1, sizeof(*rp))) == NULL)
err(1, NULL);
- rp = &rt.repos[rt.reposz++];
- rp->id = rt.reposz - 1;
+ rp->id = ++repoid;
+ TAILQ_INIT(&rp->queue);
+ SLIST_INSERT_HEAD(&repos, rp, entry);
+
+ return rp;
+}
+
+static struct repo *
+repo_find(size_t id)
+{
+ struct repo *rp;
+ SLIST_FOREACH(rp, &repos, entry)
+ if (id == rp->id)
+ break;
return rp;
}
/*
* Look up a trust anchor, queueing it for download if not found.
*/
-static const struct repo *
+static struct repo *
ta_lookup(const struct tal *tal)
{
struct repo *rp;
err(1, NULL);
/* Look up in repository table. (Lookup should actually fail here) */
- for (i = 0; i < rt.reposz; i++) {
- if (strcmp(rt.repos[i].local, local) != 0)
+ SLIST_FOREACH(rp, &repos, entry) {
+ if (strcmp(rp->local, local) != 0)
continue;
free(local);
- return &rt.repos[i];
+ return rp;
}
rp = repo_alloc();
/*
* Look up a repository, queueing it for discovery if not found.
*/
-static const struct repo *
+static struct repo *
repo_lookup(const char *uri)
{
char *local, *repo;
struct repo *rp;
- size_t i;
if ((repo = rsync_base_uri(uri)) == NULL)
return NULL;
/* Look up in repository table. */
- for (i = 0; i < rt.reposz; i++) {
- if (rt.repos[i].repouri == NULL ||
- strcmp(rt.repos[i].repouri, repo) != 0)
+ SLIST_FOREACH(rp, &repos, entry) {
+ if (rp->repouri == NULL ||
+ strcmp(rp->repouri, repo) != 0)
continue;
free(repo);
- return &rt.repos[i];
+ return rp;
}
rp = repo_alloc();
* These are always relative to the directory in which "mft" sits.
*/
static void
-queue_add_from_mft(struct entityq *q, const char *mft,
- const struct mftfile *file, enum rtype type)
+queue_add_from_mft(const char *mft, const struct mftfile *file, enum rtype type)
{
char *cp, *nfile;
* that the repository has already been loaded.
*/
- entityq_add(q, nfile, type, NULL, NULL, 0, NULL);
+ entityq_add(nfile, type, NULL, NULL, 0, NULL);
}
/*
* check the suffix anyway).
*/
static void
-queue_add_from_mft_set(struct entityq *q, const struct mft *mft)
+queue_add_from_mft_set(const struct mft *mft)
{
size_t i, sz;
const struct mftfile *f;
assert(sz > 4);
if (strcasecmp(f->file + sz - 4, ".crl") != 0)
continue;
- queue_add_from_mft(q, mft->file, f, RTYPE_CRL);
+ queue_add_from_mft(mft->file, f, RTYPE_CRL);
}
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(q, mft->file, f, RTYPE_CER);
+ queue_add_from_mft(mft->file, f, RTYPE_CER);
else if (strcasecmp(f->file + sz - 4, ".roa") == 0)
- queue_add_from_mft(q, mft->file, f, RTYPE_ROA);
+ queue_add_from_mft(mft->file, f, RTYPE_ROA);
else if (strcasecmp(f->file + sz - 4, ".gbr") == 0)
- queue_add_from_mft(q, mft->file, f, RTYPE_GBR);
+ queue_add_from_mft(mft->file, f, RTYPE_GBR);
else
logx("%s: unsupported file type: %s", mft->file,
f->file);
* Add a local TAL file (RFC 7730) to the queue of files to fetch.
*/
static void
-queue_add_tal(struct entityq *q, const char *file)
+queue_add_tal(const char *file)
{
char *nfile, *buf;
}
/* Not in a repository, so directly add to queue. */
- entityq_add(q, nfile, RTYPE_TAL, NULL, NULL, 0, buf);
+ entityq_add(nfile, RTYPE_TAL, NULL, NULL, 0, buf);
/* entityq_add makes a copy of buf */
free(buf);
}
* Add URIs (CER) from a TAL file, RFC 8630.
*/
static void
-queue_add_from_tal(struct entityq *q, const struct tal *tal)
+queue_add_from_tal(const struct tal *tal)
{
- char *nfile;
- const struct repo *repo;
+ char *nfile;
+ struct repo *repo;
assert(tal->urisz);
repo = ta_lookup(tal);
nfile = ta_filename(repo, 0);
- entityq_add(q, nfile, RTYPE_CER, repo, tal->pkey,
+ entityq_add(nfile, RTYPE_CER, repo, tal->pkey,
tal->pkeysz, tal->descr);
}
* Add a manifest (MFT) found in an X509 certificate, RFC 6487.
*/
static void
-queue_add_from_cert(struct entityq *q, const struct cert *cert)
+queue_add_from_cert(const struct cert *cert)
{
- const struct repo *repo;
- char *nfile;
+ struct repo *repo;
+ char *nfile;
repo = repo_lookup(cert->mft);
if (repo == NULL) /* bad repository URI */
nfile = repo_filename(repo, cert->mft);
- entityq_add(q, nfile, RTYPE_MFT, repo, NULL, 0, NULL);
+ entityq_add(nfile, RTYPE_MFT, repo, NULL, 0, NULL);
}
/*
* In all cases, we gather statistics.
*/
static void
-entity_process(int proc, struct stats *st, struct entityq *q,
- struct vrp_tree *tree)
+entity_process(int proc, struct stats *st, struct vrp_tree *tree)
{
enum rtype type;
struct tal *tal;
case RTYPE_TAL:
st->tals++;
tal = tal_read(proc);
- queue_add_from_tal(q, tal);
+ queue_add_from_tal(tal);
tal_free(tal);
break;
case RTYPE_CER:
* we're revoked and then we don't want to
* process the MFT.
*/
- queue_add_from_cert(q, cert);
+ queue_add_from_cert(cert);
} else
st->certs_invalid++;
cert_free(cert);
mft = mft_read(proc);
if (mft->stale)
st->mfts_stale++;
- queue_add_from_mft_set(q, mft);
+ queue_add_from_mft_set(mft);
mft_free(mft);
break;
case RTYPE_CRL:
{
size_t i, delsz = 0;
char *argv[2], **del = NULL;
+ struct repo *rp;
FTS *fts;
FTSENT *e;
- for (i = 0; i < rt.reposz; i++) {
- if (asprintf(&argv[0], "%s", rt.repos[i].local) == -1)
- err(1, NULL);
+ SLIST_FOREACH(rp, &repos, entry) {
+ argv[0] = rp->local;
argv[1] = NULL;
if ((fts = fts_open(argv, FTS_PHYSICAL | FTS_NOSTAT,
NULL)) == NULL)
{
int rc = 1, c, st, proc, rsync, http,
fl = SOCK_STREAM | SOCK_CLOEXEC;
- size_t i, outsz = 0, talsz = 0;
+ size_t i, id, outsz = 0, talsz = 0;
pid_t procpid, rsyncpid, httppid;
int fd[2];
- struct entityq q;
struct pollfd pfd[3];
struct roa **out = NULL;
+ struct repo *rp;
char *rsync_prog = "openrsync";
char *bind_addr = NULL;
const char *cachedir = NULL, *outputdir = NULL;
if (talsz == 0)
err(1, "no TAL files found in %s", "/etc/rpki");
- TAILQ_INIT(&q);
-
/* change working directory to the cache directory */
if (fchdir(cachefd) == -1)
err(1, "fchdir");
*/
for (i = 0; i < talsz; i++)
- queue_add_tal(&q, tals[i]);
+ queue_add_tal(tals[i]);
while (entity_queue > 0 && !killme) {
pfd[0].events = POLLIN;
if ((pfd[0].revents & POLLIN)) {
int ok;
- io_simple_read(rsync, &i, sizeof(size_t));
+ io_simple_read(rsync, &id, sizeof(id));
io_simple_read(rsync, &ok, sizeof(ok));
- assert(i < rt.reposz);
+ rp = repo_find(id);
+ if (rp == NULL)
+ errx(1, "unknown repository id: %zu", id);
- assert(!rt.repos[i].loaded);
+ assert(!rp->loaded);
if (ok)
- logx("%s: loaded from network",
- rt.repos[i].local);
+ logx("%s: loaded from network", rp->local);
else
logx("%s: load from network failed, "
- "fallback to cache", rt.repos[i].local);
- rt.repos[i].loaded = 1;
+ "fallback to cache", rp->local);
+ rp->loaded = 1;
stats.repos++;
- entityq_flush(&q, &rt.repos[i]);
+ entityq_flush(rp);
}
if ((pfd[2].revents & POLLIN)) {
int ok;
- io_simple_read(http, &i, sizeof(size_t));
+ io_simple_read(http, &id, sizeof(id));
io_simple_read(http, &ok, sizeof(ok));
- assert(i < rt.reposz);
+ rp = repo_find(id);
+ if (rp == NULL)
+ errx(1, "unknown repository id: %zu", id);
- assert(!rt.repos[i].loaded);
- if (http_done(&rt.repos[i], ok)) {
- rt.repos[i].loaded = 1;
+ assert(!rp->loaded);
+ if (http_done(rp, ok)) {
+ rp->loaded = 1;
stats.repos++;
- entityq_flush(&q, &rt.repos[i]);
+ entityq_flush(rp);
}
}
*/
if ((pfd[1].revents & POLLIN)) {
- entity_process(proc, &stats, &q, &v);
+ entity_process(proc, &stats, &v);
}
}
errx(1, "excessive runtime (%d seconds), giving up", timeout);
}
- assert(TAILQ_EMPTY(&q));
+ assert(entity_queue == 0);
logx("all files parsed: generating output");
rc = 0;
logx("VRP Entries: %zu (%zu unique)", stats.vrps, stats.uniqs);
/* Memory cleanup. */
- for (i = 0; i < rt.reposz; i++) {
- free(rt.repos[i].repouri);
- free(rt.repos[i].local);
- free(rt.repos[i].temp);
- free(rt.repos[i].uris[0]);
- free(rt.repos[i].uris[1]);
+ while ((rp = SLIST_FIRST(&repos)) != NULL) {
+ SLIST_REMOVE_HEAD(&repos, entry);
+ free(rp->repouri);
+ free(rp->local);
+ free(rp->temp);
+ free(rp->uris[0]);
+ free(rp->uris[1]);
+ free(rp);
}
- free(rt.repos);
for (i = 0; i < outsz; i++)
roa_free(out[i]);