Subject: allowing unpriv users to bind to priv ports
To: None <tech-kern@netbsd.org>
From: Joe Reed <jnr@po.cwru.edu>
List: tech-kern
Date: 09/25/2002 15:26:51
--------------Boundary-00=_R0E0V6F8GI09TRS3UL8Z
Content-Type: text/plain;
  charset="us-ascii"
Content-Transfer-Encoding: 8bit

hi all,

i've been working on a utility to allow unprivilaged users to bind to 
privilaged ports on a per user/group basis.  the rules are similiar to ipf 
rules and allow for daemons to be run as unprivilaged users, but still bind 
to the proper port (without losing any restriction for any other user), with 
a specific protocol.  these rules only work for ports less than the reserved 
port.  and superuser is always allowed to bind, regardless of rules.

the ports that have rules are stored in a linked list, with their rules in a 
set of lists as well (allow and deny).  i used the linked lists for 
simplicity and proof of concept.  still lookup time is (worst case) O(p+a) 
for allow and O(p+d) for deny case.  where p = number of ports that have 
rules, a,d= number of allow,deny rules respectively.  so if there is no rule 
for that user/group on that port, the worst possible search time is O(p+d+a).  
which is not too horrible.

i've modified netinet/in_pcb.c and netinet6/in6_pcb.c to check in this 
fashion.

i placed the kernel code in sys/net/ because i felt that it was more closely 
tied to the network.  and the userland code in usr.sbin/sfilter/.  if it 
should go elsewhere, please let me know.

i have not tied this into the rc scripts yet, because i'm not sure on a few 
things:
	1) how early the rules should get loaded (i think early, before any net 
daemons start, perhaps around the time of ipf)
	2) exactly how to tie in the startup.

i've attched a diff of my changes.  it's from my own personal cvs repository, 
but it only differs from anoncvs's -current in what's listed here.  i've 
imported this morning's src before creating the diff.

please let me know what you think.  i'd like to get this as good as possible 
before i send-pr it.

--joe
--------------Boundary-00=_R0E0V6F8GI09TRS3UL8Z
Content-Type: text/x-diff;
  charset="us-ascii";
  name="log.diff"
Content-Transfer-Encoding: 7bit
Content-Disposition: attachment; filename="log.diff"

Index: lib/libc/sys/Makefile.inc
===================================================================
RCS file: /cvsroot/NetBSD/current/lib/libc/sys/Makefile.inc,v
retrieving revision 1.1.1.3
diff -u -r1.1.1.3 Makefile.inc
--- lib/libc/sys/Makefile.inc	2002/09/25 17:15:00	1.1.1.3
+++ lib/libc/sys/Makefile.inc	2002/09/25 18:49:07
@@ -64,7 +64,8 @@
 	sendto.S setegid.S seteuid.S setgid.S setgroups.S setitimer.S \
 	setpgid.S setpriority.S setregid.S setreuid.S setrlimit.S \
 	setsid.S setsockopt.S setuid.S \
-	__shmctl13.S shmdt.S shmget.S shutdown.S \
+	__shmctl13.S shmdt.S shmget.S shutdown.S sfilter_insrule.S \
+	sfilter_clrrule.S \
 	__sigaltstack14.S __sigpending14.S __sigprocmask14.S __sigsuspend14.S \
 	__sigaction_sigtramp.S socket.S socketpair.S __stat13.S statfs.S \
 	swapctl.S symlink.S umask.S undelete.S unlink.S \
Index: sys/conf/files
===================================================================
RCS file: /cvsroot/NetBSD/current/sys/conf/files,v
retrieving revision 1.1.1.3
diff -u -r1.1.1.3 files
--- sys/conf/files	2002/09/25 17:13:09	1.1.1.3
+++ sys/conf/files	2002/09/25 18:49:37
@@ -1162,6 +1162,8 @@
 file	net/route.c
 file	net/rtsock.c
 file	net/slcompress.c		sl | ppp | strip | irip
+file	net/sfilter.c
+file	net/sfilter_syscalls.c
 file	net/zlib.c			(ppp & ppp_deflate) | ipsec
 file	netatalk/aarp.c			netatalk
 file	netatalk/at_control.c		netatalk
Index: sys/kern/init_main.c
===================================================================
RCS file: /cvsroot/NetBSD/current/sys/kern/init_main.c,v
retrieving revision 1.1.1.2
retrieving revision 1.3
diff -u -r1.1.1.2 -r1.3
--- sys/kern/init_main.c	2002/09/22 16:35:50	1.1.1.2
+++ sys/kern/init_main.c	2002/09/22 22:31:21	1.3
@@ -119,6 +119,9 @@
 #include <dev/cons.h>
 
 #include <net/if.h>
+#ifdef SOCKFILTER
+#include <net/sfilter.h>
+#endif
 #include <net/raw_cb.h>
 
 const char copyright[] =
@@ -521,6 +524,15 @@
 #ifndef PIPE_SOCKETPAIR
 	/* Initialize pipe structures */
 	pipe_init();
+#endif
+
+	/*
+	 * initialize sockfilter
+	 */
+#ifdef SOCKFILTER
+	printf("sfilter initialize . . . ");
+	sfilter_init();
+	printf("done.\n");
 #endif
 
 	/*
Index: sys/kern/init_sysent.c
===================================================================
RCS file: /cvsroot/NetBSD/current/sys/kern/init_sysent.c,v
retrieving revision 1.1.1.2
retrieving revision 1.3
diff -u -r1.1.1.2 -r1.3
--- sys/kern/init_sysent.c	2002/09/22 16:35:50	1.1.1.2
+++ sys/kern/init_sysent.c	2002/09/22 22:31:21	1.3
@@ -1,4 +1,4 @@
-/* $NetBSD: init_sysent.c,v 1.133 2002/09/04 07:46:25 jdolecek Exp $ */
+/* $NetBSD$ */
 
 /*
  * System call switch table.
@@ -8,7 +8,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: init_sysent.c,v 1.133 2002/09/04 07:46:25 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD$");
 
 #include "opt_ktrace.h"
 #include "opt_nfsserver.h"
@@ -468,10 +468,17 @@
 	{ 0, 0, 0,
 	    sys_nosys },			/* 176 = excluded ntp_adjtime */
 #endif
