10baf7c86SMax Laier /* $OpenBSD: privsep.c,v 1.13 2004/12/22 09:21:02 otto Exp $ */ 2abff3868SMax Laier 3abff3868SMax Laier /* 4abff3868SMax Laier * Copyright (c) 2003 Can Erkin Acar 5abff3868SMax Laier * Copyright (c) 2003 Anil Madhavapeddy <anil@recoil.org> 6abff3868SMax Laier * 7abff3868SMax Laier * Permission to use, copy, modify, and distribute this software for any 8abff3868SMax Laier * purpose with or without fee is hereby granted, provided that the above 9abff3868SMax Laier * copyright notice and this permission notice appear in all copies. 10abff3868SMax Laier * 11abff3868SMax Laier * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12abff3868SMax Laier * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13abff3868SMax Laier * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14abff3868SMax Laier * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15abff3868SMax Laier * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16abff3868SMax Laier * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17abff3868SMax Laier * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18abff3868SMax Laier */ 1922ac3eadSMax Laier 2022ac3eadSMax Laier #include <sys/cdefs.h> 2122ac3eadSMax Laier __FBSDID("$FreeBSD$"); 2222ac3eadSMax Laier 2322ac3eadSMax Laier #include <sys/param.h> 24abff3868SMax Laier #include <sys/time.h> 25abff3868SMax Laier #include <sys/socket.h> 26abff3868SMax Laier 27abff3868SMax Laier #include <net/if.h> 28abff3868SMax Laier #include <net/bpf.h> 29abff3868SMax Laier 30abff3868SMax Laier #include <err.h> 31abff3868SMax Laier #include <errno.h> 32abff3868SMax Laier #include <fcntl.h> 33abff3868SMax Laier #include <pwd.h> 34abff3868SMax Laier #include <signal.h> 35abff3868SMax Laier #include <stdio.h> 36abff3868SMax Laier #include <stdlib.h> 37abff3868SMax Laier #include <string.h> 3822ac3eadSMax Laier #include <pcap.h> 3922ac3eadSMax Laier #include <pcap-int.h> 40abff3868SMax Laier #include <syslog.h> 41abff3868SMax Laier #include <unistd.h> 42abff3868SMax Laier #include "pflogd.h" 43abff3868SMax Laier 44abff3868SMax Laier enum cmd_types { 45abff3868SMax Laier PRIV_SET_SNAPLEN, /* set the snaplength */ 46abff3868SMax Laier PRIV_OPEN_LOG /* open logfile for appending */ 47abff3868SMax Laier }; 48abff3868SMax Laier 49abff3868SMax Laier static int priv_fd = -1; 50abff3868SMax Laier static volatile pid_t child_pid = -1; 51abff3868SMax Laier 52abff3868SMax Laier volatile sig_atomic_t gotsig_chld = 0; 53abff3868SMax Laier 54abff3868SMax Laier static void sig_pass_to_chld(int); 55abff3868SMax Laier static void sig_chld(int); 56abff3868SMax Laier static int may_read(int, void *, size_t); 57abff3868SMax Laier static void must_read(int, void *, size_t); 58abff3868SMax Laier static void must_write(int, void *, size_t); 59abff3868SMax Laier static int set_snaplen(int snap); 60abff3868SMax Laier 61abff3868SMax Laier /* bpf filter expression common to parent and child */ 62abff3868SMax Laier extern char *filter; 63abff3868SMax Laier extern char *errbuf; 64abff3868SMax Laier extern char *filename; 65abff3868SMax Laier extern pcap_t *hpcap; 66abff3868SMax Laier 67abff3868SMax Laier /* based on syslogd privsep */ 68abff3868SMax Laier int 69abff3868SMax Laier priv_init(void) 70abff3868SMax Laier { 71abff3868SMax Laier int i, fd, socks[2], cmd; 720baf7c86SMax Laier int snaplen, ret, olderrno; 73abff3868SMax Laier struct passwd *pw; 74abff3868SMax Laier 7522ac3eadSMax Laier #ifdef __FreeBSD__ 7622ac3eadSMax Laier for (i = 1; i < NSIG; i++) 7722ac3eadSMax Laier #else 78abff3868SMax Laier for (i = 1; i < _NSIG; i++) 7922ac3eadSMax Laier #endif 80abff3868SMax Laier signal(i, SIG_DFL); 81abff3868SMax Laier 82abff3868SMax Laier /* Create sockets */ 83abff3868SMax Laier if (socketpair(AF_LOCAL, SOCK_STREAM, PF_UNSPEC, socks) == -1) 84abff3868SMax Laier err(1, "socketpair() failed"); 85abff3868SMax Laier 86abff3868SMax Laier pw = getpwnam("_pflogd"); 87abff3868SMax Laier if (pw == NULL) 88abff3868SMax Laier errx(1, "unknown user _pflogd"); 89abff3868SMax Laier endpwent(); 90abff3868SMax Laier 91abff3868SMax Laier child_pid = fork(); 92abff3868SMax Laier if (child_pid < 0) 93abff3868SMax Laier err(1, "fork() failed"); 94abff3868SMax Laier 95abff3868SMax Laier if (!child_pid) { 96abff3868SMax Laier gid_t gidset[1]; 97abff3868SMax Laier 98abff3868SMax Laier /* Child - drop privileges and return */ 99abff3868SMax Laier if (chroot(pw->pw_dir) != 0) 100abff3868SMax Laier err(1, "unable to chroot"); 101abff3868SMax Laier if (chdir("/") != 0) 102abff3868SMax Laier err(1, "unable to chdir"); 103abff3868SMax Laier 104abff3868SMax Laier gidset[0] = pw->pw_gid; 105abff3868SMax Laier if (setgroups(1, gidset) == -1) 106abff3868SMax Laier err(1, "setgroups() failed"); 107abff3868SMax Laier if (setegid(pw->pw_gid) == -1) 108abff3868SMax Laier err(1, "setegid() failed"); 109abff3868SMax Laier if (setgid(pw->pw_gid) == -1) 110abff3868SMax Laier err(1, "setgid() failed"); 111abff3868SMax Laier if (seteuid(pw->pw_uid) == -1) 112abff3868SMax Laier err(1, "seteuid() failed"); 113abff3868SMax Laier if (setuid(pw->pw_uid) == -1) 114abff3868SMax Laier err(1, "setuid() failed"); 115abff3868SMax Laier close(socks[0]); 116abff3868SMax Laier priv_fd = socks[1]; 117abff3868SMax Laier return 0; 118abff3868SMax Laier } 119abff3868SMax Laier 120abff3868SMax Laier /* Father */ 1210baf7c86SMax Laier /* Pass ALRM/TERM/HUP/INT/QUIT through to child, and accept CHLD */ 122abff3868SMax Laier signal(SIGALRM, sig_pass_to_chld); 123abff3868SMax Laier signal(SIGTERM, sig_pass_to_chld); 124abff3868SMax Laier signal(SIGHUP, sig_pass_to_chld); 1250baf7c86SMax Laier signal(SIGINT, sig_pass_to_chld); 1260baf7c86SMax Laier signal(SIGQUIT, sig_pass_to_chld); 127abff3868SMax Laier signal(SIGCHLD, sig_chld); 128abff3868SMax Laier 129abff3868SMax Laier setproctitle("[priv]"); 130abff3868SMax Laier close(socks[1]); 131abff3868SMax Laier 132abff3868SMax Laier while (!gotsig_chld) { 133abff3868SMax Laier if (may_read(socks[0], &cmd, sizeof(int))) 134abff3868SMax Laier break; 135abff3868SMax Laier switch (cmd) { 136abff3868SMax Laier case PRIV_SET_SNAPLEN: 137abff3868SMax Laier logmsg(LOG_DEBUG, 138abff3868SMax Laier "[priv]: msg PRIV_SET_SNAPLENGTH received"); 139abff3868SMax Laier must_read(socks[0], &snaplen, sizeof(int)); 140abff3868SMax Laier 141abff3868SMax Laier ret = set_snaplen(snaplen); 142abff3868SMax Laier if (ret) { 143abff3868SMax Laier logmsg(LOG_NOTICE, 144abff3868SMax Laier "[priv]: set_snaplen failed for snaplen %d", 145abff3868SMax Laier snaplen); 146abff3868SMax Laier } 147abff3868SMax Laier 148abff3868SMax Laier must_write(socks[0], &ret, sizeof(int)); 149abff3868SMax Laier break; 150abff3868SMax Laier 151abff3868SMax Laier case PRIV_OPEN_LOG: 152abff3868SMax Laier logmsg(LOG_DEBUG, 153abff3868SMax Laier "[priv]: msg PRIV_OPEN_LOG received"); 154abff3868SMax Laier /* create or append logs but do not follow symlinks */ 155abff3868SMax Laier fd = open(filename, 156abff3868SMax Laier O_RDWR|O_CREAT|O_APPEND|O_NONBLOCK|O_NOFOLLOW, 157abff3868SMax Laier 0600); 1580baf7c86SMax Laier olderrno = errno; 1590baf7c86SMax Laier send_fd(socks[0], fd); 160abff3868SMax Laier if (fd < 0) 161abff3868SMax Laier logmsg(LOG_NOTICE, 162abff3868SMax Laier "[priv]: failed to open %s: %s", 1630baf7c86SMax Laier filename, strerror(olderrno)); 1640baf7c86SMax Laier else 165abff3868SMax Laier close(fd); 166abff3868SMax Laier break; 167abff3868SMax Laier 168abff3868SMax Laier default: 169abff3868SMax Laier logmsg(LOG_ERR, "[priv]: unknown command %d", cmd); 170abff3868SMax Laier _exit(1); 171abff3868SMax Laier /* NOTREACHED */ 172abff3868SMax Laier } 173abff3868SMax Laier } 174abff3868SMax Laier 175abff3868SMax Laier _exit(1); 176abff3868SMax Laier } 177abff3868SMax Laier 178abff3868SMax Laier /* this is called from parent */ 179abff3868SMax Laier static int 180abff3868SMax Laier set_snaplen(int snap) 181abff3868SMax Laier { 182abff3868SMax Laier if (hpcap == NULL) 183abff3868SMax Laier return (1); 184abff3868SMax Laier 185abff3868SMax Laier hpcap->snapshot = snap; 186abff3868SMax Laier set_pcap_filter(); 187abff3868SMax Laier 188abff3868SMax Laier return 0; 189abff3868SMax Laier } 190abff3868SMax Laier 191abff3868SMax Laier 192abff3868SMax Laier /* 193abff3868SMax Laier * send the snaplength to privileged process 194abff3868SMax Laier */ 195abff3868SMax Laier int 196abff3868SMax Laier priv_set_snaplen(int snaplen) 197abff3868SMax Laier { 198abff3868SMax Laier int cmd, ret; 199abff3868SMax Laier 200abff3868SMax Laier if (priv_fd < 0) 201abff3868SMax Laier errx(1, "%s: called from privileged portion", __func__); 202abff3868SMax Laier 203abff3868SMax Laier cmd = PRIV_SET_SNAPLEN; 204abff3868SMax Laier 205abff3868SMax Laier must_write(priv_fd, &cmd, sizeof(int)); 206abff3868SMax Laier must_write(priv_fd, &snaplen, sizeof(int)); 207abff3868SMax Laier 208abff3868SMax Laier must_read(priv_fd, &ret, sizeof(int)); 209abff3868SMax Laier 210abff3868SMax Laier /* also set hpcap->snapshot in child */ 211abff3868SMax Laier if (ret == 0) 212abff3868SMax Laier hpcap->snapshot = snaplen; 213abff3868SMax Laier 214abff3868SMax Laier return (ret); 215abff3868SMax Laier } 216abff3868SMax Laier 217abff3868SMax Laier /* Open log-file */ 218abff3868SMax Laier int 219abff3868SMax Laier priv_open_log(void) 220abff3868SMax Laier { 221abff3868SMax Laier int cmd, fd; 222abff3868SMax Laier 223abff3868SMax Laier if (priv_fd < 0) 2240baf7c86SMax Laier errx(1, "%s: called from privileged portion", __func__); 225abff3868SMax Laier 226abff3868SMax Laier cmd = PRIV_OPEN_LOG; 227abff3868SMax Laier must_write(priv_fd, &cmd, sizeof(int)); 228abff3868SMax Laier fd = receive_fd(priv_fd); 229abff3868SMax Laier 230abff3868SMax Laier return (fd); 231abff3868SMax Laier } 232abff3868SMax Laier 233abff3868SMax Laier /* If priv parent gets a TERM or HUP, pass it through to child instead */ 234abff3868SMax Laier static void 235abff3868SMax Laier sig_pass_to_chld(int sig) 236abff3868SMax Laier { 237abff3868SMax Laier int oerrno = errno; 238abff3868SMax Laier 239abff3868SMax Laier if (child_pid != -1) 240abff3868SMax Laier kill(child_pid, sig); 241abff3868SMax Laier errno = oerrno; 242abff3868SMax Laier } 243abff3868SMax Laier 244abff3868SMax Laier /* if parent gets a SIGCHLD, it will exit */ 245abff3868SMax Laier static void 246abff3868SMax Laier sig_chld(int sig) 247abff3868SMax Laier { 248abff3868SMax Laier gotsig_chld = 1; 249abff3868SMax Laier } 250abff3868SMax Laier 251abff3868SMax Laier /* Read all data or return 1 for error. */ 252abff3868SMax Laier static int 253abff3868SMax Laier may_read(int fd, void *buf, size_t n) 254abff3868SMax Laier { 255abff3868SMax Laier char *s = buf; 256abff3868SMax Laier ssize_t res, pos = 0; 257abff3868SMax Laier 258abff3868SMax Laier while (n > pos) { 259abff3868SMax Laier res = read(fd, s + pos, n - pos); 260abff3868SMax Laier switch (res) { 261abff3868SMax Laier case -1: 262abff3868SMax Laier if (errno == EINTR || errno == EAGAIN) 263abff3868SMax Laier continue; 264abff3868SMax Laier case 0: 265abff3868SMax Laier return (1); 266abff3868SMax Laier default: 267abff3868SMax Laier pos += res; 268abff3868SMax Laier } 269abff3868SMax Laier } 270abff3868SMax Laier return (0); 271abff3868SMax Laier } 272abff3868SMax Laier 273abff3868SMax Laier /* Read data with the assertion that it all must come through, or 274abff3868SMax Laier * else abort the process. Based on atomicio() from openssh. */ 275abff3868SMax Laier static void 276abff3868SMax Laier must_read(int fd, void *buf, size_t n) 277abff3868SMax Laier { 278abff3868SMax Laier char *s = buf; 279abff3868SMax Laier ssize_t res, pos = 0; 280abff3868SMax Laier 281abff3868SMax Laier while (n > pos) { 282abff3868SMax Laier res = read(fd, s + pos, n - pos); 283abff3868SMax Laier switch (res) { 284abff3868SMax Laier case -1: 285abff3868SMax Laier if (errno == EINTR || errno == EAGAIN) 286abff3868SMax Laier continue; 287abff3868SMax Laier case 0: 288abff3868SMax Laier _exit(0); 289abff3868SMax Laier default: 290abff3868SMax Laier pos += res; 291abff3868SMax Laier } 292abff3868SMax Laier } 293abff3868SMax Laier } 294abff3868SMax Laier 295abff3868SMax Laier /* Write data with the assertion that it all has to be written, or 296abff3868SMax Laier * else abort the process. Based on atomicio() from openssh. */ 297abff3868SMax Laier static void 298abff3868SMax Laier must_write(int fd, void *buf, size_t n) 299abff3868SMax Laier { 300abff3868SMax Laier char *s = buf; 301abff3868SMax Laier ssize_t res, pos = 0; 302abff3868SMax Laier 303abff3868SMax Laier while (n > pos) { 304abff3868SMax Laier res = write(fd, s + pos, n - pos); 305abff3868SMax Laier switch (res) { 306abff3868SMax Laier case -1: 307abff3868SMax Laier if (errno == EINTR || errno == EAGAIN) 308abff3868SMax Laier continue; 309abff3868SMax Laier case 0: 310abff3868SMax Laier _exit(0); 311abff3868SMax Laier default: 312abff3868SMax Laier pos += res; 313abff3868SMax Laier } 314abff3868SMax Laier } 315abff3868SMax Laier } 316