summaryrefslogtreecommitdiff
path: root/usr.sbin
diff options
context:
space:
mode:
authorCan Erkin Acar <canacar@cvs.openbsd.org>2004-05-06 17:49:09 +0000
committerCan Erkin Acar <canacar@cvs.openbsd.org>2004-05-06 17:49:09 +0000
commit710d3b1a5af1484944221ff6259ee05fcfa9089d (patch)
tree25928801388da9c288273dbd513fd9c2d6ae311e /usr.sbin
parentd1c61d071c7e2ddf5856cc348e78001248359c7f (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.c179
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();
+}