+#if defined(SOCKFILTER)
+	{ 3, s(struct sys_sfilter_insrule_args), 0,
+	    sys_sfilter_insrule },		/* 177 = sfilter_insrule */
+	{ 1, s(struct sys_sfilter_clrrule_args), 0,
+	    sys_sfilter_clrrule },		/* 178 = sfilter_clrrule */
+#else
 	{ 0, 0, 0,
 	    sys_nosys },			/* 177 = unimplemented */
 	{ 0, 0, 0,
 	    sys_nosys },			/* 178 = unimplemented */
+#endif
 	{ 0, 0, 0,
 	    sys_nosys },			/* 179 = unimplemented */
 	{ 0, 0, 0,
Index: sys/kern/syscalls.c
===================================================================
RCS file: /cvsroot/NetBSD/current/sys/kern/syscalls.c,v
retrieving revision 1.1.1.2
retrieving revision 1.3
diff -u -r1.1.1.2 -r1.3
--- sys/kern/syscalls.c	2002/09/22 16:35:52	1.1.1.2
+++ sys/kern/syscalls.c	2002/09/22 22:31:21	1.3
@@ -1,4 +1,4 @@
-/* $NetBSD: syscalls.c,v 1.128 2002/09/04 07:46:25 jdolecek Exp $ */
+/* $NetBSD$ */
 
 /*
  * System call names.
@@ -8,7 +8,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: syscalls.c,v 1.128 2002/09/04 07:46:25 jdolecek Exp $");
+__KERNEL_RCSID(0, "$NetBSD$");
 
 #if defined(_KERNEL_OPT)
 #include "opt_ktrace.h"
@@ -240,8 +240,13 @@
 #else
 	"#176 (excluded ntp_adjtime)",		/* 176 = excluded ntp_adjtime */
 #endif
+#if defined(SOCKFILTER)
+	"sfilter_insrule",			/* 177 = sfilter_insrule */
+	"sfilter_clrrule",			/* 178 = sfilter_clrrule */
+#else
 	"#177 (unimplemented)",		/* 177 = unimplemented */
 	"#178 (unimplemented)",		/* 178 = unimplemented */
+#endif
 	"#179 (unimplemented)",		/* 179 = unimplemented */
 	"#180 (unimplemented)",		/* 180 = unimplemented */
 	"setgid",			/* 181 = setgid */
Index: sys/kern/syscalls.master
===================================================================
RCS file: /cvsroot/NetBSD/current/sys/kern/syscalls.master,v
retrieving revision 1.1.1.2
retrieving revision 1.5
diff -u -r1.1.1.2 -r1.5
--- sys/kern/syscalls.master	2002/09/22 16:35:52	1.1.1.2
+++ sys/kern/syscalls.master	2002/09/22 22:31:21	1.5
@@ -364,8 +364,13 @@
 #else
 176	EXCL		ntp_adjtime
 #endif
-177	UNIMPL
-178	UNIMPL
+#if defined(SOCKFILTER)
+177	STD	{ int sys_sfilter_insrule(uint16_t port, void *rule, int8_t type);}
+178 STD { int sys_sfilter_clrrule(uint16_t port); }
+#else
+177 UNIMPL
+178 UNIMPL
+#endif
 179	UNIMPL
 180	UNIMPL
 
Index: sys/net/Makefile
===================================================================
RCS file: /cvsroot/NetBSD/current/sys/net/Makefile,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- sys/net/Makefile	2002/08/15 16:17:51	1.1.1.1
+++ sys/net/Makefile	2002/08/27 23:47:39	1.2
@@ -9,6 +9,6 @@
 	if_ppp.h if_pppvar.h if_pppoe.h if_slvar.h if_sppp.h if_stf.h \
 	if_stripvar.h if_token.h if_tun.h if_types.h if_vlanvar.h \
 	netisr.h pfil.h pfkeyv2.h ppp-comp.h ppp_defs.h radix.h \
-	raw_cb.h route.h slcompress.h slip.h zlib.h
+	raw_cb.h route.h sfilter.h slcompress.h slip.h zlib.h
 
 .include <bsd.kinc.mk>
Index: sys/net/sfilter.c
===================================================================
RCS file: sfilter.c
diff -N sfilter.c
--- /dev/null	Wed Sep 25 14:55:07 2002
+++ /tmp/cvs18091aw	Wed Sep 25 14:56:29 2002
@@ -0,0 +1,130 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2000, 2001, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *        This product includes software developed by the NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: sfilter.c $");
+
+#include <net/sfilter.h>
+
+#include <sys/malloc.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <sys/errno.h>
+#include <sys/systm.h>
+#include <sys/queue.h>
+
+struct rule_list rule_list_head =
+	SLIST_HEAD_INITIALIZER (rule_list_head);
+
+struct rule_list *rlist;
+
+/*
+ * initializes the data structures
+ */
+int
+sfilter_init(void)
+{
+	rlist = &rule_list_head;
+
+	if (rlist == 0)
+		/* XXX should i printf() && return instead??? */
+		panic ("sockfilter: malloc() failed");
+
+	/* initialize the list head */
+	SLIST_INIT((struct rule_list *)rlist);
+
+	return (0);
+}
+
+/*
+ * determine if the user/group is allowed to bind to the port or not
+ */
+int
+sfilter_isallowed(port, p, flags, privmax)
+	uint16_t port;
+	struct proc *p;
+	uint16_t flags;
+	uint16_t privmax;
+{
+	struct rule_list_entry *entry;
+	struct rule_slist_entry *sptr;
+
+ 	/* first, i deal with the easy cases (port unrestricted, or suser privs*/
+	if (port >= privmax || suser(p->p_ucred,&p->p_acflag) == 0)
+		return (1);
+
+	/* easy part done, now to find the port's entry in our list */
+	SFILTER_FIND_PORT(port,entry);
+	
+	if (entry != NULL) {
+		SLIST_FOREACH(sptr,entry->deny,next) {
+			if (SFILTER_PROT_TYPE(sptr->rule.flags) & flags ) { /*protocol*/
+				if (sptr->rule.flags & SFILTER_CHKUID) {		/*chk uid*/
+					if (sptr->rule.uid == p->p_ucred->cr_uid) {
+						if (sptr->rule.flags & SFILTER_CHKGID) { /*if both*/
+							if (groupmember(sptr->rule.gid,p->p_ucred))
+								return (0);
+						} else							/*only uid*/
+							return (0);
+					}
+				} else if (sptr->rule.flags & SFILTER_CHKGID) {
+					if (groupmember(sptr->rule.gid,p->p_ucred))
+						return (0);
+				}
+			}
+		} /*end deny list loop*/
+	
+		SLIST_FOREACH(sptr,entry->allow,next) {
+			if (SFILTER_PROT_TYPE(sptr->rule.flags) & flags ) { /*protocol*/
+				if (sptr->rule.flags & SFILTER_ALLOWALL)
+					return (1);
+				else if (sptr->rule.flags & SFILTER_CHKUID) {		/*chk uid*/
+					if (sptr->rule.uid == p->p_ucred->cr_uid) {
+						if (sptr->rule.flags & SFILTER_CHKGID) { /*if both*/
+							if (groupmember(sptr->rule.gid,p->p_ucred))
+								return (1);
+						} else							/*only uid*/
+							return (1);
+					}
+				} else if (sptr->rule.flags & SFILTER_CHKGID) {
+					if (groupmember(sptr->rule.gid,p->p_ucred))
+						return (1);
+				}
+			}
+		} /*end allow list loop*/				  
+	}
+
+	return (0); /*default to deny */
+}
Index: sys/net/sfilter.h
===================================================================
RCS file: sfilter.h
diff -N sfilter.h
--- /dev/null	Wed Sep 25 14:55:07 2002
+++ /tmp/cvs18091ax	Wed Sep 25 14:56:29 2002
@@ -0,0 +1,212 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2000, 2001, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *        This product includes software developed by the NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * public interfaces to socketfilter.  by Joe Reed
+ */
+
+#ifndef _NET_SFILTER_H_ 
+#define _NET_SFILTER_H_
+
+#include <sys/types.h>
+
+/*
+ * needed both in and out of kernel
+ */
+
+/* flags */
+#define SFILTER_PROT_TCP		0x0001 /* rule applies to tcp/ip */
+#define SFILTER_PROT_UDP		0x0002 /* rule applies to udp */
+#define SFILTER_PROT_ICMP	0x0004 /* rule applies to tcmp */
+#define SFILTER_PROT_ALL		(SFILTER_PROT_TCP|SFILTER_PROT_UDP|SFILTER_PROT_ICMP)
+#define SFILTER_PROT_MASK	0x0007
+
+/* bits 0x00f8 not used yet */
+
+#define SFILTER_IPV4			0x0100 /* ip version 4 */
+#define SFILTER_IPV6			0x0200 /* ip version 6 */
+#define SFILTER_IPALL		(SFILTER_IPV4 | SFILTER_IPV6) 
+
+/* bits 0x0c00 not used yet */
+
+#define SFILTER_CHKUID		0x1000 /* check the user id */
+#define SFILTER_CHKGID		0x2000 /* check the group id */
+#define SFILTER_ALLOWALL	0x4000 /* allow all users and groups */
+#define SFILTER_CHKMASK		(SFILTER_CHKUID | SFILTER_CHKGID | SFILTER_ALLOWALL)
+
+
+/* useful macros for flags */
+#define SFILTER_IPVERSION(x) (x & SFILTER_IPALL)
+#define SFILTER_PROT_TYPE(x) (x & SFILTER_PROT_MASK)
+
+/* rule types */
+#define SFILTER_ALLOWRULE	0x10 /* rule allows connections */
+#define SFILTER_DENYRULE		0x20 /* rule deny's connections */
+#define SFILTER_TYPEMASK		0x30
+
+struct sfilter_rule {
+	uid_t uid;
+	gid_t gid;
+	u_int16_t flags;
+};
+
+/*
+ * only needed in-kernel
+ */
+#ifdef _KERNEL
+//XXX #include <netinet/in.h> /* XXX should this go here or on top? */
+#include <sys/param.h>
+#include <sys/proc.h>
+#include <sys/queue.h>
+
+/* macros for ipv{4,6} wrapping -- use these */
+	/* XXX
+	 *	When NOPRIVPORTS becomes a sysctl,  delete this, 
+	 *	and use (privports{,6} ? sfilter_isallowed(....) : 1)
+	 *  !! don't forget to include ip_var.h and ip6_var.h !!
+	 */
+#ifdef NOPRIVPORTS
+	#define ISALLOWED_IPV4(port, proc, flags) (1)
+	#define ISALLOWED_IPV6(port, proc, flags) (1)
+
+#else
+	#define ISALLOWED_IPV4(port, proc, flags) \
+		sfilter_isallowed(port,proc,flags,IPPORT_RESERVED)
+	
+//XXX		#ifdef IPV6PORT_RESERVED /* ip version 6 is included */
+			#define ISALLOWED_IPV6(port, proc, flags) \
+				sfilter_isallowed(port,proc,flags,IPV6PORT_RESERVED)
+//XXX		#endif /* IPV6PORT_RESERVED */
+#endif /* NOPRIVPORTS */
+
+/*
+ * macros for rulelist manipulation
+ */
+
+#define SFILTER_RULE_LIST_INIT(x) do { \
+	x = malloc(sizeof(struct rule_slist_entry),M_MBUF,M_WAITOK|M_ZERO); \
+	SLIST_INIT(x); \
+} while(0)
+
+#define SFILTER_INSERT_RULE(list,r) do { \
+	struct rule_slist_entry *n = \
+		malloc (sizeof(struct rule_slist_entry),M_MBUF,M_WAITOK|M_ZERO); \
+	memcpy (&(n->rule), r, sizeof(struct sfilter_rule));	\
+	SLIST_INSERT_HEAD(list,n,next); \
+} while (0)
+
+#define SFILTER_INSERT_PORT(list) SLIST_INSERT_HEAD((struct rule_list *)rlist, \
+	list,next)
+
+	/* params: uint16_t port, SLIST_ENTRY(rule_list_entry) *dat_ptr */
+#define SFILTER_FIND_PORT(port,dat_ptr) do { \
+	struct rule_list_entry *tmp;	\
+	dat_ptr = NULL; \
+	SLIST_FOREACH(tmp,rlist,next){	\
+		if (tmp->port == port){	\
+			dat_ptr = tmp; \
+			break; \
+		} \
+	} \
+} while(0)
+
+#define SFILTER_REM_PORT_RULES(rlst) do { \
+	struct rule_slist_entry *r; \
+	while (!SLIST_EMPTY(rlst)) { \
+		r = SLIST_FIRST (rlst); \
+		SLIST_REMOVE_HEAD (rlst,next); \
+		free(r,M_MBUF); \
+	} \
+}while (0)
+
+#define SFILTER_REM_PORT(port_ptr) do { \
+	SFILTER_REM_PORT_RULES (port_ptr->allow); \
+	SFILTER_REM_PORT_RULES (port_ptr->deny); \
+	SLIST_REMOVE(rlist, port_ptr, rule_list_entry, next); \
+	free(port_ptr,M_MBUF); \
+} while (0)
+
+/*
+ * data structures used in the linked lists holding  the rule list
+ */
+struct rule_slist_entry {
+	/* node for the allow/deny lists */
+	struct sfilter_rule rule;
+	SLIST_ENTRY(rule_slist_entry) next;
+};
+
+SLIST_HEAD(rule_sublist,rule_slist_entry) _tmp1;
+
+struct rule_list_entry {
+	/*  node for each port */
+	uint16_t port;
+	struct rule_sublist	*allow,
+						*deny;
+	SLIST_ENTRY(rule_list_entry) next;
+};
+
+SLIST_HEAD(rule_list,rule_list_entry);
+
+extern struct rule_list *rlist; /* list head */
+
+/*
+ *	initialize the rulelist
+ */
+int 
+sfilter_initalize(void);
+
+/*
+ *	check to see if a binding is allowed by the ruleset.
+ */
+int
+sfilter_init(void);
+int
+sfilter_isallowed(uint16_t port, struct proc *p,
+	u_int16_t flags, uint16_t privmax);
+
+/*
+ * only needed out of kernel
+ */
+#else 
+
+/* system call prototypes */
+int
+sfilter_insrule(uint16_t port, void *rule, uint16_t type);
+int
+sfilter_clrrule(uint16_t port);
+
+#endif /* _KERNEL */
+
+#endif /* _NET_SFILTER_H_ */
Index: sys/net/sfilter_syscalls.c
===================================================================
RCS file: sfilter_syscalls.c
diff -N sfilter_syscalls.c
--- /dev/null	Wed Sep 25 14:55:07 2002
+++ /tmp/cvs18091ay	Wed Sep 25 14:56:29 2002
@@ -0,0 +1,153 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2000, 2001, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *        This product includes software developed by the NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * system call interface definitions for sockfilter.  by: Joe Reed
+ */
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: sfilter_syscalls.c $");
+
+#include <net/sfilter.h>
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/proc.h>
+#include <sys/buf.h>
+#include <sys/malloc.h>
+#include <sys/mbuf.h>
+#include <sys/protosw.h>
+
+#include <sys/mount.h>
+#include <sys/syscallargs.h>
+
+#include <netinet/in.h>
+
+int
+sys_sfilter_insrule (p, v, rv)
+	struct proc *p;
+	void *v;
+	register_t *rv;
+{
+	struct sys_sfilter_insrule_args /* {
+    	syscallarg(uint16_t) port;
+    	syscallarg(void *) rule;
+    	syscallarg(int8_t) type;
+	} */ *args = v;
+
+	struct rule_list_entry *p_lst;
+	struct sfilter_rule *newrule = SCARG(args,rule);
+	uint16_t port = SCARG(args,port);
+
+	/* if process doesn't have superser privs, return EACCES */
+	if ( suser(p->p_ucred,&p->p_acflag) == EPERM) {
+		*rv = -1;
+		return (EPERM);
+	}
+
+	/* be sure the port's in restricted range */
+	if (port > ( (newrule->flags & SFILTER_PROT_MASK) & SFILTER_IPV4 
+							?  IPPORT_RESERVED : IPV6PORT_RESERVED) ) {	
+		*rv = -1;
+		return (EDOM); /* XXX i should add an errno to cover this, i think 8 */
+	}
+
+		
+	SFILTER_FIND_PORT(port,p_lst);
+
+	/* if the port does not have any rules, we need to add the port */
+	if (p_lst == NULL) {
+		p_lst = malloc (sizeof(struct rule_list_entry),M_MBUF,M_WAITOK|M_ZERO);
+/* XXX error check malloc! */
+		p_lst->port = SCARG(args,port);
+		
+		SFILTER_RULE_LIST_INIT(p_lst->deny);
+		SFILTER_RULE_LIST_INIT(p_lst->allow);
+
+		SFILTER_INSERT_PORT(p_lst);
+	}
+
+	switch (SCARG(args,type) & SFILTER_TYPEMASK) {
+		case SFILTER_ALLOWRULE:	
+			SFILTER_INSERT_RULE(p_lst->allow,newrule);break;
+		case SFILTER_DENYRULE:	
+			SFILTER_INSERT_RULE(p_lst->deny,newrule);break;
+		default:
+			*rv = -1;
+			return (EINVAL);
+	}
+
+	*rv = 0;
+	return (0);
+}
+		
+/*
+ * clear the allow/deny lists for the specified port. if the port is 0
+ * remove all the entries
+ */
+int
+sys_sfilter_clrrule(p, v, rv)
+	struct proc *p;
+	void *v;
+	register_t *rv;
+{
+	struct sys_sfilter_clrrule_args /* {
+    	syscallarg(uint16_t) port;
+	} */ *args = v;
+
+	struct rule_list_entry *p_lst;
+	uint16_t port = SCARG(args,port);
+
+	/* if process doesn't have superser privs, return EACCES */
+	if ( suser(p->p_ucred,&p->p_acflag) == EPERM) {
+		*rv = -1;
+		return (EPERM);
+	}
+
+	if (port) { /* the port is >0, only remove that port's entries */
+		SFILTER_FIND_PORT(port,p_lst);
+
+		if (p_lst != NULL)
+			SFILTER_REM_PORT(p_lst);
+
+	} else { /* remove rules for all ports */
+		while (!SLIST_EMPTY(rlist)) {
+			p_lst = SLIST_FIRST(rlist);
+			SFILTER_REM_PORT (p_lst);
+		}
+	}
+
+	*rv = 0;
+	return (0);
+}
Index: sys/netinet/in_pcb.c
===================================================================
RCS file: /cvsroot/NetBSD/current/sys/netinet/in_pcb.c,v
retrieving revision 1.1.1.1
retrieving revision 1.2
diff -u -r1.1.1.1 -r1.2
--- sys/netinet/in_pcb.c	2002/08/15 16:17:54	1.1.1.1
+++ sys/netinet/in_pcb.c	2002/09/08 01:15:04	1.2
@@ -120,6 +120,7 @@
 #include <sys/proc.h>
 
 #include <net/if.h>
