1 /* $OpenBSD: privsep.c,v 1.13 2004/12/22 09:21:02 otto Exp $ */
4 * Copyright (c) 2003 Can Erkin Acar
5 * Copyright (c) 2003 Anil Madhavapeddy <anil@recoil.org>
7 * Permission to use, copy, modify, and distribute this software for any
8 * purpose with or without fee is hereby granted, provided that the above
9 * copyright notice and this permission notice appear in all copies.
11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include <sys/cdefs.h>
21 __FBSDID("$FreeBSD$");
23 #include <sys/param.h>
25 #include <sys/socket.h>
45 PRIV_SET_SNAPLEN, /* set the snaplength */
46 PRIV_OPEN_LOG /* open logfile for appending */
49 static int priv_fd = -1;
50 static volatile pid_t child_pid = -1;
52 volatile sig_atomic_t gotsig_chld = 0;
54 static void sig_pass_to_chld(int);
55 static void sig_chld(int);
56 static int may_read(int, void *, size_t);
57 static void must_read(int, void *, size_t);
58 static void must_write(int, void *, size_t);
59 static int set_snaplen(int snap);
61 /* bpf filter expression common to parent and child */
64 extern char *filename;
67 /* based on syslogd privsep */
71 int i, fd, socks[2], cmd;
72 int snaplen, ret, olderrno;
76 for (i = 1; i < NSIG; i++)
78 for (i = 1; i < _NSIG; i++)
83 if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, socks) == -1)
84 err(1, "socketpair() failed");
86 pw = getpwnam("_pflogd");
88 errx(1, "unknown user _pflogd");
93 err(1, "fork() failed");
98 /* Child - drop privileges and return */
99 if (chroot(pw->pw_dir) != 0)
100 err(1, "unable to chroot");
102 err(1, "unable to chdir");
104 gidset[0] = pw->pw_gid;
105 if (setgroups(1, gidset) == -1)
106 err(1, "setgroups() failed");
107 if (setegid(pw->pw_gid) == -1)
108 err(1, "setegid() failed");
109 if (setgid(pw->pw_gid) == -1)
110 err(1, "setgid() failed");
111 if (seteuid(pw->pw_uid) == -1)
112 err(1, "seteuid() failed");
113 if (setuid(pw->pw_uid) == -1)
114 err(1, "setuid() failed");
121 /* Pass ALRM/TERM/HUP/INT/QUIT through to child, and accept CHLD */
122 signal(SIGALRM, sig_pass_to_chld);
123 signal(SIGTERM, sig_pass_to_chld);
124 signal(SIGHUP, sig_pass_to_chld);
125 signal(SIGINT, sig_pass_to_chld);
126 signal(SIGQUIT, sig_pass_to_chld);
127 signal(SIGCHLD, sig_chld);
129 setproctitle("[priv]");
132 while (!gotsig_chld) {
133 if (may_read(socks[0], &cmd, sizeof(int)))
136 case PRIV_SET_SNAPLEN:
138 "[priv]: msg PRIV_SET_SNAPLENGTH received");
139 must_read(socks[0], &snaplen, sizeof(int));
141 ret = set_snaplen(snaplen);
144 "[priv]: set_snaplen failed for snaplen %d",
148 must_write(socks[0], &ret, sizeof(int));
153 "[priv]: msg PRIV_OPEN_LOG received");
154 /* create or append logs but do not follow symlinks */
156 O_RDWR|O_CREAT|O_APPEND|O_NONBLOCK|O_NOFOLLOW,
159 send_fd(socks[0], fd);
162 "[priv]: failed to open %s: %s",
163 filename, strerror(olderrno));
169 logmsg(LOG_ERR, "[priv]: unknown command %d", cmd);
178 /* this is called from parent */
180 set_snaplen(int snap)
185 hpcap->snapshot = snap;
193 * send the snaplength to privileged process
196 priv_set_snaplen(int snaplen)
201 errx(1, "%s: called from privileged portion", __func__);
203 cmd = PRIV_SET_SNAPLEN;
205 must_write(priv_fd, &cmd, sizeof(int));
206 must_write(priv_fd, &snaplen, sizeof(int));
208 must_read(priv_fd, &ret, sizeof(int));
210 /* also set hpcap->snapshot in child */
212 hpcap->snapshot = snaplen;
224 errx(1, "%s: called from privileged portion", __func__);
227 must_write(priv_fd, &cmd, sizeof(int));
228 fd = receive_fd(priv_fd);
233 /* If priv parent gets a TERM or HUP, pass it through to child instead */
235 sig_pass_to_chld(int sig)
240 kill(child_pid, sig);
244 /* if parent gets a SIGCHLD, it will exit */
251 /* Read all data or return 1 for error. */
253 may_read(int fd, void *buf, size_t n)
256 ssize_t res, pos = 0;
259 res = read(fd, s + pos, n - pos);
262 if (errno == EINTR || errno == EAGAIN)
273 /* Read data with the assertion that it all must come through, or
274 * else abort the process. Based on atomicio() from openssh. */
276 must_read(int fd, void *buf, size_t n)
279 ssize_t res, pos = 0;
282 res = read(fd, s + pos, n - pos);
285 if (errno == EINTR || errno == EAGAIN)
295 /* Write data with the assertion that it all has to be written, or
296 * else abort the process. Based on atomicio() from openssh. */
298 must_write(int fd, void *buf, size_t n)
301 ssize_t res, pos = 0;
304 res = write(fd, s + pos, n - pos);
307 if (errno == EINTR || errno == EAGAIN)