1 /*
2 * Copyright (c) 2003 Anil Madhavapeddy <anil@recoil.org>
3 * Copyright (c) 2015 Laurent Coustet <ed@zehome.com>
4 *
5 * Permission to use, copy, modify, and distribute this software for any
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 #define _DEFAULT_SOURCE
19 #define _GNU_SOURCE
20
21 #include "includes.h"
22
23 #include <sys/ioctl.h>
24 #include <sys/wait.h>
25 #include <sys/types.h>
26 #include <sys/socket.h>
27 #include <sys/stat.h>
28 #include <netdb.h>
29 #include <err.h>
30 #include <errno.h>
31 #include <fcntl.h>
32 #include <pwd.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 #include <unistd.h>
37 #include <grp.h>
38
39 #if defined(HAVE_FREEBSD) || defined(HAVE_OPENBSD)
40 #include <signal.h>
41 #endif
42 #ifdef HAVE_FREEBSD
43 #define _NSIG _SIG_MAXSIG
44 #endif
45
46 #include "privsep.h"
47 #include "mlvpn.h"
48 #include "tuntap_generic.h"
49
50 /*
51 * mlvpn can only go forward in these states; each state should represent
52 * less privilege. After STATE_INIT, the child is allowed to parse its
53 * config file once, and communicate the information regarding what logfile
54 * it needs access to back to the parent. When that is done, it sends a
55 * message to the priv parent revoking this access, moving to STATE_RUNNING.
56 * In this state, any log-files not in the access list are rejected.
57 *
58 * This allows a HUP signal to the child to reopen its log files, and
59 * the config file to be parsed if it hasn't been changed (this is still
60 * useful to force resolution of remote syslog servers again).
61 * If the config file has been modified, then the child dies, and
62 * the priv parent restarts itself.
63 */
64 enum priv_state {
65 STATE_INIT, /* just started up */
66 STATE_CONFIG, /* parsing config file for first time */
67 STATE_RUNNING, /* running and accepting network traffic */
68 STATE_QUIT /* shutting down */
69 };
70
71 enum cmd_types {
72 PRIV_OPEN_CONFIG, /* open config file for reading only */
73 PRIV_INIT_SCRIPT, /* set allowed status script path */
74 PRIV_OPEN_TUN, /* open tun/tap device */
75 PRIV_RUN_SCRIPT, /* run status script */
76 PRIV_RELOAD_RESOLVER,
77 PRIV_GETADDRINFO,
78 PRIV_SET_RUNNING_STATE /* ready for maximum security */
79 };
80
81 /* Error message for some communication between processes */
82 #define ERRMSGSIZ 1024
83
84 static int priv_fd = -1;
85 static volatile pid_t child_pid = -1;
86 static volatile sig_atomic_t cur_state = STATE_INIT;
87
88 /* No-change runtime file path */
89 static char allowed_configfile[MAXPATHLEN] = {0};
90
91 static int root_open_file(char *, int);
92 int root_tuntap_open(int tuntapmode, char *devname, int mtu);
93 static int root_launch_script(char *, int, char **, char **);
94 static void increase_state(int);
95 static void sig_got_chld(int);
96 static void sig_pass_to_chld(int);
97 static void must_read(int, void *, size_t);
98 static void must_write(int, void *, size_t);
99 static int may_read(int, void *, size_t);
100 static void reset_default_signals();
101
102 int
priv_init(char * argv[],char * username)103 priv_init(char *argv[], char *username)
104 {
105 int i, fd, socks[2], cmd;
106 int nullfd;
107 int mtu;
108 int tuntapmode;
109 int env_len;
110 size_t len;
111 size_t hostname_len, servname_len, addrinfo_len;
112 char path[MAXPATHLEN];
113 struct passwd *pw = NULL;
114 struct sigaction sa;
115 struct addrinfo hints, *res0, *res;
116 char hostname[MLVPN_MAXHNAMSTR], servname[MLVPN_MAXHNAMSTR];
117 char *phostname, *pservname;
118 char script_path[MAXPATHLEN] = {0};
119 char tuntapname[MLVPN_IFNAMSIZ];
120 char **script_argv;
121 char **script_env;
122 char errormessage[ERRMSGSIZ];
123 int script_argc;
124 struct stat st;
125
126 /* LC: TODO: Better way to check for root ! */
127 int is_root = getuid() == 0;
128
129 reset_default_signals();
130 memset(&sa, 0, sizeof(sa));
131 sigemptyset(&sa.sa_mask);
132 sa.sa_handler = SIG_IGN;
133 sigaction(SIGPIPE, &sa, NULL);
134
135 /* Create sockets */
136 if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, socks) == -1)
137 err(1, "socketpair() failed");
138
139 /* Safe enough ? */
140 if (username && *username)
141 {
142 pw = getpwnam(username);
143 if (pw == NULL)
144 errx(1, "unknown user %s", username);
145 }
146
147 child_pid = fork();
148 if (child_pid < 0)
149 err(1, "fork() failed");
150
151 if (!child_pid)
152 {
153 if (RUNNING_ON_VALGRIND) {
154 warnx("running on valgrind, keep privileges");
155 } else {
156 /* Child - drop privileges and return */
157 if (is_root && pw)
158 {
159 if (chroot(pw->pw_dir) != 0)
160 err(1, "unable to chroot");
161 }
162
163 /* May be usefull to chose chdir directory ? */
164 if (chdir("/") != 0)
165 err(1, "unable to chdir");
166
167 if (is_root && pw)
168 {
169 if (setgroups(1, &pw->pw_gid) == -1)
170 err(1, "setgroups() failed");
171 /* NetBSD does not have thoses */
172 #ifdef HAVE_SETRESGID
173 if (setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) == -1)
174 err(1, "setresgid() failed");
175 #else
176 if (setregid(pw->pw_gid, pw->pw_gid) == -1)
177 err(1, "setregid() failed");
178 #endif
179 #ifdef HAVE_SETRESUID
180 if (setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid) == -1)
181 err(1, "setresuid() failed");
182 #else
183 if (setreuid(pw->pw_uid, pw->pw_uid) == -1)
184 err(1, "setreuid() failed");
185 #endif
186 }
187 }
188 close(socks[0]);
189 priv_fd = socks[1];
190 #ifdef HAVE_PLEDGE
191 if (pledge("stdio inet unix recvfd", NULL) != 0) {
192 err(1, "pledge");
193 }
194 #endif
195 return 0;
196 }
197 /* Father */
198 /* Pass TERM/HUP/INT/QUIT through to child, and accept CHLD */
199 sa.sa_flags = SA_RESTART;
200 sa.sa_handler = sig_pass_to_chld;
201 sigaction(SIGTERM, &sa, NULL);
202 sigaction(SIGHUP, &sa, NULL);
203 sigaction(SIGINT, &sa, NULL);
204 sigaction(SIGQUIT, &sa, NULL);
205 /* mlvpn (unpriv) died */
206 sa.sa_handler = sig_got_chld;
207 sa.sa_flags = SA_NOCLDSTOP;
208 sigaction(SIGCHLD, &sa, NULL);
209
210 close(socks[1]);
211
212 nullfd = open("/dev/null", O_RDONLY);
213 if (nullfd < 0)
214 {
215 perror("/dev/null");
216 _exit(1);
217 }
218 dup2(nullfd, 0);
219 dup2(nullfd, 1);
220 //dup2(nullfd, 2);
221 if (nullfd > 2)
222 close(nullfd);
223
224 increase_state(STATE_CONFIG);
225
226 while (cur_state < STATE_QUIT)
227 {
228 if (may_read(socks[0], &cmd, sizeof(cmd)))
229 break;
230 switch (cmd) {
231
232 case PRIV_OPEN_CONFIG:
233 must_read(socks[0], &len, sizeof(len));
234 if (len == 0 || len > sizeof(path) || len > MAXPATHLEN)
235 _exit(0);
236 must_read(socks[0], &path, len);
237 path[len - 1] = '\0';
238
239 if (cur_state == STATE_CONFIG)
240 strlcpy(allowed_configfile, path, len);
241 if (! *allowed_configfile)
242 fatalx("empty configuration file path");
243
244 fd = root_open_file(allowed_configfile, O_RDONLY|O_NONBLOCK);
245 send_fd(socks[0], fd);
246 if (fd < 0)
247 log_warnx("privsep", "priv_open_config `%s' failed",
248 allowed_configfile);
249 else
250 close(fd);
251 break;
252
253 case PRIV_OPEN_TUN:
254 /* we should not re-open the tuntap device ever! */
255 if (cur_state != STATE_CONFIG)
256 _exit(0);
257
258 must_read(socks[0], &tuntapmode, sizeof(tuntapmode));
259 if (tuntapmode != MLVPN_TUNTAPMODE_TUN &&
260 tuntapmode != MLVPN_TUNTAPMODE_TAP)
261 _exit(0);
262
263 must_read(socks[0], &len, sizeof(len));
264 if (len > MLVPN_IFNAMSIZ)
265 _exit(0);
266 else if (len > 0) {
267 must_read(socks[0], &tuntapname, len);
268 tuntapname[len - 1] = '\0';
269 } else {
270 tuntapname[0] = '\0';
271 }
272 must_read(socks[0], &mtu, sizeof(mtu));
273 if (mtu < 0 || mtu > 1500) {
274 fatalx("priv_open_tun: wrong mtu.");
275 }
276
277 /* see tuntap_*.c . That's where this is defined. */
278 fd = root_tuntap_open(tuntapmode, tuntapname, mtu);
279 if (fd < 0)
280 {
281 len = 0;
282 must_write(socks[0], &len, sizeof(len));
283 break;
284 }
285
286 len = strlen(tuntapname) + 1;
287 must_write(socks[0], &len, sizeof(len));
288 must_write(socks[0], tuntapname, len);
289 send_fd(socks[0], fd);
290 if (fd >= 0)
291 close(fd);
292 break;
293
294 case PRIV_INIT_SCRIPT:
295 /* Not allowed to change script path when running
296 * for security reasons
297 */
298 if (cur_state != STATE_CONFIG)
299 _exit(0);
300
301 must_read(socks[0], &len, sizeof(len));
302 if (len == 0 || len > sizeof(script_path))
303 _exit(0);
304 must_read(socks[0], &path, len);
305
306 path[len - 1] = '\0';
307
308 /* Basic permission checking.
309 * basically, the script must be 0700 owned by root
310 */
311 *errormessage = '\0';
312 if (stat(path, &st) < 0)
313 {
314 snprintf(errormessage, ERRMSGSIZ, "Unable to open file %s:%s",
315 path, strerror(errno));
316 } else if (st.st_mode & (S_IRWXG|S_IRWXO)) {
317 snprintf(errormessage, ERRMSGSIZ,
318 "%s is group/other accessible",
319 path);
320 } else if (!(st.st_mode & S_IXUSR)) {
321 snprintf(errormessage, ERRMSGSIZ,
322 "%s is not executable",
323 path);
324 } else {
325 strlcpy(script_path, path, len);
326 }
327 len = strlen(errormessage) + 1;
328 must_write(socks[0], &len, sizeof(len));
329 must_write(socks[0], errormessage, len);
330 break;
331
332 case PRIV_GETADDRINFO:
333 /* Expecting: len, hostname, len, servname, hints */
334 must_read(socks[0], &hostname_len, sizeof(hostname_len));
335 if (hostname_len > sizeof(hostname))
336 _exit(0);
337 else if (hostname_len > 0) {
338 must_read(socks[0], &hostname, hostname_len);
339 hostname[hostname_len - 1] = '\0';
340 phostname = hostname;
341 } else {
342 phostname = NULL;
343 }
344
345 must_read(socks[0], &servname_len, sizeof(servname_len));
346 if (servname_len > sizeof(servname))
347 _exit(0);
348 if (servname_len > 0) {
349 must_read(socks[0], &servname, servname_len);
350 servname[servname_len - 1] = '\0';
351 pservname = servname;
352 } else {
353 pservname = NULL;
354 }
355
356 memset(&hints, '\0', sizeof(struct addrinfo));
357 must_read(socks[0], &hints, sizeof(struct addrinfo));
358
359 addrinfo_len = 0;
360 i = getaddrinfo(phostname, pservname, &hints, &res0);
361 if (i != 0 || res0 == NULL) {
362 must_write(socks[0], &addrinfo_len, sizeof(addrinfo_len));
363 } else {
364 res = res0;
365 while (res)
366 {
367 addrinfo_len++;
368 res = res->ai_next;
369 }
370 must_write(socks[0], &addrinfo_len, sizeof(addrinfo_len));
371
372 res = res0;
373 while (res)
374 {
375 must_write(socks[0], &res->ai_flags, sizeof(res->ai_flags));
376 must_write(socks[0], &res->ai_family, sizeof(res->ai_family));
377 must_write(socks[0], &res->ai_socktype, sizeof(res->ai_socktype));
378 must_write(socks[0], &res->ai_protocol, sizeof(res->ai_protocol));
379 must_write(socks[0], &res->ai_addrlen, sizeof(res->ai_addrlen));
380 must_write(socks[0], res->ai_addr, res->ai_addrlen);
381 res = res->ai_next;
382 }
383 freeaddrinfo(res0);
384 }
385 break;
386
387 case PRIV_RUN_SCRIPT:
388 must_read(socks[0], &script_argc, sizeof(script_argc));
389 if (script_argc <= 0)
390 _exit(0);
391
392 if ((script_argv = (char **)calloc(script_argc + 1, sizeof(char *))) == NULL)
393 _exit(0);
394
395 /* read script argumuments */
396 for(i = 0; i < script_argc; i++) {
397 must_read(socks[0], &len, sizeof(len));
398 if (len <= 0)
399 _exit(0);
400 if ((script_argv[i] = (char *)malloc(len)) == NULL)
401 _exit(0);
402 must_read(socks[0], script_argv[i], len);
403 script_argv[i][len-1] = '\0';
404 }
405 script_argv[i] = NULL;
406
407 /* Read environment */
408 must_read(socks[0], &env_len, sizeof(env_len));
409 if (env_len <= 0)
410 _exit(0);
411 if ((script_env = (char **)calloc(env_len + 1, sizeof(char *))) == NULL)
412 _exit(0);
413 for(i = 0; i < env_len; i++) {
414 must_read(socks[0], &len, sizeof(len));
415 if (len <= 0)
416 _exit(0);
417 if ((script_env[i] = (char *)malloc(len)) == NULL)
418 _exit(0);
419 must_read(socks[0], script_env[i], len);
420 script_env[i][len - 1] = '\0';
421 }
422
423 if (! *script_path)
424 i = -1;
425 else
426 i = root_launch_script(script_path,
427 script_argc, script_argv, script_env);
428 must_write(socks[0], &i, sizeof(i));
429 for(i = 0; i < script_argc && script_argv[i]; i++)
430 free(script_argv[i]);
431 free(script_argv);
432 for(i = 0; i < env_len && script_env[i]; i++)
433 free(script_env[i]);
434 free(script_env);
435 break;
436 case PRIV_RELOAD_RESOLVER:
437 #ifdef HAVE_DECL_RES_INIT
438 res_init();
439 #endif
440 break;
441
442 case PRIV_SET_RUNNING_STATE:
443 increase_state(STATE_RUNNING);
444 #ifdef HAVE_PLEDGE
445 if (pledge("rpath stdio dns sendfd exec proc", NULL) != 0) {
446 err(1, "pledge");
447 }
448 #endif
449 break;
450
451 default:
452 errx(1, "unknown command %d", cmd);
453 break;
454 }
455 }
456
457 close(socks[0]);
458 _exit(1);
459 }
460
461 static int
root_open_file(char * path,int flags)462 root_open_file(char *path, int flags)
463 {
464 /* must not start with | */
465 if (path[0] == '|')
466 return (-1);
467 return (open(path, flags, 0));
468 }
469
470 static int
root_launch_script(char * setup_script,int argc,char ** argv,char ** env)471 root_launch_script(char *setup_script, int argc, char **argv, char **env)
472 {
473 sigset_t oldmask, mask;
474 int pid, status = -1;
475 int i;
476 char **newargs;
477 char **envp = env;
478
479 sigemptyset(&mask);
480 sigaddset(&mask, SIGCHLD);
481 sigprocmask(SIG_BLOCK, &mask, &oldmask);
482
483 /* try to launch network script */
484 pid = fork();
485 if (pid == 0)
486 {
487 /* Reset all signals is required because after fork
488 * the child process inherits all signal dispositions
489 * of the parent
490 */
491 reset_default_signals();
492 closefrom(3);
493 newargs = (char **)calloc(argc + 2, sizeof(char *));
494 if (! newargs)
495 err(1, "memory allocation failed");
496 newargs[0] = setup_script;
497 for(i = 0; i < argc; i++)
498 newargs[i+1] = argv[i];
499 newargs[i+1] = NULL;
500
501 while (*envp) {
502 putenv(*envp);
503 envp++;
504 }
505
506 if(chdir("/") != 0)
507 errx(1, "chdir failed.");
508 execv(setup_script, newargs);
509 _exit(1);
510 } else if (pid > 0) {
511 while (waitpid(pid, &status, 0) != pid) {
512 /* loop */
513 }
514 sigprocmask(SIG_SETMASK, &oldmask, NULL);
515 if (WIFEXITED(status) && WEXITSTATUS(status) == 0) {
516 return status;
517 } else if (WIFSIGNALED(status)) {
518 log_warnx("privsep", "network script %s killed by signal %d",
519 setup_script,
520 WTERMSIG(status));
521 } else {
522 log_warnx("privsep", "network script %s exit status %d",
523 setup_script,
524 WEXITSTATUS(status));
525 }
526 } else
527 log_warn("privsep",
528 "%s: could not launch network script", setup_script);
529 return status;
530 }
531
532 /* Crank our state into less permissive modes */
533 static void
increase_state(int state)534 increase_state(int state)
535 {
536 if (state <= cur_state)
537 errx(1, "attempt to decrease or match current state");
538 if (state < STATE_INIT || state > STATE_QUIT)
539 errx(1, "attempt to switch to invalid state");
540 cur_state = state;
541 }
542
543 /* Open mlvpn config file for reading */
544 int
priv_open_config(char * config_path)545 priv_open_config(char *config_path)
546 {
547 int cmd, fd;
548 size_t len;
549
550 if (priv_fd < 0)
551 errx(1, "%s: called from privileged portion", "priv_open_config");
552
553 len = strlen(config_path) + 1;
554
555 cmd = PRIV_OPEN_CONFIG;
556 must_write(priv_fd, &cmd, sizeof(cmd));
557
558 must_write(priv_fd, &len, sizeof(len));
559 must_write(priv_fd, config_path, len);
560
561 fd = receive_fd(priv_fd);
562 return fd;
563 }
564
565 /* Open tun from unpriviled code
566 * Scope: public
567 */
priv_open_tun(int tuntapmode,char * devname,int mtu)568 int priv_open_tun(int tuntapmode, char *devname, int mtu)
569 {
570 int cmd, fd;
571 size_t len;
572
573 if (priv_fd < 0)
574 errx(1, "%s: called from privileged portion", "priv_open_tun");
575
576 if (devname == NULL)
577 len = 0;
578 else
579 len = strlen(devname) + 1;
580
581 cmd = PRIV_OPEN_TUN;
582 must_write(priv_fd, &cmd, sizeof(cmd));
583 must_write(priv_fd, &tuntapmode, sizeof(tuntapmode));
584
585 must_write(priv_fd, &len, sizeof(len));
586 if (len > 0 && devname != NULL)
587 must_write(priv_fd, devname, len);
588 must_write(priv_fd, &mtu, sizeof(mtu));
589
590 must_read(priv_fd, &len, sizeof(len));
591 if (len > 0 && len < MLVPN_IFNAMSIZ && devname != NULL)
592 {
593 must_read(priv_fd, devname, len);
594 devname[len-1] = '\0';
595 fd = receive_fd(priv_fd);
596 } else if (len <= 0) {
597 fd = len;
598 } else {
599 /* Too big ! */
600 errx(1, "%s: device name returned by privileged "
601 "service is too long.",
602 "priv_open_tun");
603 }
604 return fd;
605 }
606
607
608 /* Name/service to address translation. Response is placed into addr, and
609 * the length is returned (zero on error) */
610 int
priv_getaddrinfo(char * host,char * serv,struct addrinfo ** addrinfo,struct addrinfo * hints)611 priv_getaddrinfo(char *host, char *serv, struct addrinfo **addrinfo,
612 struct addrinfo *hints)
613 {
614 char hostcpy[MLVPN_MAXHNAMSTR], servcpy[MLVPN_MAXHNAMSTR];
615 int cmd;
616 size_t i, hostname_len, servname_len, ret_len;
617 struct addrinfo *new, *last = NULL;
618
619 if (priv_fd < 0)
620 errx(1, "%s: called from privileged portion", "priv_getaddrinfo");
621
622 if (host) {
623 strlcpy(hostcpy, host, sizeof(hostcpy));
624 hostname_len = strlen(hostcpy) + 1;
625 } else {
626 hostname_len = 0;
627 }
628
629 if (serv) {
630 strlcpy(servcpy, serv, sizeof(servcpy));
631 servname_len = strlen(servcpy) + 1;
632 } else {
633 servname_len = 0;
634 }
635 cmd = PRIV_GETADDRINFO;
636 must_write(priv_fd, &cmd, sizeof(cmd));
637 must_write(priv_fd, &hostname_len, sizeof(hostname_len));
638 if (hostname_len)
639 must_write(priv_fd, hostcpy, hostname_len);
640 must_write(priv_fd, &servname_len, sizeof(servname_len));
641 if (servname_len)
642 must_write(priv_fd, servcpy, servname_len);
643 must_write(priv_fd, hints, sizeof(struct addrinfo));
644
645 /* How much addrinfo we have */
646 must_read(priv_fd, &ret_len, sizeof(ret_len));
647
648 /* Check there was no error (indicated by a return of 0) */
649 if (!ret_len)
650 return 0;
651
652 for (i=0; i < ret_len; i++)
653 {
654 new = (struct addrinfo *)malloc(sizeof(struct addrinfo));
655 must_read(priv_fd, &new->ai_flags, sizeof(new->ai_flags));
656 must_read(priv_fd, &new->ai_family, sizeof(new->ai_family));
657 must_read(priv_fd, &new->ai_socktype, sizeof(new->ai_socktype));
658 must_read(priv_fd, &new->ai_protocol, sizeof(new->ai_protocol));
659 must_read(priv_fd, &new->ai_addrlen, sizeof(new->ai_addrlen));
660 new->ai_addr = (struct sockaddr *)malloc(new->ai_addrlen);
661 must_read(priv_fd, new->ai_addr, new->ai_addrlen);
662 new->ai_canonname = NULL;
663 new->ai_next = NULL;
664
665 if (i == 0)
666 *addrinfo = new;
667 if (last)
668 last->ai_next = new;
669 last = new;
670 }
671
672 return ret_len;
673 }
674
675 /* init script path */
676 int
priv_init_script(char * path)677 priv_init_script(char *path)
678 {
679 int cmd;
680 size_t len;
681 char errormessage[ERRMSGSIZ];
682
683 if (priv_fd < 0)
684 errx(1, "%s: called from privileged portion",
685 "priv_init_script");
686
687 cmd = PRIV_INIT_SCRIPT;
688 must_write(priv_fd, &cmd, sizeof(cmd));
689 len = strlen(path) + 1;
690 must_write(priv_fd, &len, sizeof(len));
691 must_write(priv_fd, path, len);
692
693 must_read(priv_fd, &len, sizeof(len));
694
695 if (len <= 0)
696 {
697 errx(1, "priv_init_script: invalid answer from server");
698 } else if (len > ERRMSGSIZ) {
699 log_warnx("privsep", "priv_init_script: error message truncated");
700 len = ERRMSGSIZ;
701 }
702 must_read(priv_fd, errormessage, len);
703 errormessage[len-1] = 0;
704
705 if (*errormessage)
706 {
707 log_warnx("privsep", "error from priv server: %s",
708 errormessage);
709 return -1;
710 }
711 return 0;
712 }
713
714 /* run script */
715 int
priv_run_script(int argc,char ** argv,int env_len,char ** env)716 priv_run_script(int argc, char **argv, int env_len, char **env)
717 {
718 int cmd, retval;
719 int i;
720 size_t len;
721
722 if (priv_fd < 0)
723 errx(1, "%s: called from privileged portion",
724 "priv_run_script");
725
726 cmd = PRIV_RUN_SCRIPT;
727 must_write(priv_fd, &cmd, sizeof(cmd));
728
729 must_write(priv_fd, &argc, sizeof(argc));
730 for (i=0; i < argc; i++)
731 {
732 len = strlen(argv[i]) + 1;
733 must_write(priv_fd, &len, sizeof(len));
734 must_write(priv_fd, argv[i], len);
735 }
736 must_write(priv_fd, &env_len, sizeof(env_len));
737 for (i=0; i < env_len; i++) {
738 len = strlen(env[i]) + 1;
739 must_write(priv_fd, &len, sizeof(len));
740 must_write(priv_fd, env[i], len);
741 }
742
743 must_read(priv_fd, &retval, sizeof(retval));
744 return retval;
745 }
746
priv_reload_resolver(void)747 void priv_reload_resolver(void)
748 {
749 int cmd;
750 if (priv_fd < 0)
751 errx(1, "%s: called from privileged portion",
752 "priv_reload_resolver");
753 cmd = PRIV_RELOAD_RESOLVER;
754 must_write(priv_fd, &cmd, sizeof(cmd));
755 }
756
757 /* Child can signal that its initial parsing is done, so that parent
758 * can revoke further logfile permissions. This call only works once. */
759 void
priv_set_running_state(void)760 priv_set_running_state(void)
761 {
762 int cmd;
763 if (priv_fd < 0)
764 errx(1, "%s: called from privileged portion",
765 "priv_set_running_state");
766 cmd = PRIV_SET_RUNNING_STATE;
767 must_write(priv_fd, &cmd, sizeof(cmd));
768 }
769
770 /* When child dies, move into the shutdown state */
771 /* ARGSUSED */
772 static void
sig_got_chld(int sig)773 sig_got_chld(int sig)
774 {
775 int save_errno = errno;
776 pid_t pid;
777
778 do {
779 pid = waitpid(WAIT_ANY, NULL, WNOHANG);
780 if (pid == child_pid && cur_state < STATE_QUIT)
781 cur_state = STATE_QUIT;
782 } while (pid > 0 || (pid == -1 && errno == EINTR));
783 errno = save_errno;
784 }
785
786 static void
sig_pass_to_chld(int sig)787 sig_pass_to_chld(int sig)
788 {
789 int save_errno = errno;
790 if (child_pid != -1)
791 {
792 kill(child_pid, sig);
793 errno = save_errno;
794 }
795 }
796
797 /* Read all data or return 1 for error. */
798 static int
may_read(int fd,void * buf,size_t n)799 may_read(int fd, void *buf, size_t n)
800 {
801 char *s = buf;
802 ssize_t res, pos = 0;
803
804 while (n > pos)
805 {
806 res = read(fd, s + pos, n - pos);
807 switch (res) {
808 case -1:
809 if (errno == EINTR || errno == EAGAIN)
810 continue;
811 case 0:
812 return (1);
813 default:
814 pos += res;
815 }
816 }
817 return (0);
818 }
819
820 /* Read data with the assertion that it all must come through, or
821 * else abort the process. Based on atomicio() from openssh. */
822 static void
must_read(int fd,void * buf,size_t n)823 must_read(int fd, void *buf, size_t n)
824 {
825 char *s = buf;
826 ssize_t res, pos = 0;
827
828 while (n > pos)
829 {
830 res = read(fd, s + pos, n - pos);
831 switch (res) {
832 case -1:
833 if (errno == EINTR || errno == EAGAIN)
834 continue;
835 case 0:
836 _exit(0);
837 default:
838 pos += res;
839 }
840 }
841 }
842
843 /* Write data with the assertion that it all has to be written, or
844 * else abort the process. Based on atomicio() from openssh. */
845 static void
must_write(int fd,void * buf,size_t n)846 must_write(int fd, void *buf, size_t n)
847 {
848 char *s = buf;
849 ssize_t res, pos = 0;
850
851 while (n > pos)
852 {
853 res = write(fd, s + pos, n - pos);
854 switch (res) {
855 case -1:
856 if (errno == EINTR || errno == EAGAIN)
857 continue;
858 case 0:
859 _exit(0);
860 default:
861 pos += res;
862 }
863 }
864 }
865
866 static void
reset_default_signals()867 reset_default_signals()
868 {
869 int i;
870 struct sigaction sa;
871 memset(&sa, 0, sizeof(sa));
872 sigemptyset(&sa.sa_mask);
873 sa.sa_flags = SA_RESTART;
874 sa.sa_handler = SIG_DFL;
875 for (i = 1; i < _NSIG; i++)
876 sigaction(i, &sa, NULL);
877 }
878