s6

Mirror/fork of https://skarnet.org/software/s6/
git clone https://ccx.te2000.cz/git/s6
Log | Files | Refs | README | LICENSE

s6-accessrules-fs-from-cdb.c (4263B)


      1 /* ISC license. */
      2 
      3 #include <string.h>
      4 #include <stdint.h>
      5 #include <sys/stat.h>
      6 #include <errno.h>
      7 #include <unistd.h>
      8 
      9 #include <skalibs/bytestr.h>
     10 #include <skalibs/types.h>
     11 #include <skalibs/cdb.h>
     12 #include <skalibs/strerr.h>
     13 #include <skalibs/djbunix.h>
     14 
     15 #define USAGE "s6-accessrules-fs-from-cdb dir cdbfile"
     16 
     17 static char const *basedir ;
     18 size_t basedirlen ;
     19 
     20 static void cleanup ()
     21 {
     22   int e = errno ;
     23   rm_rf(basedir) ;
     24   errno = e ;
     25 }
     26 
     27 static int domkdir (char const *s)
     28 {
     29   return mkdir(s, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH | S_ISGID) < 0 ? errno == EEXIST : 1 ;
     30 }
     31 
     32 static void mkdirp (char *s)
     33 {
     34   mode_t m = umask(0) ;
     35   size_t len = strlen(s) ;
     36   size_t i = basedirlen + 1 ;
     37   for (; i < len ; i++) if (s[i] == '/')
     38   {
     39     s[i] = 0 ;
     40     if (!domkdir(s)) goto err ;
     41     s[i] = '/' ;
     42   }
     43   if (!domkdir(s)) goto err ;
     44   umask(m) ;
     45   return ;
     46 
     47  err:
     48   cleanup() ;
     49   strerr_diefu2sys(111, "mkdir ", s) ;
     50 }
     51 
     52 static void touchtrunc (char const *file)
     53 {
     54   int fd = open_trunc(file) ;
     55   if (fd < 0)
     56   {
     57     cleanup() ;
     58     strerr_diefu2sys(111, "open_trunc ", file) ;
     59   }
     60   fd_close(fd) ;
     61 }
     62 
     63 static int doenv (char const *dir, size_t dirlen, char const *env, uint32_t envlen)
     64 {
     65   mode_t m = umask(0) ;
     66   size_t i = 0 ;
     67   if (!domkdir(dir))
     68   {
     69     cleanup() ;
     70     strerr_diefu2sys(111, "mkdir ", dir) ;
     71   }
     72   umask(m) ;
     73   while (i < envlen)
     74   {
     75     size_t n = byte_chr(env + i, envlen - i, 0) ;
     76     if (i + n >= envlen) return 0 ;
     77     {
     78       size_t p = byte_chr(env + i, n, '=') ;
     79       char tmp[dirlen + p + 2] ;
     80       memcpy(tmp, dir, dirlen) ;
     81       tmp[dirlen] = '/' ;
     82       memcpy(tmp + dirlen + 1, env + i, p) ;
     83       tmp[dirlen + p + 1] = 0 ;
     84       if (p < n)
     85       {
     86         struct iovec v[2] = { { .iov_base = (char *)env + i + p + 1, .iov_len = n - p - 1 }, { .iov_base = "\n", .iov_len = 1 } } ;
     87         if (!openwritevnclose_unsafe(tmp, v, 2))
     88         {
     89           cleanup() ;
     90           strerr_diefu2sys(111, "openwritenclose_unsafe ", tmp) ;
     91         }
     92       }
     93       else touchtrunc(tmp) ;
     94     }
     95     i += n + 1 ;
     96   }
     97   return 1 ;
     98 }
     99 
    100 static int doit (char const *key, uint32_t klen, char const *data, uint32_t dlen)
    101 {
    102   uint16_t envlen, execlen ;
    103   char name[basedirlen + klen + 8] ;
    104   if (!dlen || (dlen > 8201)) return 0 ;
    105   memcpy(name, basedir, basedirlen) ;
    106   name[basedirlen] = '/' ;
    107   memcpy(name + basedirlen + 1, key, klen) ;
    108   name[basedirlen + 1 + klen] = 0 ;
    109   mkdirp(name) ;
    110   name[basedirlen + 1 + klen] = '/' ;
    111   if (data[0] == 'A')
    112   {
    113     memcpy(name + basedirlen + klen + 2, "allow", 6) ;
    114     touchtrunc(name) ;
    115   }
    116   else if (data[0] == 'D')
    117   {
    118     memcpy(name + basedirlen + klen + 2, "deny", 5) ;
    119     touchtrunc(name) ;
    120   }
    121   if (dlen < 3) return 1 ;
    122   uint16_unpack_big(data + 1, &envlen) ;
    123   if ((envlen > 4096U) || (3U + envlen > dlen)) return 0 ;
    124   uint16_unpack_big(data + 3 + envlen, &execlen) ;
    125   if ((execlen > 4096U) || (5U + envlen + execlen != dlen)) return 0 ;
    126   if (envlen)
    127   {
    128     memcpy(name + basedirlen + klen + 2, "env", 4) ;
    129     if (!doenv(name, basedirlen + klen + 5, data + 3, envlen)) return 0 ;
    130   }
    131   if (execlen)
    132   {
    133     memcpy(name + basedirlen + klen + 2, "exec", 5) ;
    134     if (!openwritenclose_unsafe(name, data + 5 + envlen, execlen))
    135     {
    136       cleanup() ;
    137       strerr_diefu2sys(111, "openwritenclose_unsafe ", name) ;
    138     }
    139   }
    140   return 1 ;
    141 }
    142 
    143 int main (int argc, char const *const *argv)
    144 {
    145   cdb c = CDB_ZERO ;
    146   uint32_t pos = CDB_TRAVERSE_INIT() ;
    147   PROG = "s6-accessrules-fs-from-cdb" ;
    148   if (argc < 3) strerr_dieusage(100, USAGE) ;
    149   if (!cdb_init(&c, argv[2])) strerr_diefu1sys(111, "cdb_init") ;
    150   basedir = argv[1] ;
    151   basedirlen = strlen(argv[1]) ;
    152   {
    153     mode_t m = umask(0) ;
    154     if (mkdir(basedir, S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH | S_ISGID) < 0)
    155       strerr_diefu2sys(111, "mkdir ", basedir) ;
    156     umask(m) ;
    157   }
    158   for (;;)
    159   {
    160     cdb_data key, data ;
    161     int r = cdb_traverse_next(&c, &key, &data, &pos) ;
    162     if (r < 0)
    163     {
    164       cleanup() ;
    165       strerr_diefu1x(111, "cdb_traverse_next: invalid cdb") ;
    166     }
    167     else if (!r) break ;
    168     else if (!doit(key.s, key.len, data.s, data.len))
    169     {
    170       cleanup() ;
    171       strerr_diefu3x(111, "handle cdb record: ", argv[2], " does not contain valid accessrules data") ;
    172     }
    173   }
    174   return 0 ;
    175 }