s6-svperms.c (6679B)
1 /* ISC license. */ 2 3 #include <string.h> 4 #include <unistd.h> 5 #include <errno.h> 6 #include <sys/stat.h> 7 #include <pwd.h> 8 #include <grp.h> 9 10 #include <skalibs/types.h> 11 #include <skalibs/sgetopt.h> 12 #include <skalibs/buffer.h> 13 #include <skalibs/strerr.h> 14 15 #include <s6/supervise.h> 16 17 #define USAGE "s6-svperms [ -v ] [ -u | -g group | -G group | -o | -O group ] [ -e | -E group ] servicedir..." 18 #define dieusage() strerr_dieusage(100, USAGE) 19 20 static gid_t scangid (char const *s) 21 { 22 if (s[0] == ':') 23 { 24 gid_t g ; 25 if (!gid0_scan(s+1, &g)) dieusage() ; 26 return g ; 27 } 28 else 29 { 30 struct group *gr ; 31 errno = 0 ; 32 gr = getgrnam(s) ; 33 if (!gr) 34 { 35 if (errno) strerr_diefu1sys(111, "getgrnam") ; 36 else strerr_diefu3x(100, "find entry for ", s, " in group database") ; 37 } 38 return gr->gr_gid ; 39 } 40 } 41 42 static char *gidname (gid_t gid) 43 { 44 struct group *gr ; 45 errno = 0 ; 46 gr = getgrgid(gid) ; 47 if (!gr) 48 { 49 static char fmt[GID_FMT] ; 50 fmt[gid_fmt(fmt, gid)] = 0 ; 51 if (errno) strerr_warnwu2sys("getgrgid ", fmt) ; 52 return fmt ; 53 } 54 return gr->gr_name ; 55 } 56 57 static void out (char const *s) 58 { 59 if (buffer_puts(buffer_1, s) < 0) 60 strerr_diefu1sys(111, "write to stdout") ; 61 } 62 63 static inline int printsupervise (char const *dir) 64 { 65 struct stat st ; 66 size_t len = strlen(dir) ; 67 char fn[len + sizeof(S6_SUPERVISE_CTLDIR) + 9] ; 68 memcpy(fn, dir, len) ; 69 memcpy(fn + len, "/" S6_SUPERVISE_CTLDIR, sizeof(S6_SUPERVISE_CTLDIR) + 1) ; 70 if (stat(fn, &st) < 0) 71 { 72 strerr_warnwu2sys("stat ", fn) ; 73 return 1 ; 74 } 75 if (!S_ISDIR(st.st_mode)) 76 { 77 strerr_warnw2x(fn, " is not a directory") ; 78 return 1 ; 79 } 80 if (st.st_mode & 05066 || (st.st_mode & 0700) != 0700 || ((st.st_mode & 0001) && !(st.st_mode & 0010))) 81 { 82 char fmt[UINT_OFMT] ; 83 fmt[uint_ofmt(fmt, st.st_mode & 07777)] = 0 ; 84 strerr_warnw3x(fn, " has incorrect permissions: ", fmt) ; 85 return 1 ; 86 } 87 out(dir) ; 88 out(" status: ") ; 89 if (st.st_mode & 0011) 90 { 91 if (st.st_mode & 0001) buffer_puts(buffer_1, "public") ; 92 else 93 { 94 out("group ") ; 95 out(gidname(st.st_gid)) ; 96 } 97 } 98 else out("owner") ; 99 out("\n") ; 100 memcpy(fn + len + sizeof(S6_SUPERVISE_CTLDIR), "/control", 9) ; 101 if (stat(fn, &st) < 0) 102 { 103 strerr_warnwu2sys("stat ", fn) ; 104 return 1 ; 105 } 106 if (!S_ISFIFO(st.st_mode)) 107 { 108 strerr_warnw2x(fn, " is not a named pipe") ; 109 return 1 ; 110 } 111 if (st.st_mode & 0157) 112 { 113 char fmt[UINT_OFMT] ; 114 fmt[uint_ofmt(fmt, st.st_mode & 07777)] = 0 ; 115 strerr_warnw3x(fn, " has incorrect permissions: ", fmt) ; 116 return 1 ; 117 } 118 out(dir) ; 119 out(" control: ") ; 120 if (st.st_mode & 0020) 121 { 122 out("group ") ; 123 out(gidname(st.st_gid)) ; 124 } 125 else out("owner") ; 126 out("\n") ; 127 return 0 ; 128 } 129 130 static inline int printevent (char const *dir) 131 { 132 struct stat st ; 133 size_t len = strlen(dir) ; 134 char fn[len + sizeof(S6_SUPERVISE_EVENTDIR) + 1] ; 135 memcpy(fn, dir, len) ; 136 memcpy(fn + len, "/" S6_SUPERVISE_EVENTDIR, sizeof(S6_SUPERVISE_EVENTDIR) + 1) ; 137 if (stat(fn, &st) < 0) 138 { 139 strerr_warnwu2sys("stat ", fn) ; 140 return 1 ; 141 } 142 if (!S_ISDIR(st.st_mode)) 143 { 144 strerr_warnw2x(fn, " is not a directory") ; 145 return 1 ; 146 } 147 if ((st.st_mode & 07777) != 01733 && (st.st_mode & 07777) != 03730) 148 { 149 char fmt[UINT_OFMT] ; 150 fmt[uint_ofmt(fmt, st.st_mode & 07777)] = 0 ; 151 strerr_warnw3x(fn, " has incorrect permissions: ", fmt) ; 152 return 1 ; 153 } 154 out(dir) ; 155 out(" events: ") ; 156 if ((st.st_mode & 07777) == 03730) 157 { 158 out("group ") ; 159 out(gidname(st.st_gid)) ; 160 } 161 else out("public") ; 162 out("\n") ; 163 return 0 ; 164 } 165 166 static gid_t primarygid (char const *fn) 167 { 168 struct passwd *pw ; 169 struct stat st ; 170 if (stat(fn, &st) < 0) strerr_diefu2sys(111, "stat ", fn) ; 171 errno = 0 ; 172 pw = getpwuid(st.st_uid) ; 173 if (!pw) 174 { 175 strerr_warnwu3sys("determine primary gid for the owner of ", fn, " (using root instead)") ; 176 return 0 ; 177 } 178 else return pw->pw_gid ; 179 } 180 181 static inline void modsupervise (char const *dir, unsigned int what, gid_t gid) 182 { 183 size_t len = strlen(dir) ; 184 gid_t cgid = 0 ; 185 mode_t mode = 0700 ; 186 char fn[len + sizeof(S6_SUPERVISE_CTLDIR) + 9] ; 187 memcpy(fn, dir, len) ; 188 memcpy(fn + len, "/" S6_SUPERVISE_CTLDIR, sizeof(S6_SUPERVISE_CTLDIR) + 1) ; 189 switch (what & 3) 190 { 191 case 0 : cgid = primarygid(fn) ; mode = 0700 ; break ; 192 case 1 : cgid = gid ; mode = 0710 ; break ; 193 case 2 : cgid = primarygid(fn) ; mode = 0711 ; break ; 194 } 195 if (chown(fn, -1, cgid) < 0) 196 strerr_diefu2sys(111, "chown ", fn) ; 197 if (chmod(fn, mode) < 0) 198 strerr_diefu2sys(111, "chmod ", fn) ; 199 memcpy(fn + len + sizeof(S6_SUPERVISE_CTLDIR), "/control", 9) ; 200 if (what & 4) mode = 0620 ; 201 else 202 { 203 gid = primarygid(fn) ; 204 mode = 0600 ; 205 } 206 if (chown(fn, -1, gid) < 0) 207 strerr_diefu2sys(111, "chown ", fn) ; 208 if (chmod(fn, mode) < 0) 209 strerr_diefu2sys(111, "chmod ", fn) ; 210 } 211 212 static inline void modevent (char const *dir, gid_t gid) 213 { 214 size_t len = strlen(dir) ; 215 mode_t mode ; 216 char fn[len + sizeof(S6_SUPERVISE_EVENTDIR) + 1] ; 217 memcpy(fn, dir, len) ; 218 memcpy(fn + len, "/" S6_SUPERVISE_EVENTDIR, sizeof(S6_SUPERVISE_EVENTDIR) + 1) ; 219 if (gid == (gid_t)-1) 220 { 221 gid = primarygid(fn) ; 222 mode = 01733 ; 223 } 224 else mode = 03730 ; 225 if (chown(fn, -1, gid) < 0) 226 strerr_diefu2sys(111, "chown ", fn) ; 227 if (chmod(fn, mode) < 0) 228 strerr_diefu2sys(111, "chmod ", fn) ; 229 } 230 231 int main (int argc, char const *const *argv) 232 { 233 int e = 0 ; 234 gid_t gid = -1 ; 235 gid_t eventgid = -1 ; 236 int rw = 0 ; 237 unsigned int what = 0 ; 238 PROG = "s6-svperms" ; 239 { 240 subgetopt l = SUBGETOPT_ZERO ; 241 for (;;) 242 { 243 int opt = subgetopt_r(argc, argv, "vug:G:oO:eE:", &l) ; 244 if (opt == -1) break ; 245 switch (opt) 246 { 247 case 'v' : rw |= 1 ; break ; 248 case 'u' : rw |= 2 ; what = 0 ; break ; 249 case 'g' : rw |= 2 ; what = 1 ; gid = scangid(l.arg) ; break ; 250 case 'G' : rw |= 2 ; what = 5 ; gid = scangid(l.arg) ; break ; 251 case 'o' : rw |= 2 ; what = 2 ; break ; 252 case 'O' : rw |= 2 ; what = 6 ; gid = scangid(l.arg) ; break ; 253 case 'e' : rw |= 4 ; eventgid = -1 ; break ; 254 case 'E' : rw |= 4 ; eventgid = scangid(l.arg) ; break ; 255 default : dieusage() ; 256 } 257 } 258 argc -= l.ind ; argv += l.ind ; 259 } 260 if (!argc) dieusage() ; 261 262 if (!rw) rw = 1 ; 263 for (; *argv ; argv++) 264 { 265 if (rw & 2) modsupervise(*argv, what, gid) ; 266 if (rw & 4) modevent(*argv, eventgid) ; 267 if (rw & 1) { e |= printsupervise(*argv) ; e |= printevent(*argv) ; } 268 } 269 if (rw & 1 && !buffer_flush(buffer_1)) 270 strerr_diefu1sys(111, "write to stdout") ; 271 return e ; 272 }