For RRDP support the repository code needs to be cleaned up and adjusted.
Instead of working with host/module store the URI (repo->repo) and the
local path (repo->local). This simplifies the communication between
rpki-client main process and the rsync process a fair bit.

Also introduce mkpath() stolen and adjusted from bin/mkdir to create
all directories in a path. In a second step the repository layout will
probably change so that rsync and rrdp can coexist. This is why some code
is currently maybe a bit extra complex.

-- 
:wq Claudio

Index: Makefile
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/Makefile,v
retrieving revision 1.16
diff -u -p -r1.16 Makefile
--- Makefile    8 Jan 2021 08:09:07 -0000       1.16
+++ Makefile    2 Feb 2021 17:24:34 -0000
@@ -1,8 +1,8 @@
 #      $OpenBSD: Makefile,v 1.16 2021/01/08 08:09:07 claudio Exp $
 
 PROG=  rpki-client
-SRCS=  as.c cert.c cms.c crl.c gbr.c io.c ip.c log.c main.c mft.c output.c \
-       output-bgpd.c output-bird.c output-csv.c output-json.c \
+SRCS=  as.c cert.c cms.c crl.c gbr.c io.c ip.c log.c main.c mft.c mkdir.c \
+       output.c output-bgpd.c output-bird.c output-csv.c output-json.c \
        roa.c rsync.c tal.c validate.c x509.c
 MAN=   rpki-client.8
 
