summaryrefslogtreecommitdiff
path: root/src/conn-tools/s6-accessrules-cdb-from-fs.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/conn-tools/s6-accessrules-cdb-from-fs.c')
-rw-r--r--src/conn-tools/s6-accessrules-cdb-from-fs.c195
1 files changed, 195 insertions, 0 deletions
diff --git a/src/conn-tools/s6-accessrules-cdb-from-fs.c b/src/conn-tools/s6-accessrules-cdb-from-fs.c
new file mode 100644
index 0000000..20fef4d
--- /dev/null
+++ b/src/conn-tools/s6-accessrules-cdb-from-fs.c
@@ -0,0 +1,195 @@
+/* ISC license. */
+
+#include <unistd.h>
+#include <errno.h>
+#include <stdio.h> /* for rename() */
+#include <skalibs/bytestr.h>
+#include <skalibs/uint16.h>
+#include <skalibs/fmtscan.h>
+#include <skalibs/cdb_make.h>
+#include <skalibs/strerr2.h>
+#include <skalibs/stralloc.h>
+#include <skalibs/direntry.h>
+#include <skalibs/djbunix.h>
+#include <skalibs/skamisc.h>
+#include <skalibs/random.h>
+
+#define USAGE "s6-accessrules-cdb-from-fs cdbfile dir"
+
+static stralloc tmp = STRALLOC_ZERO ;
+
+static void cleanup (void)
+{
+ register int e = errno ;
+ unlink(tmp.s) ;
+ errno = e ;
+}
+
+static void dienomem (void)
+{
+ cleanup() ;
+ strerr_diefu1sys(111, "stralloc_catb") ;
+}
+
+static void doit (struct cdb_make *c, stralloc *sa, unsigned int start)
+{
+ unsigned int tmpbase = tmp.len ;
+ unsigned int k = sa->len ;
+ if (!stralloc_readyplus(sa, 10)) dienomem() ;
+ stralloc_catb(sa, "/allow", 7) ;
+ tmp.s[tmpbase] = 0 ;
+ if (access(sa->s, F_OK) < 0)
+ {
+ if ((errno != ENOENT) && (errno != EACCES))
+ {
+ cleanup() ;
+ strerr_diefu2sys(111, "access ", sa->s) ;
+ }
+ sa->len = k+1 ;
+ stralloc_catb(sa, "deny", 5) ;
+ if (access(sa->s, F_OK) < 0)
+ if ((errno != ENOENT) && (errno != EACCES))
+ {
+ cleanup() ;
+ strerr_diefu2sys(111, "access ", sa->s) ;
+ }
+ else return ;
+ else if (cdb_make_add(c, sa->s + start, k - start, "D", 1) < 0)
+ {
+ cleanup() ;
+ strerr_diefu1sys(111, "cdb_make_add") ;
+ }
+ }
+ else
+ {
+ uint16 envlen = 0 ;
+ uint16 execlen = 0 ;
+ register int r ;
+ tmp.s[tmpbase] = 'A' ;
+ sa->len = k+1 ;
+ stralloc_catb(sa, "env", 4) ;
+ tmp.len = tmpbase + 3 ;
+ if ((envdir(sa->s, &tmp) < 0) && (errno != ENOENT))
+ {
+ cleanup() ;
+ strerr_diefu2sys(111, "envdir ", sa->s) ;
+ }
+ if (tmp.len > tmpbase + 4103)
+ {
+ cleanup() ;
+ strerr_diefu2sys(100, sa->s, "too big") ;
+ }
+ envlen = tmp.len - tmpbase - 3 ;
+ tmp.len = tmpbase ;
+ uint16_pack_big(tmp.s + tmpbase + 1, envlen) ;
+ sa->len = k+1 ;
+ stralloc_catb(sa, "exec", 5) ;
+ r = openreadnclose(sa->s, tmp.s + tmpbase + 5 + envlen, 4096) ;
+ if ((r < 0) && (errno != ENOENT))
+ {
+ cleanup() ;
+ strerr_diefu2sys(111, "openreadnclose ", sa->s) ;
+ }
+ if (r > 0) execlen = r ;
+ if (execlen == 4096) strerr_warnw2x("possibly truncated file ", sa->s) ;
+ uint16_pack_big(tmp.s + tmpbase + 3 + envlen, execlen) ;
+ if (cdb_make_add(c, sa->s + start, k - start, tmp.s + tmpbase, 5 + envlen + execlen) < 0)
+ {
+ cleanup() ;
+ strerr_diefu1sys(111, "cdb_make_add") ;
+ }
+ }
+}
+
+int main (int argc, char const *const *argv)
+{
+ stralloc sa = STRALLOC_ZERO ;
+ struct cdb_make c = CDB_MAKE_ZERO ;
+ DIR *dir ;
+ unsigned int start ;
+ int fd ;
+ PROG = "s6-accessrules-cdb-from-fs" ;
+ if (argc < 3) strerr_dieusage(100, USAGE) ;
+ if (!stralloc_cats(&tmp, argv[1])) return 0 ;
+ if (random_sauniquename(&tmp, 8) < 0)
+ strerr_diefu1sys(111, "random_sauniquename") ;
+ if (!stralloc_readyplus(&tmp, 8210))
+ strerr_diefu1sys(111, "stralloc_catb") ;
+ stralloc_0(&tmp) ;
+ fd = open_trunc(tmp.s) ;
+ if (fd < 0) strerr_diefu2sys(111, "open_trunc ", tmp.s) ;
+ if (cdb_make_start(&c, fd) < 0)
+ {
+ cleanup() ;
+ strerr_diefu1sys(111, "cdb_make_start") ;
+ }
+ dir = opendir(argv[2]) ;
+ if (!dir)
+ {
+ cleanup() ;
+ strerr_diefu2sys(111, "opendir ", argv[2]) ;
+ }
+ if (!stralloc_cats(&sa, argv[2]) || !stralloc_catb(&sa, "/", 1)) dienomem() ;
+ start = sa.len ;
+
+ for (;;)
+ {
+ DIR *subdir ;
+ direntry *d ;
+ unsigned int base ;
+ errno = 0 ;
+ d = readdir(dir) ;
+ if (!d) break ;
+ if (d->d_name[0] == '.') continue ;
+ sa.len = start ;
+ if (!stralloc_cats(&sa, d->d_name) || !stralloc_0(&sa)) dienomem() ;
+ base = sa.len ;
+ subdir = opendir(sa.s) ;
+ if (!subdir)
+ {
+ cleanup() ;
+ strerr_diefu2sys(111, "opendir ", sa.s) ;
+ }
+ sa.s[base-1] = '/' ;
+ for (;;)
+ {
+ errno = 0 ;
+ d = readdir(subdir) ;
+ if (!d) break ;
+ if (d->d_name[0] == '.') continue ;
+ sa.len = base ;
+ if (!stralloc_cats(&sa, d->d_name)) dienomem() ;
+ doit(&c, &sa, start) ;
+ }
+ if (errno)
+ {
+ sa.s[base-1] = 0 ;
+ cleanup() ;
+ strerr_diefu2sys(111, "readdir ", sa.s) ;
+ }
+ dir_close(subdir) ;
+ }
+ if (errno)
+ {
+ cleanup() ;
+ strerr_diefu2sys(111, "readdir ", argv[2]) ;
+ }
+ dir_close(dir) ;
+ if (cdb_make_finish(&c) < 0)
+ {
+ cleanup() ;
+ strerr_diefu1sys(111, "cdb_make_finish") ;
+ }
+ if (fd_sync(fd) < 0)
+ {
+ cleanup() ;
+ strerr_diefu1sys(111, "fd_sync") ;
+ }
+ fd_close(fd) ;
+ if (rename(tmp.s, argv[1]) < 0)
+ {
+ cleanup() ;
+ strerr_diefu4sys(111, "rename ", tmp.s, " to ", argv[1]) ;
+ }
+ return 0 ;
+}