Ticket #8195: captest.c

File captest.c, 2.6 KB (added by nickm, 19 months ago)
Line 
1#include <stdio.h>
2#include <stdlib.h>
3#include <unistd.h>
4#include <string.h>
5#include <errno.h>
6
7#include <sys/socket.h>
8#include <netinet/in.h>
9#include <arpa/inet.h>
10
11#include <sys/capability.h>
12#include <sys/prctl.h>
13
14/* This part gets called before the setuid stuff */
15int
16keep_cap_net_bind_service(void)
17{
18  cap_user_header_t hdr;
19  cap_user_data_t data;
20
21  hdr = malloc(sizeof *hdr);
22  data = malloc(sizeof *hdr);
23
24  /* Get the capabilities or bail out */
25  hdr->version = _LINUX_CAPABILITY_VERSION;
26  hdr->pid = 0;
27  if (capget(hdr, data)) {
28    printf("Error getting capabilities: %s", strerror(errno));
29    return -1;
30  }
31
32  /* Set the capabilities or bail out */
33  data->permitted &= CAP_TO_MASK(CAP_NET_BIND_SERVICE)|CAP_TO_MASK(CAP_SETUID)|CAP_TO_MASK(CAP_SETGID);
34  data->effective = data->permitted;
35  data->inheritable = 0;
36  if (capset(hdr, data)) {
37    printf("Error setting capabilities: %s", strerror(errno));
38    return -1;
39  }
40
41  /* Keep the capabilities or bail out */
42  if (prctl(PR_SET_KEEPCAPS, 1)) {
43    printf("Error keeping capabilities: %s", strerror(errno));
44    return -1;
45  }
46
47  return 0;
48}
49
50/* this part happens after the setuid: we need to drop setuid, and add the
51   BIND_SERVICE capability back to the active set. */
52int
53post_setuid_capmagic(void)
54{
55  cap_user_header_t hdr;
56  cap_user_data_t data;
57
58  hdr = malloc(sizeof *hdr);
59  data = malloc(sizeof *hdr);
60
61  /* Get the capabilities or bail out */
62  hdr->version = _LINUX_CAPABILITY_VERSION;
63  hdr->pid = 0;
64  if (capget(hdr, data)) {
65    printf("2: Error getting capabilities: %s", strerror(errno));
66    return -1;
67  }
68
69  /* Set the capabilities or bail out */
70  data->permitted &= CAP_TO_MASK(CAP_NET_BIND_SERVICE);
71  data->effective = data->permitted;
72  data->inheritable = 0;
73  if (capset(hdr, data)) {
74    printf("2: Error setting capabilities: %s", strerror(errno));
75    return -1;
76  }
77
78  /* If we setuid again, don't retain capabilities. */
79  if (prctl(PR_SET_KEEPCAPS, 0)) {
80    printf("2: Error unkeeping capabilities: %s", strerror(errno));
81    return -1;
82  }
83
84  return 0;
85}
86
87
88int main(int argc, char **argv)
89{
90
91  int s;
92  struct sockaddr_in sin;
93
94  memset(&sin, 0, sizeof(sin));
95  sin.sin_family = AF_INET;
96  sin.sin_addr.s_addr = htonl(0x7f000001);
97  sin.sin_port = htons(100);
98
99  if (keep_cap_net_bind_service() < 0) {
100    return 1;
101  }
102
103  /* Your UID may vary */
104  if (setuid(1000)) {
105    perror("setuid");  return 1;
106  }
107
108  if (post_setuid_capmagic() < 0) {
109    return 1;
110  }
111
112  s = socket(AF_INET, SOCK_STREAM, 0);
113  if (s<0) { perror("socket"); return -1; }
114
115  if (bind(s, (void*)&sin, sizeof(sin)) < 0) {
116    perror("bind"); return -1;
117  }
118
119  puts("OK");
120  return 0;
121}