Statistics
| Branch: | Revision:

iof-bird-daemon / sysdep / linux / syspriv.h @ 48e5f32d

History | View | Annotate | Download (1.71 KB)

1

    
2
#include <sys/prctl.h>
3
#include <linux/capability.h>
4

    
5
#ifndef _LINUX_CAPABILITY_VERSION_3
6
#define _LINUX_CAPABILITY_VERSION_3  0x20080522
7
#define _LINUX_CAPABILITY_U32S_3     2
8
#endif
9

    
10
/* CAP_TO_MASK is missing in CentOS header files */
11
#ifndef CAP_TO_MASK
12
#define CAP_TO_MASK(x)      (1 << ((x) & 31))
13
#endif
14

    
15
/* capset() prototype is missing ... */
16
int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
17

    
18
static inline int
19
set_capabilities(u32 caps)
20
{
21
  struct __user_cap_header_struct cap_hdr;
22
  struct __user_cap_data_struct cap_dat[_LINUX_CAPABILITY_U32S_3];
23
  int err;
24

    
25
  cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
26
  cap_hdr.pid = 0;
27

    
28
  memset(cap_dat, 0, sizeof(cap_dat));
29
  cap_dat[0].effective = cap_dat[0].permitted = caps;
30

    
31
  err = capset(&cap_hdr, cap_dat);
32
  if (!err)
33
    return 0;
34

    
35
  /* Kernel may support do not support our version of capability interface.
36
       The last call returned supported version so we just retry it. */
37
  if (errno == EINVAL)
38
  {
39
    err = capset(&cap_hdr, cap_dat);
40
    if (!err)
41
      return 0;
42
  }
43

    
44
  return -1;
45
}
46

    
47
static void
48
drop_uid(uid_t uid)
49
{
50
  u32 caps =
51
    CAP_TO_MASK(CAP_NET_BIND_SERVICE) |
52
    CAP_TO_MASK(CAP_NET_BROADCAST) |
53
    CAP_TO_MASK(CAP_NET_ADMIN) |
54
    CAP_TO_MASK(CAP_NET_RAW);
55

    
56
  /* change effective user ID to be able to switch to that
57
     user ID completely after dropping CAP_SETUID */
58
  if (seteuid(uid) < 0)
59
    die("seteuid: %m");
60

    
61
  /* restrict the capabilities */
62
  if (set_capabilities(caps) < 0)
63
    die("capset: %m");
64

    
65
  /* keep the capabilities after dropping root ID */
66
  if (prctl(PR_SET_KEEPCAPS, 1) < 0)
67
    die("prctl: %m");
68

    
69
  /* completely switch to the unprivileged user ID */
70
  if (setresuid(uid, uid, uid) < 0)
71
    die("setresuid: %m");
72
}