/* ISC license. */ #include #include #include #include #include #include #include #include #include #include #include #define USAGE "s6-svperms [ -v ] [ -u | -g group | -G group | -o | -O group ] [ -e | -E group ] servicedir..." #define dieusage() strerr_dieusage(100, USAGE) static gid_t scangid (char const *s) { if (s[0] == ':') { gid_t g ; if (!gid0_scan(s+1, &g)) dieusage() ; return g ; } else { struct group *gr ; errno = 0 ; gr = getgrnam(s) ; if (!gr) { if (errno) strerr_diefu1sys(111, "getgrnam") ; else strerr_diefu3x(100, "find entry for ", s, " in group database") ; } return gr->gr_gid ; } } static char *gidname (gid_t gid) { struct group *gr ; errno = 0 ; gr = getgrgid(gid) ; if (!gr) { static char fmt[GID_FMT] ; fmt[gid_fmt(fmt, gid)] = 0 ; if (errno) strerr_warnwu2sys("getgrgid ", fmt) ; return fmt ; } return gr->gr_name ; } static void out (char const *s) { if (buffer_puts(buffer_1, s) < 0) strerr_diefu1sys(111, "write to stdout") ; } static inline int printsupervise (char const *dir) { struct stat st ; size_t len = strlen(dir) ; char fn[len + sizeof(S6_SUPERVISE_CTLDIR) + 9] ; memcpy(fn, dir, len) ; memcpy(fn + len, "/" S6_SUPERVISE_CTLDIR, sizeof(S6_SUPERVISE_CTLDIR) + 1) ; if (stat(fn, &st) < 0) { strerr_warnwu2sys("stat ", fn) ; return 1 ; } if (!S_ISDIR(st.st_mode)) { strerr_warnw2x(fn, " is not a directory") ; return 1 ; } if (st.st_mode & 05066 || (st.st_mode & 0700) != 0700 || ((st.st_mode & 0001) && !(st.st_mode & 0010))) { char fmt[UINT_OFMT] ; fmt[uint_ofmt(fmt, st.st_mode & 07777)] = 0 ; strerr_warnw3x(fn, " has incorrect permissions: ", fmt) ; return 1 ; } out(dir) ; out(" status: ") ; if (st.st_mode & 0011) { if (st.st_mode & 0001) buffer_puts(buffer_1, "public") ; else { out("group ") ; out(gidname(st.st_gid)) ; } } else out("owner") ; out("\n") ; memcpy(fn + len + sizeof(S6_SUPERVISE_CTLDIR), "/control", 9) ; if (stat(fn, &st) < 0) { strerr_warnwu2sys("stat ", fn) ; return 1 ; } if (!S_ISFIFO(st.st_mode)) { strerr_warnw2x(fn, " is not a named pipe") ; return 1 ; } if (st.st_mode & 0157) { char fmt[UINT_OFMT] ; fmt[uint_ofmt(fmt, st.st_mode & 07777)] = 0 ; strerr_warnw3x(fn, " has incorrect permissions: ", fmt) ; return 1 ; } out(dir) ; out(" control: ") ; if (st.st_mode & 0020) { out("group ") ; out(gidname(st.st_gid)) ; } else out("owner") ; out("\n") ; return 0 ; } static inline int printevent (char const *dir) { struct stat st ; size_t len = strlen(dir) ; char fn[len + sizeof(S6_SUPERVISE_EVENTDIR) + 1] ; memcpy(fn, dir, len) ; memcpy(fn + len, "/" S6_SUPERVISE_EVENTDIR, sizeof(S6_SUPERVISE_EVENTDIR) + 1) ; if (stat(fn, &st) < 0) { strerr_warnwu2sys("stat ", fn) ; return 1 ; } if (!S_ISDIR(st.st_mode)) { strerr_warnw2x(fn, " is not a directory") ; return 1 ; } if ((st.st_mode & 07777) != 01733 && (st.st_mode & 07777) != 03730) { char fmt[UINT_OFMT] ; fmt[uint_ofmt(fmt, st.st_mode & 07777)] = 0 ; strerr_warnw3x(fn, " has incorrect permissions: ", fmt) ; return 1 ; } out(dir) ; out(" events: ") ; if ((st.st_mode & 07777) == 03730) { out("group ") ; out(gidname(st.st_gid)) ; } else out("public") ; out("\n") ; return 0 ; } static gid_t primarygid (char const *fn) { struct passwd *pw ; struct stat st ; if (stat(fn, &st) < 0) strerr_diefu2sys(111, "stat ", fn) ; errno = 0 ; pw = getpwuid(st.st_uid) ; if (!pw) { strerr_warnwu3sys("determine primary gid for the owner of ", fn, " (using root instead)") ; return 0 ; } else return pw->pw_gid ; } static inline void modsupervise (char const *dir, unsigned int what, gid_t gid) { size_t len = strlen(dir) ; gid_t cgid = 0 ; mode_t mode = 0700 ; char fn[len + sizeof(S6_SUPERVISE_CTLDIR) + 9] ; memcpy(fn, dir, len) ; memcpy(fn + len, "/" S6_SUPERVISE_CTLDIR, sizeof(S6_SUPERVISE_CTLDIR) + 1) ; switch (what & 3) { case 0 : cgid = primarygid(fn) ; mode = 0700 ; break ; case 1 : cgid = gid ; mode = 0710 ; break ; case 2 : cgid = primarygid(fn) ; mode = 0711 ; break ; } if (chown(fn, -1, cgid) < 0) strerr_diefu2sys(111, "chown ", fn) ; if (chmod(fn, mode) < 0) strerr_diefu2sys(111, "chmod ", fn) ; memcpy(fn + len + sizeof(S6_SUPERVISE_CTLDIR), "/control", 9) ; if (what & 4) mode = 0620 ; else { gid = primarygid(fn) ; mode = 0600 ; } if (chown(fn, -1, gid) < 0) strerr_diefu2sys(111, "chown ", fn) ; if (chmod(fn, mode) < 0) strerr_diefu2sys(111, "chmod ", fn) ; } static inline void modevent (char const *dir, gid_t gid) { size_t len = strlen(dir) ; mode_t mode ; char fn[len + sizeof(S6_SUPERVISE_EVENTDIR) + 1] ; memcpy(fn, dir, len) ; memcpy(fn + len, "/" S6_SUPERVISE_EVENTDIR, sizeof(S6_SUPERVISE_EVENTDIR) + 1) ; if (gid == (gid_t)-1) { gid = primarygid(fn) ; mode = 01733 ; } else mode = 03730 ; if (chown(fn, -1, gid) < 0) strerr_diefu2sys(111, "chown ", fn) ; if (chmod(fn, mode) < 0) strerr_diefu2sys(111, "chmod ", fn) ; } int main (int argc, char const *const *argv) { int e = 0 ; gid_t gid = -1 ; gid_t eventgid = -1 ; int rw = 0 ; unsigned int what = 0 ; PROG = "s6-svperms" ; { subgetopt l = SUBGETOPT_ZERO ; for (;;) { int opt = subgetopt_r(argc, argv, "vug:G:oO:eE:", &l) ; if (opt == -1) break ; switch (opt) { case 'v' : rw |= 1 ; break ; case 'u' : rw |= 2 ; what = 0 ; break ; case 'g' : rw |= 2 ; what = 1 ; gid = scangid(l.arg) ; break ; case 'G' : rw |= 2 ; what = 5 ; gid = scangid(l.arg) ; break ; case 'o' : rw |= 2 ; what = 2 ; break ; case 'O' : rw |= 2 ; what = 6 ; gid = scangid(l.arg) ; break ; case 'e' : rw |= 4 ; eventgid = -1 ; break ; case 'E' : rw |= 4 ; eventgid = scangid(l.arg) ; break ; default : dieusage() ; } } argc -= l.ind ; argv += l.ind ; } if (!argc) dieusage() ; if (!rw) rw = 1 ; for (; *argv ; argv++) { if (rw & 2) modsupervise(*argv, what, gid) ; if (rw & 4) modevent(*argv, eventgid) ; if (rw & 1) { e |= printsupervise(*argv) ; e |= printevent(*argv) ; } } if (rw & 1 && !buffer_flush(buffer_1)) strerr_diefu1sys(111, "write to stdout") ; return e ; }