summaryrefslogtreecommitdiff
path: root/src/server/clientrules.c
blob: 4050b2fa1d33d4b1f80f71046aeaecf8af698dc6 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
/* ISC license. */

#include <sys/types.h>
#include <stdint.h>

#include <skalibs/posixplz.h>
#include <skalibs/bytestr.h>
#include <skalibs/types.h>
#include <skalibs/env.h>
#include <skalibs/strerr2.h>
#include <skalibs/djbunix.h>
#include <skalibs/cdb.h>

#include <s6/accessrules.h>

#include "clientrules.h"

static unsigned int rulestype = 0 ;
static char const *rules = 0 ;
static int cdbfd = -1 ;
static struct cdb cdbmap = CDB_ZERO ;

void clientrules_init (unsigned int type, char const *s)
{
  rulestype = type ;
  rules = s ;
  if (rulestype == 2)
  {
    cdbfd = open_readb(rules) ;
    if (cdbfd < 0) strerr_diefu3sys(111, "open ", rules, " for reading") ;
    if (cdb_init(&cdbmap, cdbfd) < 0)
      strerr_diefu2sys(111, "cdb_init ", rules) ;
  }
}

void clientrules_reload ()
{
  int fd ;
  struct cdb c = CDB_ZERO ;
  if (rulestype != 2) break ;
  fd = open_readb(rules) ;
  if (fd < 0) break ;
  if (cdb_init(&c, fd) < 0)
  {
    fd_close(fd) ;
    break ;
  }
  cdb_free(&cdbmap) ;
  fd_close(cdbfd) ;
  cdbfd = fd ;
  cdbmap = c ;
}

static inline uint8_t parse_env (char const *const *envp)
{
  uint8_t perms = 0 ;
  for (; *envp ; envp++)
  {
    if (str_start(*envp, "query=")) perms |= 1 ;
    if (str_start(*envp, "monitor=")) perms |= 2 ;
    if (str_start(*envp, "change=")) perms |= 4 ;
    if (str_start(*envp, "event=")) perms |= 8 ;
    if (str_start(*envp, "admin=")) perms |= 16 ;
  }
  return perms ;
}

int clientrules_check (int fd, uint8_t *perms)
{
  s6_accessrules_params_t params = S6_ACCESSRULES_PARAMS_ZERO ;
  s6_accessrules_result_t result = S6_ACCESSRULES_ERROR ;
  uid_t uid ;
  gid_t gid ;

  if (getpeereid(fd, &uid, &gid) < 0)
  {
    if (verbosity) strerr_warnwu1sys("getpeereid") ;
    return 0 ;
  }

  switch (rulestype)
  {
    case 1 :
      result = s6_accessrules_uidgid_fs(uid, gid, rules, &params) ; break ;
    case 2 :
      result = s6_accessrules_uidgid_cdb(uid, gid, &cdbmap, &params) ; break ;
    default : break ;
  }
  if (result != S6_ACCESSRULES_ALLOW)
  {
    if (verbosity && (result == S6_ACCESSRULES_ERROR))
       strerr_warnw1sys("error while checking rules") ;
    return 0 ;
  }
  if (params.exec.len && verbosity)
  {
    char fmtuid[UID_FMT] ;
    char fmtgid[GID_FMT] ;
    fmtuid[uid_fmt(fmtuid, uid)] = 0 ;
    fmtgid[gid_fmt(fmtgid, gid)] = 0 ;
    strerr_warnw4x("unused exec string in rules for uid ", fmtuid, " gid ", fmtgid) ;
  }
  if (params.env.s)
  {
    size_t n = byte_count(params.env.s, params.env.len, '\0') ;
    char const *envp[n+1] ;
    if (!env_make(envp, n, params.env.s, params.env.len))
    {
      if (verbosity) strerr_warnwu1sys("env_make") ;
      s6_accessrules_params_free(&params) ;
      return 0 ;
    }
    envp[n] = 0 ;
    *perms = parse_env(envp, perms) ;
  }
  s6_accessrules_params_free(&params) ;
  return !!perms ;
}