s6

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

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 }