Index: extern.h
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/extern.h,v
retrieving revision 1.38
diff -u -p -r1.38 extern.h
--- extern.h    29 Jan 2021 10:13:16 -0000      1.38
+++ extern.h    2 Feb 2021 17:25:27 -0000
@@ -422,6 +422,8 @@ int          output_json(FILE *, struct vrp_tre
 void   logx(const char *fmt, ...)
                    __attribute__((format(printf, 1, 2)));
 
+int    mkpath(const char *);
+
 #define                RPKI_PATH_OUT_DIR       "/var/db/rpki-client"
 #define                RPKI_PATH_BASE_DIR      "/var/cache/rpki-client"
 
Index: main.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/main.c,v
retrieving revision 1.91
diff -u -p -r1.91 main.c
--- main.c      29 Jan 2021 10:13:16 -0000      1.91
+++ main.c      2 Feb 2021 17:57:51 -0000
@@ -83,10 +83,11 @@
  * An rsync repository.
  */
 struct repo {
-       char    *host; /* hostname */
-       char    *module; /* module name */
-       int      loaded; /* whether loaded or not */
-       size_t   id; /* identifier (array index) */
+       char            *repo;  /* repository rsync URI */
+       char            *local; /* local path name */
+       char            *notify; /* RRDB notify URI if available */
+       size_t           id; /* identifier (array index) */
+       int              loaded; /* whether loaded or not */
 };
 
 size_t entity_queue;
@@ -288,6 +289,7 @@ repo_lookup(struct msgbuf *msgq, const c
 {
        const char      *host, *mod;
        size_t           hostsz, modsz, i;
+       char            *local;
        struct repo     *rp;
        struct ibuf     *b;
 
@@ -295,17 +297,16 @@ repo_lookup(struct msgbuf *msgq, const c
            &mod, &modsz, NULL, NULL, NULL, uri))
                errx(1, "%s: malformed", uri);
 
+       if (asprintf(&local, "%.*s/%.*s", (int)hostsz, host,
+           (int)modsz, mod) == -1)
+               err(1, "asprintf");
+
        /* Look up in repository table. */
 
        for (i = 0; i < rt.reposz; i++) {
-               if (strlen(rt.repos[i].host) != hostsz)
-                       continue;
-               if (strlen(rt.repos[i].module) != modsz)
-                       continue;
-               if (strncasecmp(rt.repos[i].host, host, hostsz))
-                       continue;
-               if (strncasecmp(rt.repos[i].module, mod, modsz))
+               if (strcmp(rt.repos[i].local, local))
                        continue;
+               free(local);
                return &rt.repos[i];
        }
 
@@ -317,25 +318,25 @@ repo_lookup(struct msgbuf *msgq, const c
        rp = &rt.repos[rt.reposz++];
        memset(rp, 0, sizeof(struct repo));
        rp->id = rt.reposz - 1;
+       rp->local = local;
 
-       if ((rp->host = strndup(host, hostsz)) == NULL ||
-           (rp->module = strndup(mod, modsz)) == NULL)
-               err(1, "strndup");
-
-       i = rt.reposz - 1;
+       if ((rp->repo = strndup(uri, mod + modsz - uri)) == NULL)
+               err(1, "strdup");
 
        if (!noop) {
-               logx("%s/%s: pulling from network", rp->host, rp->module);
-               if ((b = ibuf_dynamic(128, UINT_MAX)) == NULL)
+               if (asprintf(&local, "%s", rp->local) == -1)
+                       err(1, "asprintf");
+               logx("%s: pulling from network", local);
+               if ((b = ibuf_dynamic(256, UINT_MAX)) == NULL)
                        err(1, NULL);
-               io_simple_buffer(b, &i, sizeof(i));
-               io_str_buffer(b, rp->host);
-               io_str_buffer(b, rp->module);
-
+               io_simple_buffer(b, &rp->id, sizeof(rp->id));
+               io_str_buffer(b, local);
+               io_str_buffer(b, rp->repo);
                ibuf_close(msgq, b);
+               free(local);
        } else {
                rp->loaded = 1;
-               logx("%s/%s: using cache", rp->host, rp->module);
+               logx("%s: using cache", rp->local);
                stats.repos++;
                /* there is nothing in the queue so no need to flush */
        }
@@ -350,9 +351,8 @@ repo_filename(const struct repo *repo, c
 {
        char *nfile;
 
-       uri += 8 + strlen(repo->host) + 1 + strlen(repo->module) + 1;
-
-       if (asprintf(&nfile, "%s/%s/%s", repo->host, repo->module, uri) == -1)
+       uri += strlen(repo->repo) + 1;
+       if (asprintf(&nfile, "%s/%s", repo->local, uri) == -1)
                err(1, "asprintf");
        return nfile;
 }
@@ -411,8 +411,6 @@ queue_add_from_mft(struct msgbuf *msgq, 
        char            *cp, *nfile;
 
        /* Construct local path from filename. */
-       /* We know this is host/module/... */
-
        cp = strrchr(mft, '/');
        assert(cp != NULL);
        assert(cp - mft < INT_MAX);
@@ -555,17 +553,13 @@ queue_add_from_tal(struct msgbuf *procq,
  */
 static void
 queue_add_from_cert(struct msgbuf *procq, struct msgbuf *rsyncq,
-    struct entityq *q, const char *rsyncuri, const char *rrdpuri)
+    struct entityq *q, const struct cert *cert)
 {
-       char                    *nfile;
        const struct repo       *repo;
+       char                    *nfile;
 
-       if (rsyncuri == NULL)
-               return;
-
-       /* Look up the repository. */
-       repo = repo_lookup(rsyncq, rsyncuri);
-       nfile = repo_filename(repo, rsyncuri);
+       repo = repo_lookup(rsyncq, cert->mft);
+       nfile = repo_filename(repo, cert->mft);
 
        entityq_add(procq, q, nfile, RTYPE_MFT, repo, NULL, 0, NULL);
 }
@@ -1206,7 +1200,7 @@ entity_process(int proc, struct msgbuf *
                         * process the MFT.
                         */
                        queue_add_from_cert(procq, rsyncq,
-                           q, cert->mft, cert->notify);
+                           q, cert);
                } else
                        st->certs_invalid++;
                cert_free(cert);
@@ -1311,8 +1305,7 @@ repo_cleanup(const char *cachedir)
                err(1, "%s: chdir", cachedir);
 
        for (i = 0; i < rt.reposz; i++) {
-               if (asprintf(&argv[0], "%s/%s", rt.repos[i].host,
-                   rt.repos[i].module) == -1)
+               if (asprintf(&argv[0], "%s", rt.repos[i].local) == -1)
                        err(1, NULL);
                argv[1] = NULL;
                if ((fts = fts_open(argv, FTS_PHYSICAL | FTS_NOSTAT,
@@ -1603,8 +1596,11 @@ main(int argc, char *argv[])
 
                if (c == 0) {
                        for (i = j = 0; i < rt.reposz; i++)
-                               if (!rt.repos[i].loaded)
+                               if (!rt.repos[i].loaded) {
+                                       logx("pending repo %s",
+                                           rt.repos[i].local);
                                        j++;
+                               }
                        logx("period stats: %zu pending repos", j);
                        logx("period stats: %zu pending entries", entity_queue);
                        continue;
@@ -1646,15 +1642,15 @@ main(int argc, char *argv[])
                        io_simple_read(rsync, &i, sizeof(size_t));
                        io_simple_read(rsync, &ok, sizeof(ok));
                        assert(i < rt.reposz);
+
                        assert(!rt.repos[i].loaded);
                        rt.repos[i].loaded = 1;
                        if (ok)
-                               logx("%s/%s: loaded from network",
-                                   rt.repos[i].host, rt.repos[i].module);
+                               logx("%s: loaded from network",
+                                   rt.repos[i].local);
                        else
-                               logx("%s/%s: load from network failed, "
-                                   "fallback to cache",
-                                   rt.repos[i].host, rt.repos[i].module);
+                               logx("%s: load from network failed, "
+                                   "fallback to cache", rt.repos[i].local);
                        stats.repos++;
                        entityq_flush(&procq, &q, &rt.repos[i]);
                }
@@ -1733,8 +1729,8 @@ main(int argc, char *argv[])
 
        /* Memory cleanup. */
        for (i = 0; i < rt.reposz; i++) {
-               free(rt.repos[i].host);
-               free(rt.repos[i].module);
+               free(rt.repos[i].local);
+               free(rt.repos[i].repo);
        }
        free(rt.repos);
 
Index: mkdir.c
===================================================================
RCS file: mkdir.c
diff -N mkdir.c
--- /dev/null   1 Jan 1970 00:00:00 -0000
+++ mkdir.c     2 Feb 2021 16:56:35 -0000
@@ -0,0 +1,75 @@
+/*     $OpenBSD: mkdir.c,v 1.31 2019/06/28 13:34:59 deraadt Exp $      */
+
+/*
+ * Copyright (c) 1983, 1992, 1993
+ *     The Regents of the University of California.  All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of the University nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <sys/stat.h>
+
+#include <errno.h>
+#include <string.h>
+
+#include "extern.h"
+
+/*
+ * mkpath -- create directories.
+ *     path     - path
+ *     mode     - file mode of terminal directory
+ *     dir_mode - file mode of intermediate directories
+ */
+int
+mkpath(const char *dir)
+{
+       char *path, *slash;
+       int done;
+
+       if ((path = strdup(dir)) == NULL)
+               return -1;
+
+       slash = path;
+       for (;;) {
+               slash += strspn(slash, "/");
+               slash += strcspn(slash, "/");
+
+               done = (*slash == '\0');
+               *slash = '\0';
+
+               if (mkdir(path, 0700) == -1 && errno != EEXIST) {
+                       free(path);
+                       return (-1);
+               }
+
+               if (done)
+                       break;
+
+               *slash = '/';
+       }
+
+       free(path);
+       return (0);
+}
Index: rsync.c
===================================================================
RCS file: /cvs/src/usr.sbin/rpki-client/rsync.c,v
retrieving revision 1.14
diff -u -p -r1.14 rsync.c
--- rsync.c     12 Jan 2021 09:22:11 -0000      1.14
+++ rsync.c     2 Feb 2021 17:37:35 -0000
@@ -173,8 +173,7 @@ proc_rsync(char *prog, char *bind_addr, 
 {
        size_t                   id, i, idsz = 0;
        ssize_t                  ssz;
-       char                    *host = NULL, *mod = NULL, *uri = NULL,
-                               *dst = NULL, *path, *save, *cmd;
+       char                    *uri = NULL, *dst = NULL, *path, *save, *cmd;
        const char              *pp;
        pid_t                    pid;
        char                    *args[32];
@@ -228,6 +227,9 @@ proc_rsync(char *prog, char *bind_addr, 
        if (unveil(NULL, NULL) == -1)
                err(1, "unveil");
 
+       if (pledge("stdio cpath proc exec", NULL) == -1)
+               err(1, "pledge");
+
        /* Initialise retriever for children exiting. */
 
        if (sigemptyset(&mask) == -1)
@@ -314,10 +316,10 @@ proc_rsync(char *prog, char *bind_addr, 
 
                /* Read host and module. */
 
-               io_str_read(fd, &host);
-               io_str_read(fd, &mod);
-               assert(host);
-               assert(mod);
+               io_str_read(fd, &dst);
+               io_str_read(fd, &uri);
+               assert(dst);
+               assert(uri);
 
                /*
                 * Create source and destination locations.
@@ -325,17 +327,9 @@ proc_rsync(char *prog, char *bind_addr, 
                 * will not build the destination for us.
                 */
 
-               if (mkdir(host, 0700) == -1 && EEXIST != errno)
-                       err(1, "%s", host);
-
-               if (asprintf(&dst, "%s/%s", host, mod) == -1)
-                       err(1, NULL);
-               if (mkdir(dst, 0700) == -1 && EEXIST != errno)
+               if (mkpath(dst))
                        err(1, "%s", dst);
 
-               if (asprintf(&uri, "rsync://%s/%s", host, mod) == -1)
-                       err(1, NULL);
-
                /* Run process itself, wait for exit, check error. */
 
                if ((pid = fork()) == -1)
@@ -378,9 +372,7 @@ proc_rsync(char *prog, char *bind_addr, 
 
                /* Clean up temporary values. */
 
-               free(mod);
                free(dst);
-               free(host);
        }
 
        /* No need for these to be hanging around. */

Reply via email to