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