1abff3868SMax Laier /* $OpenBSD: privsep.c,v 1.8 2004/03/14 19:17:05 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; 72abff3868SMax Laier int snaplen, ret; 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 */ 121abff3868SMax Laier /* Pass ALRM/TERM/HUP 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); 125abff3868SMax Laier signal(SIGCHLD, sig_chld); 126abff3868SMax Laier 127abff3868SMax Laier setproctitle("[priv]"); 128abff3868SMax Laier close(socks[1]); 129abff3868SMax Laier 130abff3868SMax Laier while (!gotsig_chld) { 131abff3868SMax Laier if (may_read(socks[0], &cmd, sizeof(int))) 132abff3868SMax Laier break; 133abff3868SMax Laier switch (cmd) { 134abff3868SMax Laier case PRIV_SET_SNAPLEN: 135abff3868SMax Laier logmsg(LOG_DEBUG, 136abff3868SMax Laier "[priv]: msg PRIV_SET_SNAPLENGTH received"); 137abff3868SMax Laier must_read(socks[0], &snaplen, sizeof(int)); 138abff3868SMax Laier 139abff3868SMax Laier ret = set_snaplen(snaplen); 140abff3868SMax Laier if (ret) { 141abff3868SMax Laier logmsg(LOG_NOTICE, 142abff3868SMax Laier "[priv]: set_snaplen failed for snaplen %d", 143abff3868SMax Laier snaplen); 144abff3868SMax Laier } 145abff3868SMax Laier 146abff3868SMax Laier must_write(socks[0], &ret, sizeof(int)); 147abff3868SMax Laier break; 148abff3868SMax Laier 149abff3868SMax Laier case PRIV_OPEN_LOG: 150abff3868SMax Laier logmsg(LOG_DEBUG, 151abff3868SMax Laier "[priv]: msg PRIV_OPEN_LOG received"); 152abff3868SMax Laier /* create or append logs but do not follow symlinks */ 153abff3868SMax Laier fd = open(filename, 154abff3868SMax Laier O_RDWR|O_CREAT|O_APPEND|O_NONBLOCK|O_NOFOLLOW, 155abff3868SMax Laier 0600); 156abff3868SMax Laier if (fd < 0) 157abff3868SMax Laier logmsg(LOG_NOTICE, 158abff3868SMax Laier "[priv]: failed to open %s: %s", 159abff3868SMax Laier filename, strerror(errno)); 160abff3868SMax Laier send_fd(socks[0], fd); 161abff3868SMax Laier close(fd); 162abff3868SMax Laier break; 163abff3868SMax Laier 164abff3868SMax Laier default: 165abff3868SMax Laier logmsg(LOG_ERR, "[priv]: unknown command %d", cmd); 166abff3868SMax Laier _exit(1); 167abff3868SMax Laier /* NOTREACHED */ 168abff3868SMax Laier } 169abff3868SMax Laier } 170abff3868SMax Laier 171abff3868SMax Laier _exit(1); 172abff3868SMax Laier } 173abff3868SMax Laier 174abff3868SMax Laier /* this is called from parent */ 175abff3868SMax Laier static int 176abff3868SMax Laier set_snaplen(int snap) 177abff3868SMax Laier { 178abff3868SMax Laier if (hpcap == NULL) 179abff3868SMax Laier return (1); 180abff3868SMax Laier 181abff3868SMax Laier hpcap->snapshot = snap; 182abff3868SMax Laier set_pcap_filter(); 183abff3868SMax Laier 184abff3868SMax Laier return 0; 185abff3868SMax Laier } 186abff3868SMax Laier 187abff3868SMax Laier 188abff3868SMax Laier /* 189abff3868SMax Laier * send the snaplength to privileged process 190abff3868SMax Laier */ 191abff3868SMax Laier int 192abff3868SMax Laier priv_set_snaplen(int snaplen) 193abff3868SMax Laier { 194abff3868SMax Laier int cmd, ret; 195abff3868SMax Laier 196abff3868SMax Laier if (priv_fd < 0) 197abff3868SMax Laier errx(1, "%s: called from privileged portion", __func__); 198abff3868SMax Laier 199abff3868SMax Laier cmd = PRIV_SET_SNAPLEN; 200abff3868SMax Laier 201abff3868SMax Laier must_write(priv_fd, &cmd, sizeof(int)); 202abff3868SMax Laier must_write(priv_fd, &snaplen, sizeof(int)); 203abff3868SMax Laier 204abff3868SMax Laier must_read(priv_fd, &ret, sizeof(int)); 205abff3868SMax Laier 206abff3868SMax Laier /* also set hpcap->snapshot in child */ 207abff3868SMax Laier if (ret == 0) 208abff3868SMax Laier hpcap->snapshot = snaplen; 209abff3868SMax Laier 210abff3868SMax Laier return (ret); 211abff3868SMax Laier } 212abff3868SMax Laier 213abff3868SMax Laier /* Open log-file */ 214abff3868SMax Laier int 215abff3868SMax Laier priv_open_log(void) 216abff3868SMax Laier { 217abff3868SMax Laier int cmd, fd; 218abff3868SMax Laier 219abff3868SMax Laier if (priv_fd < 0) 220abff3868SMax Laier errx(1, "%s: called from privileged portion\n", __func__); 221abff3868SMax Laier 222abff3868SMax Laier cmd = PRIV_OPEN_LOG; 223abff3868SMax Laier must_write(priv_fd, &cmd, sizeof(int)); 224abff3868SMax Laier fd = receive_fd(priv_fd); 225abff3868SMax Laier 226abff3868SMax Laier return (fd); 227abff3868SMax Laier } 228abff3868SMax Laier 229abff3868SMax Laier /* If priv parent gets a TERM or HUP, pass it through to child instead */ 230abff3868SMax Laier static void 231abff3868SMax Laier sig_pass_to_chld(int sig) 232abff3868SMax Laier { 233abff3868SMax Laier int oerrno = errno; 234abff3868SMax Laier 235abff3868SMax Laier if (child_pid != -1) 236abff3868SMax Laier kill(child_pid, sig); 237abff3868SMax Laier errno = oerrno; 238abff3868SMax Laier } 239abff3868SMax Laier 240abff3868SMax Laier /* if parent gets a SIGCHLD, it will exit */ 241abff3868SMax Laier static void 242abff3868SMax Laier sig_chld(int sig) 243abff3868SMax Laier { 244abff3868SMax Laier gotsig_chld = 1; 245abff3868SMax Laier } 246abff3868SMax Laier 247abff3868SMax Laier /* Read all data or return 1 for error. */ 248abff3868SMax Laier static int 249abff3868SMax Laier may_read(int fd, void *buf, size_t n) 250abff3868SMax Laier { 251abff3868SMax Laier char *s = buf; 252abff3868SMax Laier ssize_t res, pos = 0; 253abff3868SMax Laier 254abff3868SMax Laier while (n > pos) { 255abff3868SMax Laier res = read(fd, s + pos, n - pos); 256abff3868SMax Laier switch (res) { 257abff3868SMax Laier case -1: 258abff3868SMax Laier if (errno == EINTR || errno == EAGAIN) 259abff3868SMax Laier continue; 260abff3868SMax Laier case 0: 261abff3868SMax Laier return (1); 262abff3868SMax Laier default: 263abff3868SMax Laier pos += res; 264abff3868SMax Laier } 265abff3868SMax Laier } 266abff3868SMax Laier return (0); 267abff3868SMax Laier } 268abff3868SMax Laier 269abff3868SMax Laier /* Read data with the assertion that it all must come through, or 270abff3868SMax Laier * else abort the process. Based on atomicio() from openssh. */ 271abff3868SMax Laier static void 272abff3868SMax Laier must_read(int fd, void *buf, size_t n) 273abff3868SMax Laier { 274abff3868SMax Laier char *s = buf; 275abff3868SMax Laier ssize_t res, pos = 0; 276abff3868SMax Laier 277abff3868SMax Laier while (n > pos) { 278abff3868SMax Laier res = read(fd, s + pos, n - pos); 279abff3868SMax Laier switch (res) { 280abff3868SMax Laier case -1: 281abff3868SMax Laier if (errno == EINTR || errno == EAGAIN) 282abff3868SMax Laier continue; 283abff3868SMax Laier case 0: 284abff3868SMax Laier _exit(0); 285abff3868SMax Laier default: 286abff3868SMax Laier pos += res; 287abff3868SMax Laier } 288abff3868SMax Laier } 289abff3868SMax Laier } 290abff3868SMax Laier 291abff3868SMax Laier /* Write data with the assertion that it all has to be written, or 292abff3868SMax Laier * else abort the process. Based on atomicio() from openssh. */ 293abff3868SMax Laier static void 294abff3868SMax Laier must_write(int fd, void *buf, size_t n) 295abff3868SMax Laier { 296abff3868SMax Laier char *s = buf; 297abff3868SMax Laier ssize_t res, pos = 0; 298abff3868SMax Laier 299abff3868SMax Laier while (n > pos) { 300abff3868SMax Laier res = write(fd, s + pos, n - pos); 301abff3868SMax Laier switch (res) { 302abff3868SMax Laier case -1: 303abff3868SMax Laier if (errno == EINTR || errno == EAGAIN) 304abff3868SMax Laier continue; 305abff3868SMax Laier case 0: 306abff3868SMax Laier _exit(0); 307abff3868SMax Laier default: 308abff3868SMax Laier pos += res; 309abff3868SMax Laier } 310abff3868SMax Laier } 311abff3868SMax Laier } 312