diff options
author | Can Erkin Acar <canacar@cvs.openbsd.org> | 2004-05-06 17:49:09 +0000 |
---|---|---|
committer | Can Erkin Acar <canacar@cvs.openbsd.org> | 2004-05-06 17:49:09 +0000 |
commit | 710d3b1a5af1484944221ff6259ee05fcfa9089d (patch) | |
tree | 25928801388da9c288273dbd513fd9c2d6ae311e /usr.sbin | |
parent | d1c61d071c7e2ddf5856cc348e78001248359c7f (diff) |
pppoe now drops privileges to user _ppp and chroots after setting
write filters and locking its bpf descriptor. ok deraadt@
Diffstat (limited to 'usr.sbin')
-rw-r--r-- | usr.sbin/pppoe/pppoe.c | 179 |
1 files changed, 166 insertions, 13 deletions
diff --git a/usr.sbin/pppoe/pppoe.c b/usr.sbin/pppoe/pppoe.c index 79870c6998d..315a664d47f 100644 --- a/usr.sbin/pppoe/pppoe.c +++ b/usr.sbin/pppoe/pppoe.c @@ -1,4 +1,4 @@ -/* $OpenBSD: pppoe.c,v 1.11 2003/08/19 22:19:07 itojun Exp $ */ +/* $OpenBSD: pppoe.c,v 1.12 2004/05/06 17:49:08 canacar Exp $ */ /* * Copyright (c) 2000 Network Security Technologies, Inc. http://www.netsec.net @@ -42,6 +42,7 @@ #include <string.h> #include <err.h> #include <fcntl.h> +#include <pwd.h> #include <unistd.h> #include <sysexits.h> #include <stdlib.h> @@ -57,8 +58,11 @@ int main(int, char **); void usage(void); int getifhwaddr(char *, char *, struct ether_addr *); int setupfilter(char *, struct ether_addr *, int); +int setup_rfilter(struct bpf_insn *, struct ether_addr *, int); +int setup_wfilter(struct bpf_insn *, int); void child_handler(int); int signal_init(void); +void drop_privs(struct passwd *pw); int main(int argc, char **argv) { @@ -67,6 +71,10 @@ main(int argc, char **argv) { char ifnambuf[IFNAMSIZ]; struct ether_addr ea; int bpffd, smode = 0, c; + struct passwd *pw; + + if ((pw = getpwnam("_ppp")) == NULL) + err(EX_CONFIG, "getpwnam(\"_ppp\")"); while ((c = getopt(argc, argv, "svi:n:p:")) != -1) { switch (c) { @@ -120,6 +128,8 @@ main(int argc, char **argv) { if (bpffd < 0) return (EX_IOERR); + drop_privs(pw); + signal_init(); if (smode) @@ -130,22 +140,19 @@ main(int argc, char **argv) { return (0); } +#define MAX_INSNS 20 + +/* bpf read filter */ int -setupfilter(ifn, ea, server_mode) - char *ifn; +setup_rfilter(insns, ea, server_mode) + struct bpf_insn *insns; struct ether_addr *ea; int server_mode; { - char device[sizeof "/dev/bpf0000000000"]; u_int8_t *ep = (u_int8_t *)ea; - int fd, idx = 0; - u_int u, i; - struct ifreq ifr; - struct bpf_insn insns[20]; - struct bpf_program filter; - - idx = 0; + int idx = 0; + /* allow session or discovery packets */ insns[idx].code = BPF_LD | BPF_H | BPF_ABS; insns[idx].k = 12; insns[idx].jt = insns[idx].jf = 0; @@ -163,6 +170,7 @@ setupfilter(ifn, ea, server_mode) insns[idx].jf = 4; idx++; + /* reject packets containing our address as source */ insns[idx].code = BPF_LD | BPF_W | BPF_ABS; insns[idx].k = 6; insns[idx].jt = insns[idx].jf = 0; @@ -191,6 +199,7 @@ setupfilter(ifn, ea, server_mode) idx++; if (server_mode) { + /* if server mode, allow broadcast as destination */ insns[idx].code = BPF_LD | BPF_W | BPF_ABS; insns[idx].k = insns[idx].jt = insns[idx].jf = 0; idx++; @@ -213,6 +222,7 @@ setupfilter(ifn, ea, server_mode) idx++; } + /* make sure packet is destined to our addres */ insns[idx].code = BPF_LD | BPF_W | BPF_ABS; insns[idx].k = insns[idx].jt = insns[idx].jf = 0; idx++; @@ -244,8 +254,101 @@ setupfilter(ifn, ea, server_mode) insns[idx].k = insns[idx].jt = insns[idx].jf = 0; idx++; - filter.bf_len = idx; - filter.bf_insns = insns; + return idx; +} + +/* bpf write filter */ +int +setup_wfilter(insns, server_mode) + struct bpf_insn *insns; + int server_mode; +{ + int idx = 0; + + /* check if dest is broadcast */ + insns[idx].code = BPF_LD | BPF_W | BPF_ABS; + insns[idx].k = insns[idx].jt = insns[idx].jf = 0; + idx++; + + insns[idx].code = BPF_JMP | BPF_JEQ | BPF_K; + insns[idx].k = 0xffffffff; + insns[idx].jt = 0; + insns[idx].jf = 2; + idx++; + + insns[idx].code = BPF_LD | BPF_H | BPF_ABS; + insns[idx].k = 4; + insns[idx].jt = insns[idx].jf = 0; + idx++; + + insns[idx].code = BPF_JMP | BPF_JEQ | BPF_K; + insns[idx].k = 0xffff; + insns[idx].jt = 4; + insns[idx].jf = 0; + idx++; + + /* dest not broadcast, check type for session or discovery */ + insns[idx].code = BPF_LD | BPF_H | BPF_ABS; + insns[idx].k = 12; + insns[idx].jt = insns[idx].jf = 0; + idx++; + + insns[idx].code = BPF_JMP | BPF_JEQ | BPF_K; + insns[idx].k = ETHERTYPE_PPPOE; + insns[idx].jt = 1; + insns[idx].jf = 0; + idx++; + + insns[idx].code = BPF_JMP | BPF_JEQ | BPF_K; + insns[idx].k = ETHERTYPE_PPPOEDISC; + insns[idx].jt = 0; + insns[idx].jf = (server_mode) ? 1 : 4; + idx++; + + insns[idx].code = BPF_RET | BPF_K; + insns[idx].k = (u_int)-1; + insns[idx].jt = insns[idx].jf = 0; + idx++; + + /* packet is broadcast */ + if (! server_mode) { + /* only allowed for discovery in client mode */ + insns[idx].code = BPF_LD | BPF_H | BPF_ABS; + insns[idx].k = 12; + insns[idx].jt = insns[idx].jf = 0; + idx++; + + insns[idx].code = BPF_JMP | BPF_JEQ | BPF_K; + insns[idx].k = ETHERTYPE_PPPOEDISC; + insns[idx].jt = 0; + insns[idx].jf = 1; + idx++; + + insns[idx].code = BPF_RET | BPF_K; + insns[idx].k = (u_int)-1; + insns[idx].jt = insns[idx].jf = 0; + idx++; + } + + insns[idx].code = BPF_RET | BPF_K; + insns[idx].k = insns[idx].jt = insns[idx].jf = 0; + idx++; + + return idx; +} + +int +setupfilter(ifn, ea, server_mode) + char *ifn; + struct ether_addr *ea; + int server_mode; +{ + char device[sizeof "/dev/bpf0000000000"]; + int fd, idx = 0; + u_int u, i; + struct ifreq ifr; + struct bpf_insn insns[MAX_INSNS]; + struct bpf_program filter; for (i = 0; ; i++) { snprintf(device, sizeof(device), "/dev/bpf%d", i); @@ -283,11 +386,33 @@ setupfilter(ifn, ea, server_mode) if (u != DLT_EN10MB) err(EX_IOERR, "%s is not ethernet", ifn); + + idx = setup_rfilter(insns, ea, server_mode); + + filter.bf_len = idx; + filter.bf_insns = insns; + if (ioctl(fd, BIOCSETF, &filter) < 0) { close(fd); err(EX_IOERR, "BIOCSETF"); } + idx = setup_wfilter(insns, server_mode); + + filter.bf_len = idx; + filter.bf_insns = insns; + + if (ioctl(fd, BIOCSETWF, &filter) < 0) { + close(fd); + err(EX_IOERR, "BIOCSETWF"); + } + + /* lock the descriptor against changes */ + if (ioctl(fd, BIOCLOCK) < 0) { + close(fd); + err(EX_IOERR, "BIOCLOCK"); + } + return (fd); } @@ -383,3 +508,31 @@ signal_init(void) return (0); } + +void +drop_privs(struct passwd *pw) +{ + + if (chroot(pw->pw_dir) == -1) + err(EX_OSERR, "chroot: %s", pw->pw_dir); + + if (chdir("/") == -1) + err(EX_OSERR, "chdir"); + + if (setgroups(1, &pw->pw_gid)) + err(EX_OSERR, "setgroups"); + + if (setegid(pw->pw_gid)) + err(EX_OSERR, "setegid"); + + if (setgid(pw->pw_gid)) + err(EX_OSERR, "setgid"); + + if (seteuid(pw->pw_uid)) + err(EX_OSERR, "seteuid"); + + if (setuid(pw->pw_uid)) + err(EX_OSERR, "setuid"); + + endpwent(); +} |