s6-accessrules-cdb-from-fs.c (4646B)
1 /* ISC license. */ 2 3 #include <stdint.h> 4 #include <unistd.h> 5 #include <errno.h> 6 #include <stdlib.h> 7 #include <stdio.h> 8 9 #include <skalibs/posixplz.h> 10 #include <skalibs/types.h> 11 #include <skalibs/cdbmake.h> 12 #include <skalibs/strerr.h> 13 #include <skalibs/stralloc.h> 14 #include <skalibs/env.h> 15 #include <skalibs/direntry.h> 16 #include <skalibs/djbunix.h> 17 #include <skalibs/skamisc.h> 18 19 #define USAGE "s6-accessrules-cdb-from-fs cdbfile dir" 20 #define SUFFIX ":s6-accessrules-cdb-from-fs:XXXXXX" 21 22 static stralloc tmp = STRALLOC_ZERO ; 23 24 static void cleanup (void) 25 { 26 unlink_void(tmp.s) ; 27 } 28 29 static void dienomem (void) 30 { 31 cleanup() ; 32 strerr_diefu1sys(111, "stralloc_catb") ; 33 } 34 35 static void doit (cdbmaker *c, stralloc *sa, size_t start) 36 { 37 size_t tmpbase = tmp.len ; 38 unsigned int k = sa->len ; 39 if (!stralloc_readyplus(sa, 10)) dienomem() ; 40 stralloc_catb(sa, "/allow", 7) ; 41 tmp.s[tmpbase] = 0 ; 42 if (access(sa->s, F_OK) < 0) 43 { 44 if ((errno != ENOENT) && (errno != EACCES)) 45 { 46 cleanup() ; 47 strerr_diefu2sys(111, "access ", sa->s) ; 48 } 49 sa->len = k+1 ; 50 stralloc_catb(sa, "deny", 5) ; 51 if (access(sa->s, F_OK) < 0) 52 if ((errno != ENOENT) && (errno != EACCES)) 53 { 54 cleanup() ; 55 strerr_diefu2sys(111, "access ", sa->s) ; 56 } 57 else return ; 58 else if (!cdbmake_add(c, sa->s + start, k - start, "D", 1)) 59 { 60 cleanup() ; 61 strerr_diefu1sys(111, "cdbmake_add") ; 62 } 63 } 64 else 65 { 66 uint16_t envlen = 0 ; 67 uint16_t execlen = 0 ; 68 ssize_t r ; 69 tmp.s[tmpbase] = 'A' ; 70 sa->len = k+1 ; 71 stralloc_catb(sa, "env", 4) ; 72 tmp.len = tmpbase + 3 ; 73 if ((envdir(sa->s, &tmp) < 0) && (errno != ENOENT)) 74 { 75 cleanup() ; 76 strerr_diefu2sys(111, "envdir ", sa->s) ; 77 } 78 if (tmp.len > tmpbase + 4103) 79 { 80 cleanup() ; 81 strerr_dief2sys(100, sa->s, " too big") ; 82 } 83 envlen = tmp.len - tmpbase - 3 ; 84 tmp.len = tmpbase ; 85 uint16_pack_big(tmp.s + tmpbase + 1, envlen) ; 86 sa->len = k+1 ; 87 stralloc_catb(sa, "exec", 5) ; 88 r = openreadnclose(sa->s, tmp.s + tmpbase + 5 + envlen, 4096) ; 89 if ((r == -1) && (errno != ENOENT)) 90 { 91 cleanup() ; 92 strerr_diefu2sys(111, "openreadnclose ", sa->s) ; 93 } 94 if (r > 0) execlen = r ; 95 if (execlen == 4096) strerr_warnw2x("possibly truncated file ", sa->s) ; 96 uint16_pack_big(tmp.s + tmpbase + 3 + envlen, execlen) ; 97 if (!cdbmake_add(c, sa->s + start, k - start, tmp.s + tmpbase, 5 + envlen + execlen)) 98 { 99 cleanup() ; 100 strerr_diefu1sys(111, "cdbmake_add") ; 101 } 102 } 103 } 104 105 int main (int argc, char const *const *argv) 106 { 107 stralloc sa = STRALLOC_ZERO ; 108 cdbmaker c = CDBMAKER_ZERO ; 109 DIR *dir ; 110 size_t start ; 111 int fd ; 112 PROG = "s6-accessrules-cdb-from-fs" ; 113 if (argc < 3) strerr_dieusage(100, USAGE) ; 114 if (!stralloc_cats(&tmp, argv[1])) return 0 ; 115 if (!stralloc_readyplus(&tmp, 8210)) 116 strerr_diefu1sys(111, "stralloc_catb") ; 117 stralloc_catb(&tmp, SUFFIX, sizeof(SUFFIX)) ; 118 fd = mkstemp(tmp.s) ; 119 if (fd < 0) strerr_diefu2sys(111, "mkstemp ", tmp.s) ; 120 if (!cdbmake_start(&c, fd)) 121 { 122 cleanup() ; 123 strerr_diefu1sys(111, "cdbmake_start") ; 124 } 125 dir = opendir(argv[2]) ; 126 if (!dir) 127 { 128 cleanup() ; 129 strerr_diefu2sys(111, "opendir ", argv[2]) ; 130 } 131 if (!stralloc_cats(&sa, argv[2]) || !stralloc_catb(&sa, "/", 1)) dienomem() ; 132 start = sa.len ; 133 134 for (;;) 135 { 136 DIR *subdir ; 137 direntry *d ; 138 size_t base ; 139 errno = 0 ; 140 d = readdir(dir) ; 141 if (!d) break ; 142 if (d->d_name[0] == '.') continue ; 143 sa.len = start ; 144 if (!stralloc_cats(&sa, d->d_name) || !stralloc_0(&sa)) dienomem() ; 145 base = sa.len ; 146 subdir = opendir(sa.s) ; 147 if (!subdir) 148 { 149 cleanup() ; 150 strerr_diefu2sys(111, "opendir ", sa.s) ; 151 } 152 sa.s[base-1] = '/' ; 153 for (;;) 154 { 155 errno = 0 ; 156 d = readdir(subdir) ; 157 if (!d) break ; 158 if (d->d_name[0] == '.') continue ; 159 sa.len = base ; 160 if (!stralloc_cats(&sa, d->d_name)) dienomem() ; 161 doit(&c, &sa, start) ; 162 } 163 if (errno) 164 { 165 sa.s[base-1] = 0 ; 166 cleanup() ; 167 strerr_diefu2sys(111, "readdir ", sa.s) ; 168 } 169 dir_close(subdir) ; 170 } 171 if (errno) 172 { 173 cleanup() ; 174 strerr_diefu2sys(111, "readdir ", argv[2]) ; 175 } 176 dir_close(dir) ; 177 if (!cdbmake_finish(&c)) 178 { 179 cleanup() ; 180 strerr_diefu1sys(111, "cdb_make_finish") ; 181 } 182 if (fd_sync(fd) < 0) 183 { 184 cleanup() ; 185 strerr_diefu1sys(111, "fd_sync") ; 186 } 187 fd_close(fd) ; 188 if (rename(tmp.s, argv[1]) < 0) 189 { 190 cleanup() ; 191 strerr_diefu4sys(111, "rename ", tmp.s, " to ", argv[1]) ; 192 } 193 return 0 ; 194 }