s6

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

s6-ipcserver-access.c (6031B)


      1 /* ISC license. */
      2 
      3 #include <string.h>
      4 #include <unistd.h>
      5 #include <errno.h>
      6 #include <stdlib.h>
      7 
      8 #include <skalibs/gccattributes.h>
      9 #include <skalibs/types.h>
     10 #include <skalibs/strerr.h>
     11 #include <skalibs/sgetopt.h>
     12 #include <skalibs/cdb.h>
     13 #include <skalibs/djbunix.h>
     14 #include <skalibs/socket.h>
     15 #include <skalibs/exec.h>
     16 
     17 #include <s6/config.h>
     18 #include <s6/accessrules.h>
     19 
     20 #ifdef S6_USE_EXECLINE
     21 #include <execline/config.h>
     22 #endif
     23 
     24 #define USAGE "s6-ipcserver-access [ -v verbosity ] [ -e | -E ] [ -l localname ] [ -i rulesdir | -x rulesfile ] prog..."
     25 
     26 static unsigned int verbosity = 1 ;
     27 
     28  /* Utility functions */
     29 
     30 static inline void dieusage (void) gccattr_noreturn ;
     31 static inline void dieusage ()
     32 {
     33   strerr_dieusage(100, USAGE) ;
     34 }
     35 
     36 static inline void dienomem (void) gccattr_noreturn ;
     37 static inline void dienomem ()
     38 {
     39   strerr_diefu1sys(111, "update environment") ;
     40 }
     41 
     42 static inline void X (void) gccattr_noreturn ;
     43 static inline void X ()
     44 {
     45   strerr_dief1x(101, "internal inconsistency. Please submit a bug-report.") ;
     46 }
     47 
     48 
     49  /* Logging */
     50 
     51 static void logit (pid_t pid, uid_t uid, gid_t gid, int h)
     52 {
     53   char fmtpid[PID_FMT] ;
     54   char fmtuid[UID_FMT] ;
     55   char fmtgid[GID_FMT] ;
     56   fmtpid[pid_fmt(fmtpid, pid)] = 0 ;
     57   fmtuid[uid_fmt(fmtuid, uid)] = 0 ;
     58   fmtgid[gid_fmt(fmtgid, gid)] = 0 ;
     59   if (h) strerr_warni7x("allow", " pid ", fmtpid, " uid ", fmtuid, " gid ", fmtgid) ;
     60   else strerr_warni7sys("deny", " pid ", fmtpid, " uid ", fmtuid, " gid ", fmtgid) ;
     61 }
     62 
     63 static inline void log_accept (pid_t pid, uid_t uid, gid_t gid)
     64 {
     65   logit(pid, uid, gid, 1) ;
     66 }
     67 
     68 static inline void log_deny (pid_t pid, uid_t uid, gid_t gid)
     69 {
     70   logit(pid, uid, gid, 0) ;
     71 }
     72 
     73 
     74  /* Checking */
     75 
     76 static s6_accessrules_result_t check_cdb (uid_t uid, gid_t gid, char const *file, s6_accessrules_params_t *params)
     77 {
     78   cdb c = CDB_ZERO ;
     79   s6_accessrules_result_t r ;
     80   if (!cdb_init(&c, file)) strerr_diefu2sys(111, "cdb_init ", file) ;
     81   r = s6_accessrules_uidgid_cdb(uid, gid, &c, params) ;
     82   cdb_free(&c) ;
     83   return r ;
     84 }
     85 
     86 static inline int check (s6_accessrules_params_t *params, char const *rules, unsigned int rulestype, uid_t uid, gid_t gid)
     87 {
     88   char const *x = "" ;
     89   s6_accessrules_result_t r ;
     90   switch (rulestype)
     91   {
     92     case 0 :
     93       if (verbosity >= 2) strerr_warnw1x("invoked without a ruleset!") ;
     94       return 1 ;
     95     case 1 :
     96       r = s6_accessrules_uidgid_fs(uid, gid, rules, params) ;
     97       x = "fs" ;
     98       break ;
     99     case 2 :
    100       r = check_cdb(uid, gid, rules, params) ;
    101       x = "cdb" ;
    102       break ;
    103     default : X() ;
    104   }
    105   switch (r)
    106   {
    107     case S6_ACCESSRULES_ERROR : strerr_diefu4sys(111, "check ", x, " ruleset in ", rules) ;
    108     case S6_ACCESSRULES_ALLOW :    return 1 ;
    109     case S6_ACCESSRULES_DENY :     return (errno = EACCES, 0) ;
    110     case S6_ACCESSRULES_NOTFOUND : return (errno = ENOENT, 0) ;
    111     default : X() ;
    112   }
    113 }
    114 
    115 int main (int argc, char const *const *argv)
    116 {
    117   s6_accessrules_params_t params = S6_ACCESSRULES_PARAMS_ZERO ;
    118   char const *rules = 0 ;
    119   char const *localname = 0 ;
    120   char const *proto ;
    121   size_t protolen ;
    122   uid_t uid = 0 ;
    123   gid_t gid = 0 ;
    124   unsigned int rulestype = 0 ;
    125   int doenv = 1 ;
    126   PROG = "s6-ipcserver-access" ;
    127   {
    128     subgetopt l = SUBGETOPT_ZERO ;
    129     for (;;)
    130     {
    131       int opt = subgetopt_r(argc, argv, "v:Eel:i:x:", &l) ;
    132       if (opt == -1) break ;
    133       switch (opt)
    134       {
    135         case 'v' : if (!uint0_scan(l.arg, &verbosity)) dieusage() ; break ;
    136         case 'E' : doenv = 0 ; break ;
    137         case 'e' : doenv = 1 ; break ;
    138         case 'l' : localname = l.arg ; break ;
    139         case 'i' : rules = l.arg ; rulestype = 1 ; break ;
    140         case 'x' : rules = l.arg ; rulestype = 2 ; break ;
    141         default : dieusage() ;
    142       }
    143     }
    144     argc -= l.ind ; argv += l.ind ;
    145   }
    146   if (!argc) dieusage() ;
    147   if (!*argv[0]) dieusage() ;
    148 
    149   proto = getenv("PROTO") ;
    150   if (!proto) strerr_dienotset(100, "PROTO") ;
    151   protolen = strlen(proto) ;
    152 
    153   {
    154     char const *x ;
    155     char tmp[protolen + 11] ;
    156     memcpy(tmp, proto, protolen) ;
    157     memcpy(tmp + protolen, "REMOTEEUID", 11) ;
    158     x = getenv(tmp) ;
    159     if (!x) strerr_dienotset(100, tmp) ;
    160     if (!uid0_scan(x, &uid)) strerr_dieinvalid(100, tmp) ;
    161     tmp[protolen + 7] = 'G' ;
    162     x = getenv(tmp) ;
    163     if (!x) strerr_dienotset(100, tmp) ;
    164     if (!gid0_scan(x, &gid)) strerr_dieinvalid(100, tmp) ;
    165   }
    166 
    167   if (check(&params, rules, rulestype, uid, gid)) goto accepted ;
    168 
    169   if (verbosity >= 2) log_deny(getpid(), uid, gid) ;
    170   return 1 ;
    171 
    172  accepted:
    173   if (verbosity) log_accept(getpid(), uid, gid) ;
    174 
    175   if (doenv)
    176   {
    177     char tmp[protolen + 10] ;
    178     memcpy(tmp, proto, protolen) ;
    179     memcpy(tmp + protolen, "LOCALPATH", 10) ;
    180     if (localname)
    181     {
    182       if (!env_addmodif(&params.env, tmp, localname)) dienomem() ;
    183     }
    184     else
    185     {
    186       char curname[IPCPATH_MAX+1] ;
    187       int dummy ;
    188       if (ipc_local(0, curname, IPCPATH_MAX+1, &dummy) < 0)
    189         strerr_diefu1sys(111, "ipc_local") ;
    190       if (!env_addmodif(&params.env, tmp, curname)) dienomem() ;
    191     }
    192   }
    193   else
    194   {
    195     char tmp[protolen + 11] ;
    196     memcpy(tmp, proto, protolen) ;
    197     memcpy(tmp + protolen, "REMOTEEUID", 11) ;
    198     if (!env_addmodif(&params.env, "PROTO", 0)) dienomem() ;
    199     if (!env_addmodif(&params.env, tmp, 0)) dienomem() ;
    200     tmp[protolen + 7] = 'G' ;
    201     if (!env_addmodif(&params.env, tmp, 0)) dienomem() ;
    202     memcpy(tmp + protolen + 6, "PATH", 5) ;
    203     if (!env_addmodif(&params.env, tmp, 0)) dienomem() ;
    204     memcpy(tmp + protolen, "LOCALPATH", 10) ;
    205     if (!env_addmodif(&params.env, tmp, 0)) dienomem() ;
    206     memcpy(tmp + protolen, "CONNNUM", 8) ;
    207     if (!env_addmodif(&params.env, tmp, 0)) dienomem() ;
    208   }
    209 
    210   if (params.exec.len)
    211 #ifdef S6_USE_EXECLINE
    212   {
    213     char *specialargv[4] = { EXECLINE_EXTBINPREFIX "execlineb", "-Pc", params.exec.s, 0 } ;
    214     xmexec_m((char const *const *)specialargv, params.env.s, params.env.len) ;
    215   }
    216 #else
    217   strerr_warnw1x("exec file found but ignored because s6 was compiled without execline support!") ;
    218 #endif
    219   xmexec_m(argv, params.env.s, params.env.len) ;
    220 }