2 /* $OpenBSD: privsep.c,v 1.16 2006/10/25 20:55:04 moritz Exp $ */
5 * Copyright (c) 2003 Can Erkin Acar
6 * Copyright (c) 2003 Anil Madhavapeddy <anil@recoil.org>
8 * Permission to use, copy, modify, and distribute this software for any
9 * purpose with or without fee is hereby granted, provided that the above
10 * copyright notice and this permission notice appear in all copies.
12 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
13 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
14 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
15 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
16 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
17 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
18 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
20 #include <sys/types.h>
22 #include <sys/socket.h>
23 #include <sys/ioctl.h>
36 * If we're going to include parts of the libpcap internals we MUST
37 * set the feature-test macros they expect, or they may misbehave.
41 #define HAVE_VSNPRINTF
52 PRIV_SET_SNAPLEN
, /* set the snaplength */
53 PRIV_MOVE_LOG
, /* move logfile away */
54 PRIV_OPEN_LOG
/* open logfile for appending */
57 static int priv_fd
= -1;
58 static volatile pid_t child_pid
= -1;
60 volatile sig_atomic_t gotsig_chld
= 0;
62 static void sig_pass_to_chld(int);
63 static void sig_chld(int);
64 static int may_read(int, void *, size_t);
65 static void must_read(int, void *, size_t);
66 static void must_write(int, void *, size_t);
67 static int set_snaplen(int snap
);
68 static int move_log(const char *name
);
70 extern char *filename
;
73 /* based on syslogd privsep */
77 int i
, fd
, socks
[2], cmd
;
78 int snaplen
, ret
, olderrno
;
81 for (i
= 1; i
< _NSIG
; i
++)
85 if (socketpair(AF_LOCAL
, SOCK_STREAM
, PF_UNSPEC
, socks
) == -1)
86 err(1, "socketpair() failed");
88 pw
= getpwnam("_pflogd");
90 errx(1, "unknown user _pflogd");
95 err(1, "fork() failed");
100 /* Child - drop privileges and return */
101 if (chroot(pw
->pw_dir
) != 0)
102 err(1, "unable to chroot");
104 err(1, "unable to chdir");
106 gidset
[0] = pw
->pw_gid
;
108 if (setresgid(pw
->pw_gid
, pw
->pw_gid
, pw
->pw_gid
) == -1)
109 err(1, "setresgid() failed");
111 if (setgid(pw
->pw_gid
) == -1)
112 err(1, "setgid() failed");
114 if (setgroups(1, gidset
) == -1)
115 err(1, "setgroups() failed");
117 if (setresuid(pw
->pw_uid
, pw
->pw_uid
, pw
->pw_uid
) == -1)
118 err(1, "setresuid() failed");
120 if (setuid(pw
->pw_uid
) == -1)
121 err(1, "setuid() failed");
129 /* Pass ALRM/TERM/HUP/INT/QUIT through to child, and accept CHLD */
130 signal(SIGALRM
, sig_pass_to_chld
);
131 signal(SIGTERM
, sig_pass_to_chld
);
132 signal(SIGHUP
, sig_pass_to_chld
);
133 signal(SIGINT
, sig_pass_to_chld
);
134 signal(SIGQUIT
, sig_pass_to_chld
);
135 signal(SIGCHLD
, sig_chld
);
137 setproctitle("[priv]");
140 while (!gotsig_chld
) {
141 if (may_read(socks
[0], &cmd
, sizeof(int)))
144 case PRIV_SET_SNAPLEN
:
146 "[priv]: msg PRIV_SET_SNAPLENGTH received");
147 must_read(socks
[0], &snaplen
, sizeof(int));
149 ret
= set_snaplen(snaplen
);
152 "[priv]: set_snaplen failed for snaplen %d",
156 must_write(socks
[0], &ret
, sizeof(int));
161 "[priv]: msg PRIV_OPEN_LOG received");
162 /* create or append logs but do not follow symlinks */
164 O_RDWR
|O_CREAT
|O_APPEND
|O_NONBLOCK
|O_NOFOLLOW
,
167 send_fd(socks
[0], fd
);
170 "[priv]: failed to open %s: %s",
171 filename
, strerror(olderrno
));
178 "[priv]: msg PRIV_MOVE_LOG received");
179 ret
= move_log(filename
);
180 must_write(socks
[0], &ret
, sizeof(int));
184 logmsg(LOG_ERR
, "[priv]: unknown command %d", cmd
);
193 /* this is called from parent */
195 set_snaplen(int snap
)
200 hpcap
->snapshot
= snap
;
207 move_log(const char *name
)
215 len
= snprintf(ren
, sizeof(ren
), "%s.bad.%08x",
217 if (len
>= sizeof(ren
)) {
218 logmsg(LOG_ERR
, "[priv] new name too long");
222 /* lock destinanion */
223 fd
= open(ren
, O_CREAT
|O_EXCL
, 0);
228 /* if file exists, try another name */
229 if (errno
!= EEXIST
&& errno
!= EINTR
) {
230 logmsg(LOG_ERR
, "[priv] failed to create new name: %s",
236 if (rename(name
, ren
)) {
237 logmsg(LOG_ERR
, "[priv] failed to rename %s to %s: %s",
238 name
, ren
, strerror(errno
));
243 "[priv]: log file %s moved to %s", name
, ren
);
249 * send the snaplength to privileged process
252 priv_set_snaplen(int snaplen
)
257 errx(1, "%s: called from privileged portion", __func__
);
259 cmd
= PRIV_SET_SNAPLEN
;
261 must_write(priv_fd
, &cmd
, sizeof(int));
262 must_write(priv_fd
, &snaplen
, sizeof(int));
264 must_read(priv_fd
, &ret
, sizeof(int));
266 /* also set hpcap->snapshot in child */
268 hpcap
->snapshot
= snaplen
;
280 errx(1, "%s: called from privileged portion", __func__
);
283 must_write(priv_fd
, &cmd
, sizeof(int));
284 fd
= receive_fd(priv_fd
);
288 /* Move-away and reopen log-file */
295 errx(1, "%s: called from privileged portion\n", __func__
);
298 must_write(priv_fd
, &cmd
, sizeof(int));
299 must_read(priv_fd
, &ret
, sizeof(int));
304 /* If priv parent gets a TERM or HUP, pass it through to child instead */
306 sig_pass_to_chld(int sig
)
311 kill(child_pid
, sig
);
315 /* if parent gets a SIGCHLD, it will exit */
322 /* Read all data or return 1 for error. */
324 may_read(int fd
, void *buf
, size_t n
)
327 ssize_t res
, pos
= 0;
330 res
= read(fd
, s
+ pos
, n
- pos
);
333 if (errno
== EINTR
|| errno
== EAGAIN
)
344 /* Read data with the assertion that it all must come through, or
345 * else abort the process. Based on atomicio() from openssh. */
347 must_read(int fd
, void *buf
, size_t n
)
350 ssize_t res
, pos
= 0;
353 res
= read(fd
, s
+ pos
, n
- pos
);
356 if (errno
== EINTR
|| errno
== EAGAIN
)
366 /* Write data with the assertion that it all has to be written, or
367 * else abort the process. Based on atomicio() from openssh. */
369 must_write(int fd
, void *buf
, size_t n
)
372 ssize_t res
, pos
= 0;
375 res
= write(fd
, s
+ pos
, n
- pos
);
378 if (errno
== EINTR
|| errno
== EAGAIN
)