]>
Commit | Line | Data |
---|---|---|
4b292b55 | 1 | /* -*- mode: c; c-file-style: "openbsd" -*- */ |
b5562b23 VB |
2 | /* |
3 | * Copyright (c) 2008 Vincent Bernat <bernat@luffy.cx> | |
4 | * | |
51434125 | 5 | * Permission to use, copy, modify, and/or distribute this software for any |
b5562b23 VB |
6 | * purpose with or without fee is hereby granted, provided that the above |
7 | * copyright notice and this permission notice appear in all copies. | |
8 | * | |
9 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
10 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
11 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
12 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
13 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
14 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
15 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
16 | */ | |
17 | ||
18 | /* This file contains code for privilege separation. When an error arises in | |
19 | * monitor (which is running as root), it just stops instead of trying to | |
20 | * recover. This module also contains proxies to privileged operations. In this | |
21 | * case, error can be non fatal. */ | |
22 | ||
23 | #include "lldpd.h" | |
24 | ||
25 | #include <stdio.h> | |
26 | #include <unistd.h> | |
27 | #include <errno.h> | |
b5562b23 VB |
28 | #include <sys/wait.h> |
29 | #include <sys/stat.h> | |
d72a05d4 VB |
30 | #include <sys/socket.h> |
31 | #include <sys/un.h> | |
29e043b5 | 32 | #include <regex.h> |
b5562b23 | 33 | #include <fcntl.h> |
b5562b23 VB |
34 | #include <grp.h> |
35 | #include <sys/utsname.h> | |
4afe659e | 36 | #include <sys/ioctl.h> |
b5562b23 | 37 | #include <netdb.h> |
e12c2365 VB |
38 | #include <netpacket/packet.h> |
39 | #include <net/ethernet.h> | |
d38eae28 VB |
40 | |
41 | /* Use resolv.h */ | |
42 | #ifdef HAVE_SYS_TYPES_H | |
43 | # include <sys/types.h> | |
44 | #endif | |
45 | #ifdef HAVE_NETINET_IN_H | |
46 | # include <netinet/in.h> | |
47 | #endif | |
48 | #ifdef HAVE_ARPA_NAMESER_H | |
49 | # include <arpa/nameser.h> /* DNS HEADER struct */ | |
50 | #endif | |
51 | #ifdef HAVE_NETDB_H | |
52 | # include <netdb.h> | |
53 | #endif | |
c933faf6 | 54 | #include <resolv.h> |
4afe659e VB |
55 | |
56 | enum { | |
d72a05d4 | 57 | PRIV_PING, |
4afe659e VB |
58 | PRIV_DELETE_CTL_SOCKET, |
59 | PRIV_GET_HOSTNAME, | |
60 | PRIV_OPEN, | |
61 | PRIV_ETHTOOL, | |
a7502371 VB |
62 | PRIV_IFACE_INIT, |
63 | PRIV_IFACE_MULTICAST, | |
d72a05d4 | 64 | PRIV_SNMP_SOCKET, |
b5562b23 VB |
65 | }; |
66 | ||
4afe659e VB |
67 | static int may_read(int, void *, size_t); |
68 | static void must_read(int, void *, size_t); | |
ef76f920 | 69 | static void must_write(int, const void *, size_t); |
b5562b23 | 70 | |
8888d191 VB |
71 | static int remote; /* Other side */ |
72 | static int monitored = -1; /* Child */ | |
73 | static int sock = -1; | |
b5562b23 VB |
74 | |
75 | /* Proxies */ | |
76 | ||
8888d191 | 77 | static void |
d72a05d4 VB |
78 | priv_ping() |
79 | { | |
80 | int cmd, rc; | |
81 | cmd = PRIV_PING; | |
82 | must_write(remote, &cmd, sizeof(int)); | |
83 | must_read(remote, &rc, sizeof(int)); | |
6f8925be | 84 | log_debug("privsep", "monitor ready"); |
d72a05d4 VB |
85 | } |
86 | ||
b5562b23 VB |
87 | /* Proxy for ctl_cleanup */ |
88 | void | |
89 | priv_ctl_cleanup() | |
90 | { | |
4afe659e VB |
91 | int cmd, rc; |
92 | cmd = PRIV_DELETE_CTL_SOCKET; | |
93 | must_write(remote, &cmd, sizeof(int)); | |
94 | must_read(remote, &rc, sizeof(int)); | |
b5562b23 VB |
95 | } |
96 | ||
97 | /* Proxy for gethostbyname */ | |
98 | char * | |
99 | priv_gethostbyname() | |
100 | { | |
4afe659e VB |
101 | int cmd, rc; |
102 | static char *buf = NULL; | |
103 | cmd = PRIV_GET_HOSTNAME; | |
104 | must_write(remote, &cmd, sizeof(int)); | |
105 | must_read(remote, &rc, sizeof(int)); | |
106 | if ((buf = (char*)realloc(buf, rc+1)) == NULL) | |
6f8925be | 107 | fatal("privsep", NULL); |
4afe659e VB |
108 | must_read(remote, buf, rc+1); |
109 | return buf; | |
b5562b23 VB |
110 | } |
111 | ||
112 | /* Proxy for open */ | |
113 | int | |
114 | priv_open(char *file) | |
115 | { | |
4afe659e VB |
116 | int cmd, len, rc; |
117 | cmd = PRIV_OPEN; | |
118 | must_write(remote, &cmd, sizeof(int)); | |
119 | len = strlen(file); | |
120 | must_write(remote, &len, sizeof(int)); | |
121 | must_write(remote, file, len + 1); | |
122 | must_read(remote, &rc, sizeof(int)); | |
123 | if (rc == -1) | |
124 | return rc; | |
125 | return receive_fd(remote); | |
126 | } | |
127 | ||
e12c2365 | 128 | #ifdef HOST_OS_LINUX |
4afe659e VB |
129 | /* Proxy for ethtool ioctl */ |
130 | int | |
e12c2365 | 131 | priv_ethtool(char *ifname, void *ethc, size_t length) |
4afe659e VB |
132 | { |
133 | int cmd, rc, len; | |
134 | cmd = PRIV_ETHTOOL; | |
135 | must_write(remote, &cmd, sizeof(int)); | |
136 | len = strlen(ifname); | |
137 | must_write(remote, &len, sizeof(int)); | |
138 | must_write(remote, ifname, len + 1); | |
139 | must_read(remote, &rc, sizeof(int)); | |
140 | if (rc != 0) | |
141 | return rc; | |
e12c2365 | 142 | must_read(remote, ethc, length); |
4afe659e | 143 | return rc; |
b5562b23 | 144 | } |
e12c2365 | 145 | #endif |
b5562b23 | 146 | |
a7502371 | 147 | int |
e12c2365 | 148 | priv_iface_init(int index) |
a7502371 VB |
149 | { |
150 | int cmd, rc; | |
151 | cmd = PRIV_IFACE_INIT; | |
152 | must_write(remote, &cmd, sizeof(int)); | |
e12c2365 | 153 | must_write(remote, &index, sizeof(int)); |
a7502371 | 154 | must_read(remote, &rc, sizeof(int)); |
849954d7 VB |
155 | if (rc != 0) return -1; |
156 | return receive_fd(remote); | |
a7502371 VB |
157 | } |
158 | ||
159 | int | |
ef76f920 | 160 | priv_iface_multicast(const char *name, u_int8_t *mac, int add) |
a7502371 VB |
161 | { |
162 | int cmd, rc; | |
163 | cmd = PRIV_IFACE_MULTICAST; | |
d72a05d4 | 164 | must_write(remote, &cmd, sizeof(int)); |
a7502371 VB |
165 | must_write(remote, name, IFNAMSIZ); |
166 | must_write(remote, mac, ETH_ALEN); | |
167 | must_write(remote, &add, sizeof(int)); | |
168 | must_read(remote, &rc, sizeof(int)); | |
169 | return rc; | |
170 | } | |
171 | ||
d72a05d4 VB |
172 | int |
173 | priv_snmp_socket(struct sockaddr_un *addr) | |
174 | { | |
175 | int cmd, rc; | |
176 | cmd = PRIV_SNMP_SOCKET; | |
177 | must_write(remote, &cmd, sizeof(int)); | |
178 | must_write(remote, addr, sizeof(struct sockaddr_un)); | |
179 | must_read(remote, &rc, sizeof(int)); | |
180 | if (rc < 0) | |
181 | return rc; | |
182 | return receive_fd(remote); | |
183 | } | |
184 | ||
8888d191 | 185 | static void |
d72a05d4 VB |
186 | asroot_ping() |
187 | { | |
188 | int rc = 1; | |
189 | must_write(remote, &rc, sizeof(int)); | |
190 | } | |
191 | ||
8888d191 | 192 | static void |
4afe659e | 193 | asroot_ctl_cleanup() |
b5562b23 | 194 | { |
4afe659e | 195 | int rc = 0; |
b5562b23 | 196 | ctl_cleanup(LLDPD_CTL_SOCKET); |
4afe659e VB |
197 | |
198 | /* Ack */ | |
199 | must_write(remote, &rc, sizeof(int)); | |
b5562b23 VB |
200 | } |
201 | ||
8888d191 | 202 | static void |
4afe659e | 203 | asroot_gethostbyname() |
b5562b23 VB |
204 | { |
205 | struct utsname un; | |
206 | struct hostent *hp; | |
4afe659e | 207 | int len; |
b5562b23 | 208 | if (uname(&un) != 0) |
6f8925be | 209 | fatal("privsep", "failed to get system information"); |
b5a6c479 | 210 | if ((hp = gethostbyname(un.nodename)) == NULL) { |
6f8925be | 211 | log_info("privsep", "unable to get system name"); |
c933faf6 | 212 | res_init(); |
b5a6c479 VB |
213 | len = strlen(un.nodename); |
214 | must_write(remote, &len, sizeof(int)); | |
215 | must_write(remote, un.nodename, len + 1); | |
216 | } else { | |
217 | len = strlen(hp->h_name); | |
218 | must_write(remote, &len, sizeof(int)); | |
219 | must_write(remote, hp->h_name, len + 1); | |
220 | } | |
b5562b23 VB |
221 | } |
222 | ||
8888d191 | 223 | static void |
4afe659e | 224 | asroot_open() |
b5562b23 | 225 | { |
4afe659e | 226 | const char* authorized[] = { |
b5562b23 | 227 | "/proc/sys/net/ipv4/ip_forward", |
1d291522 VB |
228 | "/proc/net/bonding/[^.][^/]*", |
229 | "/proc/self/net/bonding/[^.][^/]*", | |
89840df0 VB |
230 | SYSFS_CLASS_NET "[^.][^/]*/brforward", |
231 | SYSFS_CLASS_NET "[^.][^/]*/brport", | |
bac91719 | 232 | SYSFS_CLASS_NET "[^.][^/]*/brif/[^.][^/]*/port_no", |
89840df0 VB |
233 | SYSFS_CLASS_DMI "product_version", |
234 | SYSFS_CLASS_DMI "product_serial", | |
235 | SYSFS_CLASS_DMI "product_name", | |
236 | SYSFS_CLASS_DMI "bios_version", | |
237 | SYSFS_CLASS_DMI "sys_vendor", | |
238 | SYSFS_CLASS_DMI "chassis_asset_tag", | |
b5562b23 VB |
239 | NULL |
240 | }; | |
ef76f920 | 241 | const char **f; |
4afe659e VB |
242 | char *file; |
243 | int fd, len, rc; | |
29e043b5 | 244 | regex_t preg; |
4afe659e VB |
245 | |
246 | must_read(remote, &len, sizeof(len)); | |
247 | if ((file = (char *)malloc(len + 1)) == NULL) | |
6f8925be | 248 | fatal("privsep", NULL); |
29e043b5 VB |
249 | must_read(remote, file, len); |
250 | file[len] = '\0'; | |
b5562b23 VB |
251 | |
252 | for (f=authorized; *f != NULL; f++) { | |
29e043b5 VB |
253 | if (regcomp(&preg, *f, REG_NOSUB) != 0) |
254 | /* Should not happen */ | |
6f8925be | 255 | fatal("privsep", "unable to compile a regex"); |
29e043b5 VB |
256 | if (regexec(&preg, file, 0, NULL, 0) == 0) { |
257 | regfree(&preg); | |
4afe659e | 258 | break; |
29e043b5 VB |
259 | } |
260 | regfree(&preg); | |
b5562b23 | 261 | } |
4afe659e | 262 | if (*f == NULL) { |
6f8925be | 263 | log_warnx("privsep", "not authorized to open %s", file); |
4afe659e VB |
264 | rc = -1; |
265 | must_write(remote, &rc, sizeof(int)); | |
266 | free(file); | |
b5562b23 VB |
267 | return; |
268 | } | |
0aa5f676 | 269 | if ((fd = open(file, O_RDONLY)) == -1) { |
4afe659e VB |
270 | rc = -1; |
271 | must_write(remote, &rc, sizeof(int)); | |
272 | free(file); | |
b5562b23 VB |
273 | return; |
274 | } | |
4afe659e VB |
275 | free(file); |
276 | must_write(remote, &fd, sizeof(int)); | |
277 | send_fd(remote, fd); | |
b5562b23 VB |
278 | close(fd); |
279 | } | |
280 | ||
e12c2365 VB |
281 | #ifdef HOST_OS_LINUX |
282 | #include <linux/ethtool.h> | |
283 | #include <linux/sockios.h> | |
8888d191 | 284 | static void |
4afe659e VB |
285 | asroot_ethtool() |
286 | { | |
287 | struct ifreq ifr; | |
288 | struct ethtool_cmd ethc; | |
a7502371 | 289 | int len, rc; |
4afe659e VB |
290 | char *ifname; |
291 | ||
292 | memset(&ifr, 0, sizeof(ifr)); | |
293 | memset(ðc, 0, sizeof(ethc)); | |
294 | must_read(remote, &len, sizeof(int)); | |
295 | if ((ifname = (char*)malloc(len + 1)) == NULL) | |
6f8925be | 296 | fatal("privsep", NULL); |
29e043b5 VB |
297 | must_read(remote, ifname, len); |
298 | ifname[len] = '\0'; | |
4afe659e | 299 | strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
aabbb9ac | 300 | free(ifname); |
4afe659e VB |
301 | ifr.ifr_data = (caddr_t)ðc; |
302 | ethc.cmd = ETHTOOL_GSET; | |
4afe659e | 303 | if ((rc = ioctl(sock, SIOCETHTOOL, &ifr)) != 0) { |
4afe659e | 304 | must_write(remote, &rc, sizeof(int)); |
4afe659e VB |
305 | return; |
306 | } | |
4afe659e VB |
307 | must_write(remote, &rc, sizeof(int)); |
308 | must_write(remote, ðc, sizeof(struct ethtool_cmd)); | |
309 | } | |
e12c2365 | 310 | #endif |
4afe659e | 311 | |
8888d191 | 312 | static void |
849954d7 | 313 | asroot_iface_init() |
a7502371 VB |
314 | { |
315 | struct sockaddr_ll sa; | |
5fb6f53b | 316 | int s, rc = 0; |
e12c2365 | 317 | int ifindex; |
a7502371 | 318 | |
e12c2365 | 319 | must_read(remote, &ifindex, sizeof(ifindex)); |
a7502371 VB |
320 | |
321 | /* Open listening socket to receive/send frames */ | |
322 | if ((s = socket(PF_PACKET, SOCK_RAW, | |
323 | htons(ETH_P_ALL))) < 0) { | |
5fb6f53b VB |
324 | rc = errno; |
325 | must_write(remote, &rc, sizeof(rc)); | |
a7502371 VB |
326 | return; |
327 | } | |
328 | memset(&sa, 0, sizeof(sa)); | |
329 | sa.sll_family = AF_PACKET; | |
330 | sa.sll_protocol = 0; | |
e12c2365 | 331 | sa.sll_ifindex = ifindex; |
a7502371 | 332 | if (bind(s, (struct sockaddr*)&sa, sizeof(sa)) < 0) { |
5fb6f53b VB |
333 | rc = errno; |
334 | must_write(remote, &rc, sizeof(rc)); | |
a7502371 VB |
335 | close(s); |
336 | return; | |
337 | } | |
5fb6f53b | 338 | must_write(remote, &rc, sizeof(rc)); |
a7502371 VB |
339 | send_fd(remote, s); |
340 | close(s); | |
341 | } | |
342 | ||
8888d191 | 343 | static void |
a7502371 VB |
344 | asroot_iface_multicast() |
345 | { | |
346 | int add, rc = 0; | |
347 | struct ifreq ifr; | |
348 | memset(&ifr, 0, sizeof(ifr)); | |
349 | must_read(remote, ifr.ifr_name, IFNAMSIZ); | |
29e043b5 | 350 | ifr.ifr_name[IFNAMSIZ-1] = '\0'; |
a7502371 VB |
351 | must_read(remote, ifr.ifr_hwaddr.sa_data, ETH_ALEN); |
352 | must_read(remote, &add, sizeof(int)); | |
353 | ||
354 | if (ioctl(sock, (add)?SIOCADDMULTI:SIOCDELMULTI, | |
5fb6f53b VB |
355 | &ifr) < 0) |
356 | rc = errno; | |
509861fe | 357 | |
a7502371 VB |
358 | must_write(remote, &rc, sizeof(rc)); |
359 | } | |
360 | ||
d72a05d4 VB |
361 | static void |
362 | asroot_snmp_socket() | |
363 | { | |
364 | int sock, rc; | |
365 | static struct sockaddr_un *addr = NULL; | |
366 | struct sockaddr_un bogus; | |
367 | ||
368 | if (!addr) { | |
369 | addr = (struct sockaddr_un *)malloc(sizeof(struct sockaddr_un)); | |
370 | must_read(remote, addr, sizeof(struct sockaddr_un)); | |
371 | } else | |
372 | /* We have already been asked to connect to a socket. We will | |
373 | * connect to the same socket. */ | |
374 | must_read(remote, &bogus, sizeof(struct sockaddr_un)); | |
375 | if (addr->sun_family != AF_UNIX) | |
6f8925be | 376 | fatal("privsep", "someone is trying to trick me"); |
d72a05d4 VB |
377 | addr->sun_path[sizeof(addr->sun_path)-1] = '\0'; |
378 | ||
379 | if ((sock = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { | |
6f8925be | 380 | log_warn("privsep", "cannot open socket"); |
d72a05d4 VB |
381 | must_write(remote, &sock, sizeof(int)); |
382 | return; | |
383 | } | |
384 | if ((rc = connect(sock, (struct sockaddr *) addr, | |
385 | sizeof(struct sockaddr_un))) != 0) { | |
6f8925be | 386 | log_info("privsep", "cannot connect to %s: %s", |
5ac76eba | 387 | addr->sun_path, strerror(errno)); |
d72a05d4 VB |
388 | close(sock); |
389 | rc = -1; | |
390 | must_write(remote, &rc, sizeof(int)); | |
391 | return; | |
392 | } | |
393 | must_write(remote, &rc, sizeof(int)); | |
394 | send_fd(remote, sock); | |
e7c8287d | 395 | close(sock); |
d72a05d4 VB |
396 | } |
397 | ||
b5562b23 VB |
398 | struct dispatch_actions { |
399 | int msg; | |
4afe659e | 400 | void(*function)(void); |
b5562b23 VB |
401 | }; |
402 | ||
8888d191 | 403 | static struct dispatch_actions actions[] = { |
d72a05d4 | 404 | {PRIV_PING, asroot_ping}, |
4afe659e VB |
405 | {PRIV_DELETE_CTL_SOCKET, asroot_ctl_cleanup}, |
406 | {PRIV_GET_HOSTNAME, asroot_gethostbyname}, | |
407 | {PRIV_OPEN, asroot_open}, | |
408 | {PRIV_ETHTOOL, asroot_ethtool}, | |
849954d7 | 409 | {PRIV_IFACE_INIT, asroot_iface_init}, |
a7502371 | 410 | {PRIV_IFACE_MULTICAST, asroot_iface_multicast}, |
d72a05d4 | 411 | {PRIV_SNMP_SOCKET, asroot_snmp_socket}, |
4afe659e | 412 | {-1, NULL} |
b5562b23 VB |
413 | }; |
414 | ||
415 | /* Main loop, run as root */ | |
8888d191 | 416 | static void |
b5562b23 VB |
417 | priv_loop() |
418 | { | |
4afe659e | 419 | int cmd; |
b5562b23 VB |
420 | struct dispatch_actions *a; |
421 | ||
4afe659e | 422 | while (!may_read(remote, &cmd, sizeof(int))) { |
b5562b23 | 423 | for (a = actions; a->function != NULL; a++) { |
4afe659e VB |
424 | if (cmd == a->msg) { |
425 | a->function(); | |
b5562b23 VB |
426 | break; |
427 | } | |
428 | } | |
429 | if (a->function == NULL) | |
6f8925be | 430 | fatal("privsep", "bogus message received"); |
b5562b23 VB |
431 | } |
432 | /* Should never be there */ | |
433 | } | |
434 | ||
8888d191 | 435 | static void |
b5562b23 VB |
436 | priv_exit() |
437 | { | |
438 | int status; | |
439 | int rc; | |
440 | if ((rc = waitpid(monitored, &status, WNOHANG)) == 0) { | |
6f8925be | 441 | log_debug("privsep", "killing child"); |
b5562b23 VB |
442 | kill(monitored, SIGTERM); |
443 | } | |
444 | if ((rc = waitpid(monitored, &status, WNOHANG)) == -1) | |
445 | _exit(0); | |
6f8925be | 446 | log_debug("privsep", "waiting for child %d to terminate", monitored); |
b5562b23 VB |
447 | } |
448 | ||
4afe659e VB |
449 | /* If priv parent gets a TERM or HUP, pass it through to child instead */ |
450 | static void | |
451 | sig_pass_to_chld(int sig) | |
b5562b23 | 452 | { |
4afe659e VB |
453 | int oerrno = errno; |
454 | if (monitored != -1) | |
455 | kill(monitored, sig); | |
456 | errno = oerrno; | |
457 | } | |
458 | ||
459 | /* if parent gets a SIGCHLD, it will exit */ | |
460 | static void | |
461 | sig_chld(int sig) | |
462 | { | |
6f8925be | 463 | log_debug("privsep", "received signal %d, exiting", sig); |
b5562b23 VB |
464 | priv_exit(); |
465 | } | |
466 | ||
467 | /* Initialization */ | |
468 | void | |
2e91d1a1 | 469 | priv_init(char *chrootdir, int ctl, uid_t uid, gid_t gid) |
b5562b23 | 470 | { |
2e91d1a1 | 471 | |
b5562b23 | 472 | int pair[2]; |
4afe659e | 473 | gid_t gidset[1]; |
90149ee3 | 474 | int status; |
b5562b23 VB |
475 | |
476 | /* Create socket pair */ | |
4afe659e | 477 | if (socketpair(AF_LOCAL, SOCK_DGRAM, PF_UNSPEC, pair) < 0) |
6f8925be | 478 | fatal("privsep", "unable to create socket pair for privilege separation"); |
b5562b23 | 479 | |
b5562b23 VB |
480 | /* Spawn off monitor */ |
481 | if ((monitored = fork()) < 0) | |
6f8925be | 482 | fatal("privsep", "unable to fork monitor"); |
b5562b23 VB |
483 | switch (monitored) { |
484 | case 0: | |
485 | /* We are in the children, drop privileges */ | |
396cfdfe | 486 | if (RUNNING_ON_VALGRIND) |
6f8925be | 487 | log_warnx("privsep", "running on valgrind, keep privileges"); |
396cfdfe VB |
488 | else { |
489 | if (chroot(chrootdir) == -1) | |
6f8925be | 490 | fatal("privsep", "unable to chroot"); |
396cfdfe | 491 | if (chdir("/") != 0) |
6f8925be | 492 | fatal("privsep", "unable to chdir"); |
396cfdfe VB |
493 | gidset[0] = gid; |
494 | if (setresgid(gid, gid, gid) == -1) | |
6f8925be | 495 | fatal("privsep", "setresgid() failed"); |
396cfdfe | 496 | if (setgroups(1, gidset) == -1) |
6f8925be | 497 | fatal("privsep", "setgroups() failed"); |
396cfdfe | 498 | if (setresuid(uid, uid, uid) == -1) |
6f8925be | 499 | fatal("privsep", "setresuid() failed"); |
396cfdfe | 500 | } |
b5562b23 VB |
501 | remote = pair[0]; |
502 | close(pair[1]); | |
d72a05d4 | 503 | priv_ping(); |
b5562b23 VB |
504 | break; |
505 | default: | |
506 | /* We are in the monitor */ | |
2e91d1a1 | 507 | if (ctl != -1) close(ctl); |
b5562b23 VB |
508 | remote = pair[1]; |
509 | close(pair[0]); | |
510 | if (atexit(priv_exit) != 0) | |
6f8925be | 511 | fatal("privsep", "unable to set exit function"); |
a7502371 | 512 | if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) == -1) { |
6f8925be | 513 | fatal("privsep", "unable to get a socket"); |
a7502371 | 514 | } |
4afe659e VB |
515 | |
516 | signal(SIGALRM, sig_pass_to_chld); | |
517 | signal(SIGTERM, sig_pass_to_chld); | |
518 | signal(SIGHUP, sig_pass_to_chld); | |
519 | signal(SIGINT, sig_pass_to_chld); | |
520 | signal(SIGQUIT, sig_pass_to_chld); | |
521 | signal(SIGCHLD, sig_chld); | |
90149ee3 VB |
522 | if (waitpid(monitored, &status, WNOHANG) != 0) |
523 | /* Child is already dead */ | |
524 | _exit(1); | |
b5562b23 VB |
525 | priv_loop(); |
526 | exit(0); | |
527 | } | |
b5562b23 | 528 | } |
4afe659e VB |
529 | |
530 | /* Stolen from sbin/pflogd/privsep.c from OpenBSD */ | |
531 | /* | |
532 | * Copyright (c) 2003 Can Erkin Acar | |
533 | * Copyright (c) 2003 Anil Madhavapeddy <anil@recoil.org> | |
534 | * | |
51434125 | 535 | * Permission to use, copy, modify, and/or distribute this software for any |
4afe659e VB |
536 | * purpose with or without fee is hereby granted, provided that the above |
537 | * copyright notice and this permission notice appear in all copies. | |
538 | * | |
539 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
540 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
541 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
542 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
543 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
544 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
545 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
546 | */ | |
547 | ||
548 | /* Read all data or return 1 for error. */ | |
549 | static int | |
550 | may_read(int fd, void *buf, size_t n) | |
551 | { | |
552 | char *s = buf; | |
553 | ssize_t res, pos = 0; | |
554 | ||
555 | while (n > pos) { | |
556 | res = read(fd, s + pos, n - pos); | |
557 | switch (res) { | |
558 | case -1: | |
559 | if (errno == EINTR || errno == EAGAIN) | |
560 | continue; | |
561 | case 0: | |
562 | return (1); | |
563 | default: | |
564 | pos += res; | |
565 | } | |
566 | } | |
567 | return (0); | |
568 | } | |
569 | ||
570 | /* Read data with the assertion that it all must come through, or | |
571 | * else abort the process. Based on atomicio() from openssh. */ | |
572 | static void | |
573 | must_read(int fd, void *buf, size_t n) | |
574 | { | |
575 | char *s = buf; | |
576 | ssize_t res, pos = 0; | |
577 | ||
578 | while (n > pos) { | |
579 | res = read(fd, s + pos, n - pos); | |
580 | switch (res) { | |
581 | case -1: | |
582 | if (errno == EINTR || errno == EAGAIN) | |
583 | continue; | |
584 | case 0: | |
585 | _exit(0); | |
586 | default: | |
587 | pos += res; | |
588 | } | |
589 | } | |
590 | } | |
591 | ||
592 | /* Write data with the assertion that it all has to be written, or | |
593 | * else abort the process. Based on atomicio() from openssh. */ | |
594 | static void | |
ef76f920 | 595 | must_write(int fd, const void *buf, size_t n) |
4afe659e | 596 | { |
ef76f920 | 597 | const char *s = buf; |
4afe659e VB |
598 | ssize_t res, pos = 0; |
599 | ||
600 | while (n > pos) { | |
601 | res = write(fd, s + pos, n - pos); | |
602 | switch (res) { | |
603 | case -1: | |
604 | if (errno == EINTR || errno == EAGAIN) | |
605 | continue; | |
606 | case 0: | |
607 | _exit(0); | |
608 | default: | |
609 | pos += res; | |
610 | } | |
611 | } | |
612 | } |