+#include <net/sfilter.h>
 #include <net/route.h>
 
 #include <netinet/in.h>
@@ -265,10 +266,28 @@
 	if (lport) {
 		struct inpcb *t;
 #ifndef IPNOPRIVPORTS
+		switch (so->so_proto->pr_protocol) {
+		case IPPROTO_TCP:
+			if (! ISALLOWED_IPV4(ntohs(lport),p->p_ucred->cr_uid,
+				p->p_ucred->cr_gid,SFILTER_IPV4|SFILTER_PROT_TCP))
+				return (EACCES);
+			break;
+		case IPPROTO_UDP:
+			if (! ISALLOWED_IPV4(ntohs(lport),p->p_ucred->cr_uid,
+				p->p_ucred->cr_gid,SFILTER_IPV4|SFILTER_PROT_UDP))
+				return (EACCES);
+			break;	
+		case IPPROTO_ICMP:
+			if (! ISALLOWED_IPV4(ntohs(lport),p->p_ucred->cr_uid,
+				p->p_ucred->cr_gid,SFILTER_IPV4|SFILTER_PROT_ICMP))
+				return (EACCES);
+			break;
+		default:
 		/* GROSS */
-		if (ntohs(lport) < IPPORT_RESERVED &&
-		    (p == 0 || (error = suser(p->p_ucred, &p->p_acflag))))
-			return (EACCES);
+			if (ntohs(lport) < IPPORT_RESERVED &&
+			    (p == 0 || (error = suser(p->p_ucred, &p->p_acflag))))
+				return (EACCES);
+		}
 #endif
 		if (so->so_uid && !IN_MULTICAST(sin->sin_addr.s_addr)) {
 			t = in_pcblookup_port(table, sin->sin_addr, lport, 1);
Index: sys/netinet6/in6_pcb.c
===================================================================
RCS file: /cvsroot/NetBSD/current/sys/netinet6/in6_pcb.c,v
retrieving revision 1.1.1.2
retrieving revision 1.3
diff -u -r1.1.1.2 -r1.3
--- sys/netinet6/in6_pcb.c	2002/09/22 16:36:01	1.1.1.2
+++ sys/netinet6/in6_pcb.c	2002/09/22 22:31:21	1.3
@@ -84,6 +84,7 @@
 
 #include <net/if.h>
 #include <net/route.h>
+#include <net/sfilter.h>
 
 #include <netinet/in.h>
 #include <netinet/in_var.h>
@@ -250,10 +251,28 @@
 			 * NOTE: all operating systems use suser() for
 			 * privilege check!  do not rewrite it into SS_PRIV.
 			 */
-			priv = (p && !suser(p->p_ucred, &p->p_acflag)) ? 1 : 0;
-			/* GROSS */
-			if (ntohs(lport) < IPV6PORT_RESERVED && !priv)
-				return (EACCES);
+			switch (so->so_proto->pr_protocol) {
+			case IPPROTO_TCP:
+				if (! ISALLOWED_IPV6(ntohs(lport),p->p_ucred->cr_uid,
+					p->p_ucred->cr_gid,SFILTER_IPV6|SFILTER_PROT_TCP))
+					return (EACCES);
+				break;
+			case IPPROTO_UDP:
+				if (! ISALLOWED_IPV6(ntohs(lport),p->p_ucred->cr_uid,
+                    p->p_ucred->cr_gid,SFILTER_IPV6|SFILTER_PROT_UDP))
+                    return (EACCES);
+                break;
+			case IPPROTO_ICMPV6:
+				if (! ISALLOWED_IPV6(ntohs(lport),p->p_ucred->cr_uid,
+                    p->p_ucred->cr_gid,SFILTER_IPV6|SFILTER_PROT_ICMP))
+                    return (EACCES);
+                break;
+			default:
+				priv = (p && !suser(p->p_ucred, &p->p_acflag)) ? 1 : 0;
+				/* GROSS */
+				if (ntohs(lport) < IPV6PORT_RESERVED && !priv)
+					return(EACCES);
+			}
 #endif
 
 			if (IN6_IS_ADDR_V4MAPPED(&sin6->sin6_addr)) {
Index: sys/sys/syscall.h
===================================================================
RCS file: /cvsroot/NetBSD/current/sys/sys/syscall.h,v
retrieving revision 1.1.1.2
retrieving revision 1.3
diff -u -r1.1.1.2 -r1.3
--- sys/sys/syscall.h	2002/09/22 16:36:05	1.1.1.2
+++ sys/sys/syscall.h	2002/09/22 22:31:21	1.3
@@ -1,4 +1,4 @@
-/* $NetBSD: syscall.h,v 1.126 2002/09/04 07:46:26 jdolecek Exp $ */
+/* $NetBSD$ */
 
 /*
  * System call numbers.
@@ -442,6 +442,12 @@
 #define	SYS_ntp_adjtime	176
 
 				/* 176 is excluded ntp_adjtime */
+/* syscall: "sfilter_insrule" ret: "int" args: "uint16_t" "void *" "int8_t" */
+#define	SYS_sfilter_insrule	177
+
+/* syscall: "sfilter_clrrule" ret: "int" args: "uint16_t" */
+#define	SYS_sfilter_clrrule	178
+
 /* syscall: "setgid" ret: "int" args: "gid_t" */
 #define	SYS_setgid	181
 
Index: sys/sys/syscallargs.h
===================================================================
RCS file: /cvsroot/NetBSD/current/sys/sys/syscallargs.h,v
retrieving revision 1.1.1.2
retrieving revision 1.3
diff -u -r1.1.1.2 -r1.3
--- sys/sys/syscallargs.h	2002/09/22 16:36:05	1.1.1.2
+++ sys/sys/syscallargs.h	2002/09/22 22:31:21	1.3
@@ -1,4 +1,4 @@
-/* $NetBSD: syscallargs.h,v 1.108 2002/09/04 07:46:27 jdolecek Exp $ */
+/* $NetBSD$ */
 
 /*
  * System call argument lists.
@@ -780,6 +780,16 @@
 	syscallarg(struct timex *) tp;
 };
 
+struct sys_sfilter_insrule_args {
+	syscallarg(uint16_t) port;
+	syscallarg(void *) rule;
+	syscallarg(int8_t) type;
+};
+
+struct sys_sfilter_clrrule_args {
+	syscallarg(uint16_t) port;
+};
+
 struct sys_setgid_args {
 	syscallarg(gid_t) gid;
 };
@@ -1433,6 +1443,11 @@
 int	sys_ntp_gettime(struct proc *, void *, register_t *);
 #if defined(NTP) || !defined(_KERNEL)
 int	sys_ntp_adjtime(struct proc *, void *, register_t *);
+#else
+#endif
+#if defined(SOCKFILTER)
+int	sys_sfilter_insrule(struct proc *, void *, register_t *);
+int	sys_sfilter_clrrule(struct proc *, void *, register_t *);
 #else
 #endif
 int	sys_setgid(struct proc *, void *, register_t *);
Index: usr.sbin/sfilter/Makefile
===================================================================
RCS file: Makefile
diff -N Makefile
--- /dev/null	Wed Sep 25 14:55:07 2002
+++ /tmp/cvs18091bh	Wed Sep 25 14:57:18 2002
@@ -0,0 +1,9 @@
+#	$NetBSD $
+
+PROG=	sfilter
+SRCS=	sfilter.c
+LINKS=	${BINDIR}/sfilter
+
+MAN=	sfilter.conf.5 sfilter.8
+
+.include <bsd.prog.mk>
Index: usr.sbin/sfilter/defaults.h
===================================================================
RCS file: defaults.h
diff -N defaults.h
--- /dev/null	Wed Sep 25 14:55:07 2002
+++ /tmp/cvs18091bi	Wed Sep 25 14:57:18 2002
@@ -0,0 +1,46 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2000, 2001, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *        This product includes software developed by the NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * default values used in sfilter
+ */
+
+#ifndef NET_SFILTER_DEFAULTS_H
+#define NET_SFILTER_DEFAULTS_H
+
+#define SFILTER_RULELEN		256
+#define SFILTER_CONF_FILE	"/etc/sfilter.conf"
+
+#endif /* NET_SFILTER_DEFAULTS_H */
Index: usr.sbin/sfilter/sfilter.8
===================================================================
RCS file: sfilter.8
diff -N sfilter.8
--- /dev/null	Wed Sep 25 14:55:07 2002
+++ /tmp/cvs18091bj	Wed Sep 25 14:57:18 2002
@@ -0,0 +1,81 @@
+.\"	$NetBSD: sfilter.8,v 1.14 2001/04/21 14:42:32 wiz Exp $
+.\"
+.\" Copyright (c) 2002 The NetBSD Foundation, Inc.
+.\" All rights reserved.
+.\"
+.\" Redistribution and use in source and binary forms, with or without
+.\" modification, are permitted provided that the following conditions
+.\" are met:
+.\" 1. Redistributions of source code must retain the above copyright
+.\"    notice, this list of conditions and the following disclaimer.
+.\" 2. Redistributions in binary form must reproduce the above copyright
+.\"    notice, this list of conditions and the following disclaimer in the
+.\"    documentation and/or other materials provided with the distribution.
+.\" 3. All advertising materials mentioning features or use of this software
+.\"    must display the following acknowledgement:
+.\"        This product includes software developed by the NetBSD
+.\"        Foundation, Inc. and its contributors.
+.\" 4. Neither the name of The NetBSD Foundation nor the names of its
+.\"    contributors may be used to endorse or promote products derived
+.\"    from this software without specific prior written permission.
+.\"
+.\" THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+.\" ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+.\" TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+.\" PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+.\" BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+.\" CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+.\" SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+.\" INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+.\" CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+.\" ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+.\" POSSIBILITY OF SUCH DAMAGE.
+.\"
+.Dd September 18, 2002
+.Dt SFILTER 8 i386
+.Os
+.Sh NAME
+.Nm sfilter
+.Nd allows unprivileged users to bind to privileged ports
+.Sh SYNOPSIS
+.Nm ""
+.Op Fl i
+.Op Fl f Ar filename
+.Nm ""
+.Op Fl c Ar port
+.Nm ""
+.Op Fl C
+.Nm ""
+.Op Fl h
+.Ek
+.Sh DESCRIPTION
+SocketFilter interprets rules in a config file, and adds them to the kernel's
+rulelist.
+With no flags,
+.Nm
+clears the current rulelist, then read in and add the rules contained in 
+/etc/sfilter.conf.
+.Pp
+Available command-line flags are:
+.Bl -tag -width indent -compat
+.It Fl i
+Insert rules without clearing first.
+.It Fl f Ar filename
+Use filename instead of the default (/etc/sfilter.conf)
+.It Fl c Ar port
+Clear all rules for port.
+.It Fl C
+Clear all rules for all ports.
+.It Fl h
+Prints some help text
+.El
+.Sh FILES
+.Pa /etc/sfilter.conf /usr/sbin/sfilter
+.Sh SEE ALSO
+.Xr sfilter 2
+.Xr sfilter.conf 5
+.Sh HISTORY
+The
+.Nm
+command appeared in
+.Nx 1.6 .
Index: usr.sbin/sfilter/sfilter.c
===================================================================
RCS file: sfilter.c
diff -N sfilter.c
--- /dev/null	Wed Sep 25 14:55:07 2002
+++ /tmp/cvs18091bk	Wed Sep 25 14:57:18 2002
@@ -0,0 +1,281 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2000, 2001, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *        This product includes software developed by the NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * utility to add/clear rules to sockfilter
+ */
+
+/* usage:
+	sfilter -i [-f filename] | -c port | -C
+		i: insert rules
+		f: use file instead of defaultfile
+		c: clear all rules for port
+		C: clear all rules
+*/
+#define OPTS "if:c:Ch"
+#define SEPS " \t"
+
+#include <net/sfilter.h>
+
+#include <ctype.h>
+#include <grp.h>
+#include <pwd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "defaults.h"
+#include "sfilter.h"
+
+
+extern char *optarg;
+
+void usage (void);
+int main (int, char **);
+
+void usage ()
+{
+	fprintf(stderr,"usage: %s\n\t%s\n\t%s%s\n\t%s\n\t%s\n\t%s\n",
+		"sfilter [-i] [-f filename] | -c port | -C | -h",
+		"i: insert rules without clearing existing ones",
+		"f: insert rules contained in filename, instead of ",SFILTER_CONF_FILE,
+		"c: clear all rules for port",
+		"C: clear all rules",
+		"h: print this help menu");
+}
+
+int main (argc,argv)
+	int argc;
+	char **argv;
+{
+	int c,cnt,ln;
+	FILE *conf = NULL; 
+	struct sfilter_rule newrule;
+	char *line,
+		 *rule;
+
+	cnt = ln = 0;
+	while ((c = getopt(argc,argv,OPTS)) != -1) {
+		switch (c)
+		{
+		case 'i':
+			cnt = 1; /* using this as a flag temporarily */
+			break;
+		case 'f':
+			if ( (conf = fopen (optarg,"r")) == NULL) {
+				fprintf(stderr,"cannot open %s: \n",optarg);
+				perror("");
+				CLEANUP(2,conf);
+			}
+			break;
+		case 'c':
+			if (sfilter_clrrule( atoi(optarg) ) == -1) {
+				perror("Cannot clear rules");
+				CLEANUP(2,conf);
+			}
+			printf("Port %d rules cleared successfully\n", atoi(optarg));
+			CLEANUP(0,conf);
+		case 'C':
+			if (sfilter_clrrule( 0 ) == -1) {
+				perror("Cannot clear rules");
+				CLEANUP(2,conf);
+			}
+			printf("All rules cleared successfully\n");
+			CLEANUP(0,conf);
+		default:
+			usage();
+			CLEANUP(1,conf);
+		}
+	} /* end while() getopt loop */
+
+	if (cnt == 0)
+		if (sfilter_clrrule(0) == -1) {
+			perror("Cannot clear rules\n");
+			exit(3);
+		}
+
+	/* make sure rule file's open */
+	if (conf == NULL) 
+		if ((conf = fopen(SFILTER_CONF_FILE,"r")) == NULL) {
+			fprintf (stderr,"cannot open %s: ",SFILTER_CONF_FILE);
+			perror("");
+			CLEANUP(2,conf);
+		}
+
+
+	for (line=fgetln(conf,&c),cnt=0,ln=0; !feof(conf); line=fgetln(conf,&c)) {
+		char *p,type;
+		uint16_t port;
+		size_t len = c +(line[c]=='\n'?0:1); /*leave room for \0 if needed*/
+
+		ln++;
+
+		if (*line == '#')
+			continue;
+
+		/* clear new rule struct */
+		memset(&newrule,0,sizeof(struct sfilter_rule));
+		type = '\0';
+
+		/* make working copy of string (with a terminating NULL) */
+		rule = malloc(len);
+		if (rule == NULL) {
+			perror ("malloc failed!");
+			CLEANUP (3,conf);
+		}
+
+		bcopy (line,rule,len);
+		rule[len] = '\0';
+		
+		/* get rid of ending whitespace */
+		p = rule + len-1;
+		do {
+			switch (*p)
+			{
+			case '\n':
+			case '\r':
+				*p = '\0';
+			default: 
+				break;
+			}
+			p--;
+		} while (!isalpha(*p));
+
+		/*
+		 * now parse the rule
+		 */
+		/* {allow,deny} */
+		p = strtok(rule,SEPS); 
+		if (strncasecmp(p,"allow",5) == 0) /* allow rule */
+			type |= SFILTER_ALLOWRULE;
+		else if (strncasecmp(p,"deny",4) == 0) /* deny rule */
+			type |= SFILTER_DENYRULE;
+		else
+			QUIT(conf,rule,"Invalid rule syntax on line %d\n",ln);
+
+		/* {user,group} id | all */
+		p = strtok(NULL,SEPS);
+		if (strncasecmp(p,"user",4) == 0) {
+			if ( (p = strtok(NULL,SEPS)) != NULL) {
+				struct passwd *pwd = getpwnam(p);
+	
+				if (pwd == NULL)
+					QUIT(conf,rule,"Username lookup failed from line %d\n",ln);
+
+				newrule.uid = pwd->pw_uid;
+				newrule.flags |= SFILTER_CHKUID;
+
+			} else 
+				QUIT(conf,rule,"Invalid rule syntax on line %d\n",ln);
+
+		} else if (strncasecmp(p,"group",5) == 0) {
+			if ( (p = strtok(NULL,SEPS)) != NULL) {
+				struct group *grp = getgrnam(p);
+	
+				if (grp == NULL)
+					QUIT(conf,rule,"Group lookup failed from line %d\n",ln);
+	
+				newrule.gid = grp->gr_gid;
+				newrule.flags |= SFILTER_CHKGID;
+	
+			} else 
+				QUIT(conf,rule,"Invalid rule syntax on line %d\n",ln);
+
+		} else if (strncasecmp(p,"all",3) == 0)
+			newrule.flags |= SFILTER_ALLOWALL;
+
+		else
+			QUIT(conf,rule,"Invalid rule syntax on line %d\n",ln);
+
+		/* on | NULL */
+		p = strtok(NULL,SEPS);
+		if (strncasecmp(p,"on",2) == 0) 
+			p = strtok(NULL,SEPS);
+
+		/* port portno */
+		if (strncasecmp(p,"port",4) == 0) {
+			p = strtok(NULL,SEPS);
+			
+			if ( (port = (uint16_t) atoi(p)) == 0) 
+				QUIT(conf,rule,"Invalid port number on line %d\n",ln);
+		} else
+			QUIT(conf,rule,"Invalid rule syntax on line %d\n",ln);
+
+
+		/* proto {tcp,udp,icmp,all}{,4,6} */
+		p = strtok(NULL,SEPS);
+		if (strncasecmp(p,"proto",5) == 0) {
+			p = strtok(NULL,SEPS);
+			if (strncasecmp(p,"tcp",3) == 0)
+				newrule.flags |= SFILTER_PROT_TCP;
+			else if (strncmp(p,"udp",3) == 0)
+				newrule.flags |= SFILTER_PROT_UDP;
+			else if (strncmp(p,"icmp",4) == 0)
+				newrule.flags |= SFILTER_PROT_ICMP;
+			else if (strncmp(p,"all",3) == 0)
+				newrule.flags |= SFILTER_PROT_ALL;
+			else
+				QUIT(conf,rule,"Invalid protocol type on line %d\n",ln);
+
+			switch (p[strlen(p)-1]) {
+			case '4':
+				newrule.flags |= SFILTER_IPV4;
+				break;
+			case '6':
+				newrule.flags |= SFILTER_IPV6;
+				break;
+			default:
+				newrule.flags |= SFILTER_IPALL;
+			}
+		} else
+			QUIT (conf,rule,"Invalid rule syntax on line %d\n",ln);
+
+		if (sfilter_insrule(port,&newrule,type) == -1)
+			perror("Rule insertion failed\n");
+		else
+			cnt++;
+
+		free (rule);
+	} /* end line loop */
+
+	/* now cleanup */
+	fclose (conf);
+
+	printf ("%d rules successfully added\n",cnt);
+	exit (0);
+}
+
+
Index: usr.sbin/sfilter/sfilter.conf.5
===================================================================
RCS file: sfilter.conf.5
diff -N sfilter.conf.5
--- /dev/null	Wed Sep 25 14:55:07 2002
+++ /tmp/cvs18091bl	Wed Sep 25 14:57:18 2002
@@ -0,0 +1,71 @@
+.\"	$NetBSD: ipnat.5,v 1.8 2002/06/16 14:43:46 wiz Exp $
+.\"
+.TH SFILTER 5
+.SH NAME
+sfilter, sfilter.conf \- Socket Filter file format
+.SH DESCRIPTION
+The format for files accepted by sfilter is described by the following grammar:
+.LP
+.nf
+rule :: = type id on port protocol comment | comment .
+
+type ::= allow | deny .
+id ::= "user" uid | "group" gid
+on ::= "on" | NULL
+port ::= "port" portnum
+protocol ::= "proto" prototype
+comment ::= "#"{PRINTABLE_ASCII} | NULL
+
+uid ::= letter {letters}
+gid ::= letter {letters}
+portnumber ::= number { numbers } .
+prototype ::= "tcp"{,4,6} | "udp"{,4,6} | "icmp"{,4,6} | "all"{,4,6} .
+
+numbers ::= '0' | '1' | '2' | '3' | '4' | '5' | '6' | '7' | '8' | '9' .
+letters ::= 'A' - 'Z' | 'a' - 'z' .
+
+.fi
+.PP
+In addition to this, # is used to mark the start of a comment and may
+appear at the end of a line with a NAT rule (as described above) or on its
+own lines.  Blank lines are ignored.
+.PP
+All deny rules are processed before any allow rules.
+.PP
+Currently, the uid and gid fields must map to valid usernames and groups, 
+respectively.  They may NOT be the actual uid/gid's.
+.SH Allowing users / groups
+.PP
+To allow a user (websrv) to bind to a privilaged port (80), the rule 
+could be written as:
+.LP
+.nf
+allow user websrv on port 80 proto tcp
+.fi
+.LP
+or to specifically set ipv4 and ipv6 as
+.LP
+.nf
+allow user websrv on port 80 proto tcp4
+allow user websrv on port 80 proto tcp6
+.fi
+.PP
+To allow a group to bind to port 21, but only on ipv6 the rule could be 
+written as follows:
+.LP
+.nf
+allow group ftp on 21 proto all6
+.fi
+.LP
+The deny rules follow the same syntax, just beginning with a deny,
+instead of an allow.
+.LP
+.SH FILES
+/usr/sbin/sfilter
+.br
+/etc/sfilter.conf
+.br
+.SH SEE ALSO
+sfilter (2)
+.br
+sfilter (8)
Index: usr.sbin/sfilter/sfilter.h
===================================================================
RCS file: sfilter.h
diff -N sfilter.h
--- /dev/null	Wed Sep 25 14:55:07 2002
+++ /tmp/cvs18091bm	Wed Sep 25 14:57:18 2002
@@ -0,0 +1,54 @@
+/*	$NetBSD$	*/
+
+/*-
+ * Copyright (c) 2000, 2001, 2002 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ *    must display the following acknowledgement:
+ *        This product includes software developed by the NetBSD
+ *        Foundation, Inc. and its contributors.
+ * 4. Neither the name of The NetBSD Foundation nor the names of its
+ *    contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * default values used in sfilter
+ */
+
+#ifndef SFILTER_H
+#define SFILTER_H
+
+#define CLEANUP(x,f) do{ \
+	if (f != NULL) fclose (f); \
+	exit (x); \
+} while(0)
+
+#define QUIT(f,r,s,c) do { \
+	free (r); \
+	printf(s,c); \
+	CLEANUP(3,f); \
+} while(0)
+
+#endif /* SFILTER_H */

--------------Boundary-00=_R0E0V6F8GI09TRS3UL8Z--