From proff@profane.iq.org  Mon Jan  6 17:05:39 1997
Received: from profane.iq.org (profane.iq.org [203.4.184.217])
          by freefall.freebsd.org (8.8.4/8.8.4) with ESMTP id RAA17080
          for <FreeBSD-gnats-submit@freebsd.org>; Mon, 6 Jan 1997 17:03:34 -0800 (PST)
Received: (from proff@localhost)
          by profane.iq.org (8.8.4/8.8.2) id MAA01660;
          Tue, 7 Jan 1997 12:01:30 +1100 (EST)
Message-Id: <199701070101.MAA01660@profane.iq.org>
Date: Tue, 7 Jan 1997 12:01:30 +1100 (EST)
From: Julian Assange <proff@iq.org>
Reply-To: proff@iq.org
To: FreeBSD-gnats-submit@freebsd.org
Subject: <Synopsis of the problem (one line)> patches for new socket credential firewalling
X-Send-Pr-Version: 3.2

>Number:         2386
>Category:       misc
>Synopsis:       patches for new socket credential firewalling
>Confidential:   no
>Severity:       non-critical
>Priority:       high
>Responsible:    freebsd-bugs
>State:          closed
>Quarter:        
>Keywords:       
>Date-Required:  
>Class:          change-request
>Submitter-Id:   current-users
>Arrival-Date:   Mon Jan  6 17:10:01 PST 1997
>Closed-Date:    Sun Apr 26 10:30:58 PDT 1998
>Last-Modified:  Sun Apr 26 10:31:13 PDT 1998
>Originator:     Julian Assange
>Release:        FreeBSD 3.0-CURRENT i386
>Organization:
>Environment:

-current as of 2 days ago

	

>Description:

patches for src/sbin/ipfw/ + sys/netinet/ + sys/conf/ + sys/kern/ sys/sys/
enables bind wormholes and per uid/gid firewalls

	

>How-To-Repeat:

	

>Fix:
	
	

apply patches to current (moderately tested and running on high-volume gateway
for past 3 days...but probably still should receive secondary code-review by
sight). There are some changes not within #ifdef IPFIREWALL_CREDENTIALS they are:

	o optimise various conditions in ip_fw.c
	o increase max number of ports in a rule (10->64)
	o add general support for >108 bytes of setsockopt() data
	  (now upto a cluster's worth i.e 2048 bytes)
	o enhanced logging (uid/gid/pid/in/out)
	o rationalisation of ip_fw_chk() arguments
	o pass socket pointer, if any, to ip_output ()
	o additional room in struct socket for ucred, pid
	o code to set additional socket information
	o ip_fw proto types were moved out of in.h and into
	  ip_fw.h where they belong.

This was because the additional code was not complex or
could potentially be used by code other than the new
socket credential code.

Index: src/sys/netinet/igmp.c
diff -u src/sys/netinet/igmp.c:1.19 src/sys/netinet/igmp.c:1.20
--- src/sys/netinet/igmp.c:1.19	Wed Jun 12 15:10:20 1996
+++ src/sys/netinet/igmp.c	Sat Jan  4 15:19:58 1997
@@ -35,7 +35,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)igmp.c	8.1 (Berkeley) 7/19/93
- * $Id: igmp.c,v 1.19 1996/06/12 05:10:20 gpalmer Exp $
+ * $Id: igmp.c,v 1.20 1997/01/04 04:19:58 proff Exp $
  */
 
 /*
@@ -473,7 +473,7 @@
 	 * XXX
 	 * Do we have to worry about reentrancy here?  Don't think so.
 	 */
-        ip_output(m, router_alert, &igmprt, 0, &imo);
+        ip_output(m, router_alert, &igmprt, 0, &imo, (struct socket *)0);
 
         ++igmpstat.igps_snd_reports;
 }
Index: src/sys/netinet/in.h
diff -u src/sys/netinet/in.h:1.24 src/sys/netinet/in.h:1.25
--- src/sys/netinet/in.h:1.24	Tue Dec 31 02:34:17 1996
+++ src/sys/netinet/in.h	Sat Jan  4 15:19:59 1997
@@ -31,12 +31,14 @@
  * SUCH DAMAGE.
  *
  *	@(#)in.h	8.3 (Berkeley) 1/3/94
- * $Id: in.h,v 1.24 1996/12/30 15:34:17 peter Exp $
+ * $Id: in.h,v 1.25 1997/01/04 04:19:59 proff Exp $
  */
 
 #ifndef _NETINET_IN_H_
 #define _NETINET_IN_H_
 
+#include <sys/socketvar.h>
+
 /*
  * Constants and structures defined by the internet system,
  * Per RFC 790, September 1981, and numerous additions.
@@ -329,12 +331,7 @@
 int	 in_localaddr __P((struct in_addr));
 char 	*inet_ntoa __P((struct in_addr)); /* in libkern */
 
-/* Firewall hooks */
 struct ip;
-typedef	int ip_fw_chk_t __P((struct ip**, int, struct ifnet*, int, struct mbuf**));
-typedef	int ip_fw_ctl_t __P((int, struct mbuf**));
-extern	ip_fw_chk_t *ip_fw_chk_ptr;
-extern	ip_fw_ctl_t *ip_fw_ctl_ptr;
 
 /* IP NAT hooks */
 typedef	int ip_nat_t __P((struct ip**, struct mbuf**, struct ifnet*, int));
Index: src/sys/netinet/in_pcb.c
diff -u src/sys/netinet/in_pcb.c:1.24 src/sys/netinet/in_pcb.c:1.25
--- src/sys/netinet/in_pcb.c:1.24	Sat Dec 14 08:28:53 1996
+++ src/sys/netinet/in_pcb.c	Mon Jan  6 05:37:56 1997
@@ -31,9 +31,11 @@
  * SUCH DAMAGE.
  *
  *	@(#)in_pcb.c	8.4 (Berkeley) 5/24/95
- *	$Id: in_pcb.c,v 1.24 1996/12/13 21:28:53 wollman Exp $
+ *	$Id: in_pcb.c,v 1.25 1997/01/05 18:37:56 proff Exp $
  */
 
+#include "opt_ipfw.h"
+
 #include <sys/param.h>
 #include <sys/queue.h>
 #include <sys/systm.h>
@@ -58,6 +60,13 @@
 #include <netinet/in_pcb.h>
 #include <netinet/in_var.h>
 #include <netinet/ip_var.h>
+#ifdef IPFIREWALL_CREDENTIALS
+#  include <netinet/ip_fw.h>
+#  include <netinet/udp.h>
+#  include <netinet/udp_var.h>
+#  include <netinet/tcp.h>
+#  include <netinet/tcpip.h>
+#endif
 
 struct	in_addr zeroin_addr;
 
@@ -134,6 +143,70 @@
 	return (0);
 }
 
+#ifdef IPFIREWALL_CREDENTIALS
+static int
+ip_fw_bind_check(u_short lport, struct ifnet *ifp, struct socket *so, struct sockaddr_in *sin)
+{
+	if (ip_fw_chk_ptr) {
+		struct mbuf *m;
+		struct ip *ip;
+		struct ifaddr *ifa;
+		MGETHDR(m, M_WAIT, MT_HEADER);
+		m->m_pkthdr.rcvif=ifp;
+		ip=mtod(m, struct ip *);
+		if (!ifp && sin) {
+			ifa=ifa_ifwithaddr((struct sockaddr *)sin);
+			if (ifa)
+				ifp=ifa->ifa_ifp;
+		}
+		switch (so->so_proto->pr_protocol) {
+			case IPPROTO_TCP:
+			{
+				struct tcpiphdr *ti = (struct tcpiphdr*)ip;
+				m->m_len=sizeof (*ti);
+				bzero(m->m_data, m->m_len);
+				ti->ti_sport = lport;
+			}
+				break;
+			case IPPROTO_UDP:
+			{
+				struct udpiphdr *ui = (struct udpiphdr*)ip;
+				m->m_len=sizeof (*ui);
+				bzero(m->m_data, m->m_len);
+				ui->ui_sport = lport;
+			}
+				break;
+			default:
+				m->m_len=sizeof (struct ip);
+				bzero(m->m_data, m->m_len);
+				break;
+		}
+		ip->ip_v=4;
+		ip->ip_p=so->so_proto->pr_protocol;
+		ip->ip_hl=5;
+		if (sin)
+			ip->ip_src = sin->sin_addr;
+		ip->ip_len = htons(m->m_len);
+		m->m_pkthdr.len = m->m_len;
+		switch ((*ip_fw_chk_ptr)(m, ifp, IP_FW_BIND, 0, so)) {
+			/* deny */
+			case -1:
+				return -1;
+			/* accept - pass onto IPPORT_RESERVED checks */
+			case 0:
+				m_free(m);
+				return 0;
+			/* accept - wormhole IPPORT_RESERVED checks */
+			default:
+				m_free(m);
+				return 1;
+		}
+		/* NOT REACHED */
+	}
+	return 0;
+}
+#endif
+
 int
 in_pcbbind(inp, nam)
 	register struct inpcb *inp;
@@ -146,6 +219,9 @@
 	u_short lport = 0;
 	int wild = 0, reuseport = (so->so_options & SO_REUSEPORT);
 	int error;
+#ifdef IPFIREWALL_CREDENTIALS
+	struct ifaddr *ifa = NULL;
+#endif
 
 	if (TAILQ_EMPTY(&in_ifaddrhead)) /* XXX broken! */
 		return (EADDRNOTAVAIL);
@@ -180,16 +256,33 @@
 				reuseport = SO_REUSEADDR|SO_REUSEPORT;
 		} else if (sin->sin_addr.s_addr != INADDR_ANY) {
 			sin->sin_port = 0;		/* yech... */
+#ifdef IPFIREWALL_CREDENTIALS
+			if ((ifa=ifa_ifwithaddr((struct sockaddr *)sin)) == 0)
+				return (EADDRNOTAVAIL);
+#else
 			if (ifa_ifwithaddr((struct sockaddr *)sin) == 0)
 				return (EADDRNOTAVAIL);
+#endif
 		}
 		if (lport) {
 			struct inpcb *t;
-
+#ifdef IPFIREWALL_CREDENTIALS
+			switch (ip_fw_bind_check(lport, ifa? ifa->ifa_ifp: NULL, so, sin)) {
+			case -1:
+				return (EACCES);
+			case 0:
+				break;
+			default:
+				goto accepted;
+			}
+#endif
 			/* GROSS */
 			if (ntohs(lport) < IPPORT_RESERVED &&
 			    (error = suser(p->p_ucred, &p->p_acflag)))
 				return (EACCES);
+#ifdef IPFIREWALL_CREDENTIALS
+		accepted:
+#endif
 			t = in_pcblookup(inp->inp_pcbinfo, zeroin_addr, 0,
 			    sin->sin_addr, lport, wild);
 			if (t && (reuseport & t->inp_socket->so_options) == 0)
@@ -208,8 +301,10 @@
 			last  = ipport_hilastauto;
 			lastport = &inp->inp_pcbinfo->lasthi;
 		} else if (inp->inp_flags & INP_LOWPORT) {
+#ifndef IPFIREWALL_CREDENTIALS
 			if (error = suser(p->p_ucred, &p->p_acflag))
 				return (EACCES);
+#endif
 			first = ipport_lowfirstauto;	/* 1023 */
 			last  = ipport_lowlastauto;	/* 600 */
 			lastport = &inp->inp_pcbinfo->lastlow;
@@ -256,6 +351,17 @@
 			} while (in_pcblookup(inp->inp_pcbinfo,
 				 zeroin_addr, 0, inp->inp_laddr, lport, wild));
 		}
+#ifdef IPFIREWALL_CREDENTIALS
+		switch (ip_fw_bind_check(lport, ifa? ifa->ifa_ifp: NULL, so, sin)) {
+		case -1:
+			return (EACCES);
+		case 0:
+			if (error = suser(p->p_ucred, &p->p_acflag))
+				return (EACCES);
+		default:
+			break;
+		}
+#endif
 	}
 	inp->inp_lport = lport;
 	in_pcbrehash(inp);
Index: src/sys/netinet/ip_divert.c
diff -u src/sys/netinet/ip_divert.c:1.2 src/sys/netinet/ip_divert.c:1.3
--- src/sys/netinet/ip_divert.c:1.2	Sat Dec 14 08:28:54 1996
+++ src/sys/netinet/ip_divert.c	Sat Jan  4 15:19:59 1997
@@ -30,7 +30,7 @@
  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  * SUCH DAMAGE.
  *
- *	$Id: ip_divert.c,v 1.2 1996/12/13 21:28:54 wollman Exp $
+ *	$Id: ip_divert.c,v 1.3 1997/01/04 04:19:59 proff Exp $
  */
 
 #include <sys/param.h>
@@ -227,7 +227,7 @@
 		ipstat.ips_rawout++;			/* XXX */
 		error = ip_output(m, inp->inp_options, &inp->inp_route,
 			(so->so_options & SO_DONTROUTE) |
-			IP_ALLOWBROADCAST | IP_RAWOUTPUT, inp->inp_moptions);
+			IP_ALLOWBROADCAST | IP_RAWOUTPUT, inp->inp_moptions, (struct socket *)0);
 	} else {
 		struct ifaddr *ifa;
 
Index: src/sys/netinet/ip_fw.c
diff -u src/sys/netinet/ip_fw.c:1.52 src/sys/netinet/ip_fw.c:1.54
--- src/sys/netinet/ip_fw.c:1.52	Sat Dec 14 08:28:56 1996
+++ src/sys/netinet/ip_fw.c	Mon Jan  6 05:37:57 1997
@@ -12,7 +12,7 @@
  *
  * This software is provided ``AS IS'' without any warranties of any kind.
  *
- *	$Id: ip_fw.c,v 1.52 1996/12/13 21:28:56 wollman Exp $
+ *	$Id: ip_fw.c,v 1.54 1997/01/05 18:37:57 proff Exp $
  */
 
 /*
@@ -54,6 +54,8 @@
 #else
 static int fw_verbose_limit = 0;
 #endif
+/* start of reserved rule numbers */
+#define FW_RESERVED ((u_short)-2)
 
 LIST_HEAD (ip_fw_head, ip_fw_chain) ip_fw_chain;
 
@@ -73,7 +75,7 @@
 
 #define dprint_ip(a)	if (!fw_debug); else print_ip(a)
 
-static int	add_entry __P((struct ip_fw_head *chainptr, struct ip_fw *frwl));
+static int	add_entry __P((struct ip_fw_head *chainptr, struct ip_fw *frwl, int init));
 static int	del_entry __P((struct ip_fw_head *chainptr, struct ip_fw *frwl));
 static int	zero_entry __P((struct mbuf *m));
 static struct ip_fw *
@@ -83,16 +85,15 @@
 				int range_flag));
 static int	tcpflg_match __P((struct tcphdr *tcp, struct ip_fw *f));
 static int	icmptype_match __P((struct icmp *  icmp, struct ip_fw * f));
-static void	ipfw_report __P((char *txt, int rule, struct ip *ip, int counter, struct ifnet *rif));
+static void	ipfw_report __P((char *txt, int rule, struct ip *ip, int counter, struct ifnet *rif, int flags, struct socket *so));
 
 #ifdef IPFIREWALL_MODULE
 static ip_fw_chk_t *old_chk_ptr;
 static ip_fw_ctl_t *old_ctl_ptr;
 #endif
 
-static int	ip_fw_chk __P((struct ip **pip, int hlen, struct ifnet *rif,
-			       int dirport, struct mbuf **m));
-static int	ip_fw_ctl __P((int stage, struct mbuf **mm));
+static ip_fw_chk_t ip_fw_chk;
+static ip_fw_ctl_t ip_fw_ctl;
 
 static char err_prefix[] = "ip_fw_ctl:";
 
@@ -215,7 +216,7 @@
 }
 
 static void
-ipfw_report(char *txt, int rule, struct ip *ip, int counter, struct ifnet *rif)
+ipfw_report(char *txt, int rule, struct ip *ip, int counter, struct ifnet *rif, int flags, struct socket *so)
 {
 	struct tcphdr *tcp = (struct tcphdr *) ((u_long *) ip + ip->ip_hl);
 	struct udphdr *udp = (struct udphdr *) ((u_long *) ip + ip->ip_hl);
@@ -253,19 +254,27 @@
 		print_ip(ip->ip_dst);
 		break;
 	}
-	printf(" via %s%d", rif->if_name, rif->if_unit);
+	if (flags & IP_FW_OUT)
+		printf(" out");
+	else
+		if (flags & IP_FW_IN)
+			printf(" in");
+	if (rif)
+		printf(" via %s%d", rif->if_name, rif->if_unit);
 	if ((ip->ip_off & IP_OFFMASK)) 
-		printf(" Fragment = %d",ip->ip_off & IP_OFFMASK);
+		printf(" fragment = %d",ip->ip_off & IP_OFFMASK);
+	if (so)
+		printf(" uid %d gid %d pid %d", so->so_ucred.cr_uid, so->so_ucred.cr_gid, so->so_pid);
+	if (flags & IP_FW_BIND)
+		printf(" bind");
 	printf("\n");
 	if (fw_verbose_limit != 0 && counter == fw_verbose_limit)
 		printf("ipfw: limit reached on rule #%d\n", rule);
 }
 
 /*
- * We overload the "dirport" parameter:
  *
- *   If dirport is negative, packet is outgoing; otherwise incoming.
- *   The low order 16 bits of dirport, if non-zero, indicate that
+ *   dirport, if non-zero, indicate that
  *   we should ignore all ``divert <port>'' rules, where <port> is
  *   the low order 16 bits.
  *
@@ -278,12 +287,11 @@
  */
 
 static int 
-ip_fw_chk(struct ip **pip, int hlen,
-	struct ifnet *rif, int dirport, struct mbuf **m)
+ip_fw_chk(struct mbuf *m, struct ifnet *rif, int flags, int dirport, struct socket *so)
 {
 	struct ip_fw_chain *chain;
 	register struct ip_fw *f = NULL;
-	struct ip *ip = *pip;
+	struct ip *ip = mtod(m, struct ip *);
 	struct tcphdr *tcp = (struct tcphdr *) ((u_long *) ip + ip->ip_hl);
 	struct udphdr *udp = (struct udphdr *) ((u_long *) ip + ip->ip_hl);
 	struct icmp *icmp = (struct icmp *) ((u_long *) ip + ip->ip_hl);
@@ -307,27 +315,49 @@
 	for (chain=ip_fw_chain.lh_first; chain; chain = chain->chain.le_next) {
 		f = chain->rule;
 
+#ifdef IPFIREWALL_CREDENTIALS
+		if (f->fw_flg & IP_FW_F_UID) {
+			if (!so || so->so_ucred.cr_uid != f->fw_uid)
+				continue;
+		} else	if (flags & IP_FW_INPUT2)
+				continue;
+		if (f->fw_flg & IP_FW_F_GID) {
+			if (!so || !groupmember(f->fw_gid, &so->so_ucred))
+				continue;
+		} else	if (flags & IP_FW_INPUT2)
+				continue;
+		if (f->fw_flg & IP_FW_F_BIND) {
+			if (!(flags & IP_FW_BIND))
+				continue;
+			goto bind_skip;
+		} else	if (flags & IP_FW_BIND)
+				continue;
+#endif
+
 		/* Check direction inbound */
-		if (dirport >= 0 && !(f->fw_flg & IP_FW_F_IN))
+		if ((flags & IP_FW_IN) && !(f->fw_flg & IP_FW_F_IN))
 			continue;
 
 		/* Check direction outbound */
-		if (dirport < 0 && !(f->fw_flg & IP_FW_F_OUT))
+		if ((flags & IP_FW_OUT) && !(f->fw_flg & IP_FW_F_OUT))
 			continue;
 
 		/* Fragments */
 		if ((f->fw_flg & IP_FW_F_FRAG) && !(ip->ip_off & IP_OFFMASK))
 			continue;
 
-		/* If src-addr doesn't match, not this rule. */
-		if ((src.s_addr & f->fw_smsk.s_addr) != f->fw_src.s_addr)
-			continue;
-
 		/* If dest-addr doesn't match, not this rule. */
 		if ((dst.s_addr & f->fw_dmsk.s_addr) != f->fw_dst.s_addr)
 			continue;
 
-		/* If a i/f name was specified, and we don't know */
+#ifdef IPFIREWALL_CREDENTIALS
+	bind_skip:
+#endif
+		/* If src-addr doesn't match, not this rule. */
+		if ((src.s_addr & f->fw_smsk.s_addr) != f->fw_src.s_addr)
+			continue;
+
+	/* If a i/f name was specified, and we don't know */
 		if ((f->fw_flg & IP_FW_F_IFNAME) && !rif)
 			continue;
 
@@ -386,8 +416,8 @@
 			if (offset == 1) {
 				static int frag_counter = 0;
 				++frag_counter;
-				ipfw_report("Refuse", -1, ip, frag_counter, rif);
-				m_freem(*m);
+				ipfw_report("Refuse", -1, ip, frag_counter, rif, flags, so);
+				m_freem(m);
 				return -1;
 			}
 			if ((offset == 0) &&
@@ -420,42 +450,55 @@
 		default:
 			break;
 		}
-
+		
 got_match:
 		f->fw_pcnt++;
 		f->fw_bcnt+=ip->ip_len;
 		f->timestamp = time.tv_sec;
 		if (f->fw_flg & IP_FW_F_PRN) {
-			if ((f->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_ACCEPT) {
-				ipfw_report("Allow",
-					f->fw_number, ip, f->fw_pcnt, rif);
-			} else if ((f->fw_flg & IP_FW_F_COMMAND)
-			    == IP_FW_F_DIVERT) {
-				if (f->fw_divert_port != (dirport & 0xffff))
+			switch (f->fw_flg & IP_FW_F_COMMAND) {
+			case IP_FW_F_ACCEPT:
+				ipfw_report("Allow", f->fw_number, ip, f->fw_pcnt, rif, flags, so);
+				break;
+			case IP_FW_F_DIVERT:
+				if (f->fw_divert_port != dirport)
 					ipfw_report("Divert", f->fw_number,
-							ip, f->fw_pcnt, rif);
-			} else if ((f->fw_flg & IP_FW_F_COMMAND)
-			    == IP_FW_F_COUNT) {
-				ipfw_report("Count",
-					f->fw_number, ip, f->fw_pcnt, rif);
-			} else {
-				ipfw_report("Deny",
-					f->fw_number, ip, f->fw_pcnt, rif);
+							ip, f->fw_pcnt, rif, flags, so);
+				break;
+			case IP_FW_F_COUNT:
+				ipfw_report("Count", f->fw_number, ip, f->fw_pcnt, rif, flags, so);
+				break;
+			default:
+				ipfw_report("Deny", f->fw_number, ip, f->fw_pcnt, rif, flags, so);
+				break;
 			}
 		}
 
 		/* Take appropriate action */
-		if ((f->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_ACCEPT) {
+		switch (f->fw_flg & IP_FW_F_COMMAND) {
+		case IP_FW_F_ACCEPT:
+#ifdef IPFIREWALL_CREDENTIALS
+			/* assert IP_FW_F_WORMHOLE -> IP_FW_F_BIND + IP_FW_BIND */
+			return (f->fw_flg & IP_FW_F_WORMHOLE)? 1: 0; 
+#else
 			return 0;
-		} else if ((f->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_COUNT) {
+#endif
+		case IP_FW_F_COUNT:
 			continue;
-		} else if ((f->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_DIVERT) {
-			if (f->fw_divert_port == (dirport & 0xffff))
+		case IP_FW_F_DIVERT:
+			if (f->fw_divert_port == dirport)
 				continue;	/* ignore this rule */
 			return (f->fw_divert_port);
-		} else
-			break;		/* ie, deny/reject */
+		default:
+			goto drop; /* ie, deny/reject */
+		}
 	}
+#ifdef IPFIREWALL_CREDENTIALS
+	/* no uid/gid matches the second scan, but we know in order
+	   to get here the first scan must have accepted the packet. */
+	if (!chain && flags & IP_FW_INPUT2)
+		return 0;
+#endif
 
 #ifdef DIAGNOSTIC
 	if (!chain)			/* rule 65535 should always be there */
@@ -473,19 +516,20 @@
 	 * - The packet is not an ICMP packet
 	 * - The rule has the special ICMP reply flag set
 	 */
-	if (dirport >= 0
+drop:
+	if ((flags & IP_FW_IN)
 	    && (f->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_DENY
 	    && (ip->ip_p != IPPROTO_ICMP)
 	    && (f->fw_flg & IP_FW_F_ICMPRPL)) {
-		icmp_error(*m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0L, 0);
+		icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0L, 0);
 		return -1;
 	}
-	m_freem(*m);
+	m_freem(m);
 	return -1;
 }
 
 static int
-add_entry(struct ip_fw_head *chainptr, struct ip_fw *frwl)
+add_entry(struct ip_fw_head *chainptr, struct ip_fw *frwl, int init)
 {
 	struct ip_fw *ftmp = 0;
 	struct ip_fw_chain *fwc = 0, *fcp, *fcpl = 0;
@@ -512,7 +556,7 @@
 		LIST_INSERT_HEAD(chainptr, fwc, chain);
 		splx(s);
 		return(0);
-        } else if (ftmp->fw_number == (u_short)-1) {
+        } else if (ftmp->fw_number >= FW_RESERVED && !init) {
 		if (fwc)  free(fwc, M_IPFW);
 		if (ftmp) free(ftmp, M_IPFW);
 		splx(s);
@@ -522,12 +566,12 @@
 	/* If entry number is 0, find highest numbered rule and add 100 */
 	if (ftmp->fw_number == 0) {
 		for (fcp = chainptr->lh_first; fcp; fcp = fcp->chain.le_next) {
-			if (fcp->rule->fw_number != (u_short)-1)
+			if (fcp->rule->fw_number < FW_RESERVED)
 				nbr = fcp->rule->fw_number;
 			else
 				break;
 		}
-		if (nbr < (u_short)-1 - 100)
+		if (nbr < FW_RESERVED - 100)
 			nbr += 100;
 		ftmp->fw_number = nbr;
 	}
@@ -559,7 +603,7 @@
 	s = splnet();
 
 	fcp = chainptr->lh_first; 
-	if (frwl->fw_number != (u_short)-1) {
+	if (frwl->fw_number < FW_RESERVED) {
 		for (; fcp; fcp = fcp->chain.le_next) {
 			if (fcp->rule->fw_number == frwl->fw_number) {
 				LIST_REMOVE(fcp, chain);
@@ -629,6 +673,23 @@
 		return (NULL);
 	}
 
+#ifdef IPFIREWALL_CREDENTIALS
+	if ((frwl->fw_flg & IP_FW_F_BIND) &&
+	    (frwl->fw_flg & (IP_FW_F_FRAG | IP_FW_F_ICMPBIT | IP_FW_F_ICMPRPL | IP_FW_F_IN | IP_FW_F_OUT) ||
+	     frwl->fw_flg & IP_FW_F_COMMAND == IP_FW_F_DIVERT ||
+	     frwl->fw_ndp !=0 ||
+	     frwl->fw_dmsk.s_addr !=0
+	    )) {
+	     	dprintf(("%s use of BIND with FRAG, ICMPBIT, ICMPPRL, IN, OUT, DIVERT, fw_ndp, or fw_dmsk\n", err_prefix));
+		return NULL;
+	}
+	if (frwl->fw_flg & IP_FW_F_WORMHOLE &&
+	    !(frwl->fw_flg & IP_FW_F_BIND)) {
+	    	dprintf(("%s use of WORMHOLE without BIND\n", err_prefix));
+		return NULL;
+	}
+#endif
+
 	/* If neither In nor Out, then both */
 	if (!(frwl->fw_flg & (IP_FW_F_IN | IP_FW_F_OUT)))
 		frwl->fw_flg |= IP_FW_F_IN | IP_FW_F_OUT;
@@ -670,11 +731,19 @@
 		return(NULL);
 	}
 
-	/* Diverting to port zero is illegal */
-	if ((frwl->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_DIVERT
-	     && frwl->fw_divert_port == 0) {
-		dprintf(("ip_fw_ctl: can't divert to port 0\n"));
-		return (NULL);
+	if ((frwl->fw_flg & IP_FW_F_COMMAND) == IP_FW_F_DIVERT) {
+		/* Diverting to port zero is illegal */
+		if (frwl->fw_divert_port == 0) {
+			dprintf(("%s can't divert to port 0\n", err_prefix));
+			return (NULL);
+		}
+#ifdef IPFIREWALL_CREDENTIALS
+		/* Can't divert socket credentials or binds */
+		if (frwl->fw_flg & (IP_FW_F_UID|IP_FW_F_GID|IP_FW_F_BIND)) {
+			dprintf(("%s can't divert on bind or socket credentials\n", err_prefix));
+			return NULL;
+		}
+#endif
 	}
 	return frwl;
 }
@@ -689,6 +758,8 @@
 		struct ip_fw_chain *fcp = ip_fw_chain.lh_first;
 		*mm = m = m_get(M_WAIT, MT_SOOPTS);
 		for (; fcp; fcp = fcp->chain.le_next) {
+			if (sizeof (*(fcp->rule))> MLEN)
+				MCLGET(m, M_WAIT);
 			memcpy(m->m_data, fcp->rule, sizeof *(fcp->rule));
 			m->m_len = sizeof *(fcp->rule);
 			m->m_next = m_get(M_WAIT, MT_SOOPTS);
@@ -705,7 +776,7 @@
 	}
 	if (stage == IP_FW_FLUSH) {
 		while (ip_fw_chain.lh_first != NULL && 
-		    ip_fw_chain.lh_first->rule->fw_number != (u_short)-1) {
+		    ip_fw_chain.lh_first->rule->fw_number < FW_RESERVED) {
 			struct ip_fw_chain *fcp = ip_fw_chain.lh_first;
 			int s = splnet();
 			LIST_REMOVE(ip_fw_chain.lh_first, chain);
@@ -735,7 +806,7 @@
 		}
 
 		if (stage == IP_FW_ADD)
-			error = add_entry(&ip_fw_chain, frwl);
+			error = add_entry(&ip_fw_chain, frwl, 0);
 		else
 			error = del_entry(&ip_fw_chain, frwl);
 		if (m) (void)m_free(m);
@@ -749,22 +820,31 @@
 void
 ip_fw_init(void)
 {
-	struct ip_fw deny;
+	struct ip_fw rule;
 
 	ip_fw_chk_ptr = ip_fw_chk;
 	ip_fw_ctl_ptr = ip_fw_ctl;
 	LIST_INIT(&ip_fw_chain);
 
-	bzero(&deny, sizeof deny);
-	deny.fw_prot = IPPROTO_IP;
-	deny.fw_number = (u_short)-1;
-	add_entry(&ip_fw_chain, &deny);
+	bzero(&rule, sizeof rule);
+	rule.fw_flg = IP_FW_F_DENY | IP_FW_F_IN | IP_FW_F_OUT;
+	rule.fw_prot = IPPROTO_IP;
+	rule.fw_number = FW_RESERVED+1;
+	add_entry(&ip_fw_chain, &rule, 1);
+	rule.fw_flg |= IP_FW_F_BIND;
+	rule.fw_number--;
+	add_entry(&ip_fw_chain, &rule, 1);
 
 	printf("IP packet filtering initialized, "
 #ifdef IPDIVERT
-		"divert enabled, ");
+		"divert enabled, "
+#else
+		"divert disabled, "
+#endif
+#ifdef IPFIREWALL_CREDENTIALS
+		"socket credentials enabled, ");
 #else
-		"divert disabled, ");
+		"socket credentials disabled, ");
 #endif
 #ifndef IPFIREWALL_VERBOSE
 	printf("logging disabled\n");
Index: src/sys/netinet/ip_fw.h
diff -u src/sys/netinet/ip_fw.h:1.23 src/sys/netinet/ip_fw.h:1.25
--- src/sys/netinet/ip_fw.h:1.23	Thu Aug 22 07:36:57 1996
+++ src/sys/netinet/ip_fw.h	Mon Jan  6 05:37:57 1997
@@ -11,7 +11,7 @@
  *
  * This software is provided ``AS IS'' without any warranties of any kind.
  *
- *	$Id: ip_fw.h,v 1.23 1996/08/21 21:36:57 sos Exp $
+ *	$Id: ip_fw.h,v 1.25 1997/01/05 18:37:57 proff Exp $
  */
 
 /*
@@ -24,6 +24,10 @@
 #ifndef _IP_FW_H
 #define _IP_FW_H
 
+#ifndef IPFIREWALL
+#  undef IPFIREWALL_CREDENTIALS
+#endif
+
 struct ip_fw {
     u_long fw_pcnt,fw_bcnt;		/* Packet and byte counters */
     struct in_addr fw_src, fw_dst;	/* Source and destination IP addr */
@@ -40,12 +44,12 @@
 #define fw_via_name	fu_via_un.fu_via_if.fu_via_name
 #define fw_via_unit	fu_via_un.fu_via_if.fu_via_unit
     u_short fw_number;
-    u_short fw_flg;			/* Flags word */
+    u_int fw_flg;			/* Flags word */
     u_short fw_nsp, fw_ndp;             /* N'of src ports and # of dst ports */
     					/* in ports array (dst ports follow */
     					/* src ports; max of 10 ports in all; */
     					/* count of 0 means match all ports) */
-#define IP_FW_MAX_PORTS	10      	/* A reasonable maximum */
+#define IP_FW_MAX_PORTS	64      	/* A reasonable maximum */
     u_short fw_pts[IP_FW_MAX_PORTS];    /* Array of port numbers to match */
     u_char fw_ipopt,fw_ipnopt;		/* IP options set/unset */
     u_char fw_tcpf,fw_tcpnf;		/* TCP flags set/unset */
@@ -54,6 +58,8 @@
     long timestamp;         		/* timestamp (tv_sec) of last match */
     u_short fw_divert_port;		/* Divert port (options IPDIVERT) */
     u_char fw_prot;			/* IP protocol */
+    uid_t fw_uid;			/* uid */
+    gid_t fw_gid;			/* gid */
 };
 
 struct ip_fw_chain {
@@ -92,7 +98,14 @@
 
 #define IP_FW_F_IFUWILD	0x2000	/* Match all interface units          */
 
-#define IP_FW_F_MASK	0x3FFF	/* All possible flag bits mask        */
+#define IP_FW_F_UID	0x4000	/* Match socket owner uid	      */
+#define IP_FW_F_GID	0x8000	/* Match socket owner gid             */
+
+#define IP_FW_F_BIND	0x10000	/* Match bind() attempt		      */
+#define IP_FW_F_WORMHOLE	0x20000	/* If ACCEPTed, don't test against  *
+				 * traditional bind() limitations.    */
+
+#define IP_FW_F_MASK	0x3FFFF	/* All possible flag bits mask        */
 
 /*
  * Definitions for IP option names.
@@ -117,6 +130,22 @@
  * Main firewall chains definitions and global var's definitions.
  */
 #ifdef KERNEL
+
+/*
+ * ip_fw_chk() flags
+ */
+
+ #define IP_FW_IN	0x001	/* incoming packet */
+ #define IP_FW_OUT	0x002	/* outgoing packet */
+ #define IP_FW_LOCAL	0x004	/* from/for this host packet */
+ #define IP_FW_INPUT2	0x008	/* 2nd input pass, socket dest */
+ #define IP_FW_BIND   	0x010	/* bind() attempt */
+
+/* Firewall module hooks */
+typedef	int ip_fw_chk_t __P((struct mbuf *m, struct ifnet* rif, int flags, int dirport, struct socket *so));
+typedef	int ip_fw_ctl_t __P((int, struct mbuf**));
+extern	ip_fw_chk_t *ip_fw_chk_ptr;
+extern	ip_fw_ctl_t *ip_fw_ctl_ptr;
 
 /*
  * Function definitions.
Index: src/sys/netinet/ip_icmp.c
diff -u src/sys/netinet/ip_icmp.c:1.23 src/sys/netinet/ip_icmp.c:1.24
--- src/sys/netinet/ip_icmp.c:1.23	Sat Dec 14 08:28:56 1996
+++ src/sys/netinet/ip_icmp.c	Sat Jan  4 15:20:00 1997
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)ip_icmp.c	8.2 (Berkeley) 1/4/94
- * $Id: ip_icmp.c,v 1.23 1996/12/13 21:28:56 wollman Exp $
+ * $Id: ip_icmp.c,v 1.24 1997/01/04 04:20:00 proff Exp $
  */
 
 #include <sys/param.h>
@@ -637,7 +637,7 @@
 	}
 #endif
 	bzero(&ro, sizeof ro);
-	(void) ip_output(m, opts, &ro, 0, NULL);
+	(void) ip_output(m, opts, &ro, 0, NULL, NULL);
 	if (ro.ro_rt)
 		RTFREE(ro.ro_rt);
 }
Index: src/sys/netinet/ip_input.c
diff -u src/sys/netinet/ip_input.c:1.53 src/sys/netinet/ip_input.c:1.54
--- src/sys/netinet/ip_input.c:1.53	Sat Dec 14 08:28:57 1996
+++ src/sys/netinet/ip_input.c	Sat Jan  4 15:20:00 1997
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)ip_input.c	8.2 (Berkeley) 1/4/94
- * $Id: ip_input.c,v 1.53 1996/12/13 21:28:57 wollman Exp $
+ * $Id: ip_input.c,v 1.54 1997/01/04 04:20:00 proff Exp $
  *	$ANA: ip_input.c,v 1.5 1996/09/18 14:34:59 wollman Exp $
  */
 
@@ -117,14 +117,7 @@
 	&ip_mtu, 0, "");
 #endif
 
-#if !defined(COMPAT_IPFW) || COMPAT_IPFW == 1
-#undef COMPAT_IPFW
-#define COMPAT_IPFW 1
-#else
-#undef COMPAT_IPFW
-#endif
-
-#ifdef COMPAT_IPFW
+#ifdef IPFIREWALL
 /* Firewall hooks */
 ip_fw_chk_t *ip_fw_chk_ptr;
 ip_fw_ctl_t *ip_fw_ctl_ptr;
@@ -313,15 +306,14 @@
 	 * - Encapsulate: put it in another IP and send out. <unimp.>
  	 */
 
-#ifdef COMPAT_IPFW
+#ifdef IPFIREWALL
 	if (ip_fw_chk_ptr) {
 		int action;
 
 #ifdef IPDIVERT
-		action = (*ip_fw_chk_ptr)(&ip, hlen,
-				m->m_pkthdr.rcvif, ip_divert_ignore, &m);
+		action = (*ip_fw_chk_ptr)(m, m->m_pkthdr.rcvif, IP_FW_IN, ip_divert_ignore, (struct socket*)0);
 #else
-		action = (*ip_fw_chk_ptr)(&ip, hlen, m->m_pkthdr.rcvif, 0, &m);
+		action = (*ip_fw_chk_ptr)(m, m->m_pkthdr.rcvif, IP_FW_IN, 0, (struct socket*)0);
 #endif
 		if (action == -1)
 			return;
@@ -1271,7 +1263,7 @@
 	}
 
 	error = ip_output(m, (struct mbuf *)0, &ipforward_rt, 
-			  IP_FORWARDING, 0);
+			  IP_FORWARDING, 0, NULL);
 	if (error)
 		ipstat.ips_cantforward++;
 	else {
Index: src/sys/netinet/ip_mroute.c
diff -u src/sys/netinet/ip_mroute.c:1.35 src/sys/netinet/ip_mroute.c:1.36
--- src/sys/netinet/ip_mroute.c:1.35	Sun Nov 24 06:07:02 1996
+++ src/sys/netinet/ip_mroute.c	Sat Jan  4 15:20:01 1997
@@ -9,10 +9,11 @@
  * Modified by Bill Fenner, PARC, April 1995
  *
  * MROUTING Revision: 3.5
- * $Id: ip_mroute.c,v 1.35 1996/11/23 19:07:02 fenner Exp $
+ * $Id: ip_mroute.c,v 1.36 1997/01/04 04:20:01 proff Exp $
  */
 
 #include "opt_mrouting.h"
+#include "opt_ipfw.h"
 
 #include <sys/param.h>
 #include <sys/queue.h>
@@ -38,6 +39,9 @@
 #include <netinet/igmp_var.h>
 #include <netinet/ip_mroute.h>
 #include <netinet/udp.h>
+#ifdef IPFIREWALL_CREDENTIALS
+#  include <netinet/ip_fw.h>
+#endif
 
 #ifndef NTOHL
 #if BYTE_ORDER != BIG_ENDIAN
@@ -1260,6 +1264,23 @@
 
 	    mrtstat.mrts_upcalls++;
 
+#ifdef IPFIREWALL_CREDENTIALS
+	    if (ip_fw_chk_ptr) {
+		switch ((*ip_fw_chk_ptr)(m, ifp, IP_FW_IN|IP_FW_INPUT2, 0, ip_mrouter)) {
+			case -1:
+				m_free(mb_ntry);
+				m_freem(mb0);
+				m_free(mb_rt);
+				splx(s);
+				return EACCES;
+			case 0:
+				break;
+			default:
+				panic("X_ip_mforward ipfw divert attempt"); /* should have been diverted already */
+				break;
+		}
+	    }
+#endif
 	    if (socket_send(ip_mrouter, mm, &k_igmpsrc) < 0) {
 		log(LOG_WARNING, "ip_mforward: ip_mrouter socket queue full\n");
 		++mrtstat.mrts_upq_sockfull;
@@ -1465,7 +1486,21 @@
 
 		k_igmpsrc.sin_addr = im->im_src;
 
+#ifdef IPFIREWALL_CREDENTIALS
+	if (ip_fw_chk_ptr) {
+		switch ((*ip_fw_chk_ptr)(m, ifp, IP_FW_IN|IP_FW_INPUT2, 0, ip_mrouter)) {
+			case -1:
+				return EACCES;
+			case 0:
+				break;
+			default:
+				panic("ip_mdq ipfw divert attempt"); /* should have been diverted already */
+				break;
+		}
+	}
+#endif
 		socket_send(ip_mrouter, mm, &k_igmpsrc);
+	after_send:
 	    }
 	}
 	return 0;
@@ -1912,7 +1947,7 @@
     if (vifp->v_flags & VIFF_TUNNEL) {
 	/* If tunnel options */
 	ip_output(m, (struct mbuf *)0, &vifp->v_route,
-		  IP_FORWARDING, (struct ip_moptions *)0);
+		  IP_FORWARDING, (struct ip_moptions *)0, (struct socket *)0);
     } else {
 	imo.imo_multicast_ifp  = vifp->v_ifp;
 	imo.imo_multicast_ttl  = mtod(m, struct ip *)->ip_ttl - 1;
@@ -1926,7 +1961,7 @@
 	 * the loopback interface, thus preventing looping.
 	 */
 	error = ip_output(m, (struct mbuf *)0, &ro,
-			  IP_FORWARDING, &imo);
+			  IP_FORWARDING, &imo, (struct socket *)0);
 
 	if (mrtdebug & DEBUG_XMIT)
 	    log(LOG_DEBUG, "phyint_send on vif %d err %d\n", 
@@ -2150,9 +2185,9 @@
 	int iphlen;
 {
     int vifi;
-    register struct ip *ip = mtod(m, struct ip *);
+    struct ip *ip = mtod(m, struct ip *);
     static struct sockaddr_in rsvp_src = { sizeof rsvp_src, AF_INET };
-    register int s;
+    int s;
     struct ifnet *ifp;
 
     if (rsvpdebug)
@@ -2221,13 +2256,28 @@
 	printf("rsvp_input: m->m_len = %d, sbspace() = %ld\n",
 	       m->m_len,sbspace(&(viftable[vifi].v_rsvpd->so_rcv)));
 
+#ifdef IPFIREWALL_CREDENTIALS
+	if (ip_fw_chk_ptr) {
+		switch ((*ip_fw_chk_ptr)(m, ifp, IP_FW_IN|IP_FW_INPUT2, 0, ip_mrouter)) {
+			case -1:
+				goto after_send;
+			case 0:
+				break;
+			default:
+				panic("rsvp_input ipfw divert attempt"); /* should have been diverted already */
+				break;
+		}
+	}
+#endif
+
     if (socket_send(viftable[vifi].v_rsvpd, m, &rsvp_src) < 0)
 	if (rsvpdebug)
 	    printf("rsvp_input: Failed to append to socket\n");
     else
 	if (rsvpdebug)
 	    printf("rsvp_input: send packet up\n");
-    
+
+after_send:
     splx(s);
 }
 
Index: src/sys/netinet/ip_output.c
diff -u src/sys/netinet/ip_output.c:1.46 src/sys/netinet/ip_output.c:1.47
--- src/sys/netinet/ip_output.c:1.46	Sat Dec 14 08:28:58 1996
+++ src/sys/netinet/ip_output.c	Sat Jan  4 15:20:01 1997
@@ -31,9 +31,11 @@
  * SUCH DAMAGE.
  *
  *	@(#)ip_output.c	8.3 (Berkeley) 1/21/94
- *	$Id: ip_output.c,v 1.46 1996/12/13 21:28:58 wollman Exp $
+ *	$Id: ip_output.c,v 1.47 1997/01/04 04:20:01 proff Exp $
  */
 
+#include "opt_ipfw.h"
+
 #define _IP_VHL
 
 #include <sys/param.h>
@@ -55,19 +57,15 @@
 #include <netinet/in_pcb.h>
 #include <netinet/in_var.h>
 #include <netinet/ip_var.h>
+#ifdef IPFIREWALL
+#  include <netinet/ip_fw.h>
+#endif
 
 #ifdef vax
 #include <machine/mtpr.h>
 #endif
 #include <machine/in_cksum.h>
 
-#if !defined(COMPAT_IPFW) || COMPAT_IPFW == 1
-#undef COMPAT_IPFW
-#define COMPAT_IPFW 1
-#else
-#undef COMPAT_IPFW
-#endif
-
 u_short ip_id;
 
 static struct mbuf *ip_insertoptions __P((struct mbuf *, struct mbuf *, int *));
@@ -89,12 +87,13 @@
  * The mbuf opt, if present, will not be freed.
  */
 int
-ip_output(m0, opt, ro, flags, imo)
+ip_output(m0, opt, ro, flags, imo, so)
 	struct mbuf *m0;
 	struct mbuf *opt;
 	struct route *ro;
 	int flags;
 	struct ip_moptions *imo;
+	struct socket *so;
 {
 	struct ip *ip, *mhip;
 	struct ifnet *ifp;
@@ -340,7 +339,7 @@
 	 * - Encapsulate: put it in another IP and send out. <unimp.>
 	 */ 
 
-#ifdef COMPAT_IPFW
+#ifdef IPFIREWALL
         if (ip_nat_ptr && !(*ip_nat_ptr)(&ip, &m, ifp, IP_NAT_OUT)) {
 		error = EACCES; 
 		goto done;
@@ -351,12 +350,10 @@
 	 */
 	if (ip_fw_chk_ptr) {
 		int action;
-
 #ifdef IPDIVERT
-		action = (*ip_fw_chk_ptr)(&ip,
-				hlen, ifp, (~0 << 16) | ip_divert_ignore, &m);
+		action = (*ip_fw_chk_ptr)(m, ifp, IP_FW_OUT, ip_divert_ignore, so);
 #else
-		action = (*ip_fw_chk_ptr)(&ip, hlen, ifp, (~0 << 16), &m);
+		action = (*ip_fw_chk_ptr)(m, ifp, IP_FW_OUT, 0, so);
 #endif
 		if (action == -1) {
 			error = EACCES;		/* XXX is this appropriate? */
@@ -372,7 +369,7 @@
 #endif
 		}
 	}
-#endif /* COMPAT_IPFW */
+#endif /* IPFIREWALL */
 
 	/*
 	 * If small enough for interface, can just send directly.
Index: src/sys/netinet/ip_var.h
diff -u src/sys/netinet/ip_var.h:1.26 src/sys/netinet/ip_var.h:1.27
--- src/sys/netinet/ip_var.h:1.26	Tue Nov 12 21:02:09 1996
+++ src/sys/netinet/ip_var.h	Sat Jan  4 15:20:01 1997
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)ip_var.h	8.2 (Berkeley) 1/9/95
- *	$Id: ip_var.h,v 1.26 1996/11/12 10:02:09 bde Exp $
+ *	$Id: ip_var.h,v 1.27 1997/01/04 04:20:01 proff Exp $
  */
 
 #ifndef _NETINET_IP_VAR_H_
@@ -177,7 +177,7 @@
 extern int	 (*ip_mforward) __P((struct ip *, struct ifnet *, struct mbuf *,
 			  struct ip_moptions *));
 int	 ip_output __P((struct mbuf *,
-	    struct mbuf *, struct route *, int, struct ip_moptions *));
+	    struct mbuf *, struct route *, int, struct ip_moptions *, struct socket *));
 void	 ip_savecontrol __P((struct inpcb *, struct mbuf **, struct ip *,
 		struct mbuf *));
 void	 ip_slowtimo __P((void));
Index: src/sys/netinet/raw_ip.c
diff -u src/sys/netinet/raw_ip.c:1.39 src/sys/netinet/raw_ip.c:1.40
--- src/sys/netinet/raw_ip.c:1.39	Thu Dec 12 07:38:25 1996
+++ src/sys/netinet/raw_ip.c	Sat Jan  4 15:20:02 1997
@@ -31,9 +31,11 @@
  * SUCH DAMAGE.
  *
  *	@(#)raw_ip.c	8.7 (Berkeley) 5/15/95
- *	$Id: raw_ip.c,v 1.39 1996/12/11 20:38:25 wollman Exp $
+ *	$Id: raw_ip.c,v 1.40 1997/01/04 04:20:02 proff Exp $
  */
 
+#include "opt_ipfw.h"
+
 #include <sys/param.h>
 #include <sys/queue.h>
 #include <sys/malloc.h>
@@ -55,14 +57,8 @@
 #include <netinet/in_var.h>
 #include <netinet/ip_var.h>
 #include <netinet/ip_mroute.h>
-
-#include <netinet/ip_fw.h>
-
-#if !defined(COMPAT_IPFW) || COMPAT_IPFW == 1
-#undef COMPAT_IPFW
-#define COMPAT_IPFW 1
-#else
-#undef COMPAT_IPFW
+#ifdef IPFIREWALL
+#  include <netinet/ip_fw.h>
 #endif
 
 static struct inpcbhead ripcb;
@@ -122,6 +118,19 @@
 			continue;
 		if (last) {
 			struct mbuf *n = m_copy(m, 0, (int)M_COPYALL);
+#ifdef IPFIREWALL_CREDENTIALS
+			if (ip_fw_chk_ptr) {
+				switch ((*ip_fw_chk_ptr)(n, n->m_pkthdr.rcvif, IP_FW_IN|IP_FW_INPUT2, 0, last->inp_socket)) {
+					case -1:
+						goto skip_send;
+					case 0:
+						break;
+					default:
+						panic("raw_ip ipfw divert attempt"); /* should have been diverted already */
+						break;
+				}
+			}
+#endif
 			if (n) {
 				if (last->inp_flags & INP_CONTROLOPTS ||
 				    last->inp_socket->so_options & SO_TIMESTAMP)
@@ -137,10 +146,24 @@
 					sorwakeup(last->inp_socket);
 				opts = 0;
 			}
+		skip_send:
 		}
 		last = inp;
 	}
 	if (last) {
+#ifdef IPFIREWALL_CREDENTIALS
+		if (ip_fw_chk_ptr) {
+			switch ((*ip_fw_chk_ptr)(m, m->m_pkthdr.rcvif, IP_FW_IN|IP_FW_INPUT2, 0, last->inp_socket)) {
+				case -1:
+					return;
+				case 0:
+					break;
+				default:
+					panic("raw_ip ipfw divert attempt"); /* should have been diverted already */
+					break;
+			}
+		}
+#endif
 		if (last->inp_flags & INP_CONTROLOPTS ||
 		    last->inp_socket->so_options & SO_TIMESTAMP)
 			ip_savecontrol(last, &opts, ip, m);
@@ -211,7 +234,7 @@
 		ipstat.ips_rawout++;
 	}
 	return (ip_output(m, inp->inp_options, &inp->inp_route, flags,
-			  inp->inp_moptions));
+			  inp->inp_moptions, so));
 }
 
 /*
@@ -253,7 +276,7 @@
 		}
 		return (error);
 
-#ifdef COMPAT_IPFW
+#ifdef IPFIREWALL
 	case IP_FW_GET:
 		if (ip_fw_ctl_ptr == NULL || op == PRCO_SETOPT) {
 			if (*m) (void)m_free(*m);
Index: src/sys/netinet/tcp_input.c
diff -u src/sys/netinet/tcp_input.c:1.55 src/sys/netinet/tcp_input.c:1.56
--- src/sys/netinet/tcp_input.c:1.55	Sun Nov 10 18:37:24 1996
+++ src/sys/netinet/tcp_input.c	Sat Jan  4 15:20:02 1997
@@ -31,10 +31,12 @@
  * SUCH DAMAGE.
  *
  *	@(#)tcp_input.c	8.12 (Berkeley) 5/24/95
- *	$Id: tcp_input.c,v 1.55 1996/11/10 07:37:24 fenner Exp $
+ *	$Id: tcp_input.c,v 1.56 1997/01/04 04:20:02 proff Exp $
  */
 
 #ifndef TUBA_INCLUDE
+#include "opt_ipfw.h"
+
 #include <sys/param.h>
 #include <sys/queue.h>
 #include <sys/systm.h>
@@ -64,6 +66,9 @@
 #include <netinet/tcp_timer.h>
 #include <netinet/tcp_var.h>
 #include <netinet/tcpip.h>
+#ifdef IPFIREWALL_CREDENTIALS
+#  include <netinet/ip_fw.h>
+#endif
 #ifdef TCPDEBUG
 #include <netinet/tcp_debug.h>
 static struct	tcpiphdr tcp_saveti;
@@ -384,13 +389,39 @@
 	if (tp->t_state == TCPS_CLOSED)
 		goto drop;
 
+	so = inp->inp_socket;
+
+#ifdef IPFIREWALL_CREDENTIALS
+	if (ip_fw_chk_ptr) {
+
+		/* Remember! Some tcpfields have been NTOHS'd prior. Presently
+		   ipfw doesn't look at them, but the future may bring wooden horses */
+
+		m->m_data -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
+		m->m_len  += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
+
+		switch ((*ip_fw_chk_ptr)(m, m->m_pkthdr.rcvif, IP_FW_IN|IP_FW_INPUT2, 0, so)) {
+			case -1:
+				if (dropsocket) /* not convinced we need this */
+					(void)soabort(so);
+				return;
+			case 0:
+				break;
+			default:
+				panic("tcp_input ipfw divert attempt"); /* should have been diverted already */
+				break;
+		}
+		m->m_data += sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
+		m->m_len  -= sizeof(struct tcpiphdr)+off-sizeof(struct tcphdr);
+	}
+#endif
+	
 	/* Unscale the window into a 32-bit value. */
 	if ((tiflags & TH_SYN) == 0)
 		tiwin = ti->ti_win << tp->snd_scale;
 	else
 		tiwin = ti->ti_win;
 
-	so = inp->inp_socket;
 	if (so->so_options & (SO_DEBUG|SO_ACCEPTCONN)) {
 #ifdef TCPDEBUG
 		if (so->so_options & SO_DEBUG) {
Index: src/sys/netinet/tcp_output.c
diff -u src/sys/netinet/tcp_output.c:1.21 src/sys/netinet/tcp_output.c:1.22
--- src/sys/netinet/tcp_output.c:1.21	Sat Jun  8 18:19:00 1996
+++ src/sys/netinet/tcp_output.c	Sat Jan  4 15:20:03 1997
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)tcp_output.c	8.4 (Berkeley) 5/24/95
- *	$Id: tcp_output.c,v 1.21 1996/06/08 08:19:00 bde Exp $
+ *	$Id: tcp_output.c,v 1.22 1997/01/04 04:20:03 proff Exp $
  */
 
 #include <sys/param.h>
@@ -690,7 +690,7 @@
 	}
 #endif
 	error = ip_output(m, tp->t_inpcb->inp_options, &tp->t_inpcb->inp_route,
-	    so->so_options & SO_DONTROUTE, 0);
+	    so->so_options & SO_DONTROUTE, 0, so);
     }
 	if (error) {
 out:
Index: src/sys/netinet/tcp_subr.c
diff -u src/sys/netinet/tcp_subr.c:1.31 src/sys/netinet/tcp_subr.c:1.32
--- src/sys/netinet/tcp_subr.c:1.31	Thu Jul 25 04:46:19 1996
+++ src/sys/netinet/tcp_subr.c	Sat Jan  4 15:20:03 1997
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)tcp_subr.c	8.2 (Berkeley) 5/24/95
- *	$Id: tcp_subr.c,v 1.31 1996/07/24 18:46:19 wollman Exp $
+ *	$Id: tcp_subr.c,v 1.32 1997/01/04 04:20:03 proff Exp $
  */
 
 #include <sys/param.h>
@@ -236,7 +236,7 @@
 	if (tp == NULL || (tp->t_inpcb->inp_socket->so_options & SO_DEBUG))
 		tcp_trace(TA_OUTPUT, 0, tp, ti, 0);
 #endif
-	(void) ip_output(m, NULL, ro, 0, NULL);
+	(void) ip_output(m, NULL, ro, 0, NULL, tp? tp->t_inpcb->inp_socket: NULL);
 	if (ro == &sro && ro->ro_rt) {
 		RTFREE(ro->ro_rt);
 	}
Index: src/sys/netinet/udp_usrreq.c
diff -u src/sys/netinet/udp_usrreq.c:1.31 src/sys/netinet/udp_usrreq.c:1.32
--- src/sys/netinet/udp_usrreq.c:1.31	Mon Nov 11 15:56:32 1996
+++ src/sys/netinet/udp_usrreq.c	Sat Jan  4 15:20:03 1997
@@ -31,9 +31,11 @@
  * SUCH DAMAGE.
  *
  *	@(#)udp_usrreq.c	8.6 (Berkeley) 5/23/95
- *	$Id: udp_usrreq.c,v 1.31 1996/11/11 04:56:32 fenner Exp $
+ *	$Id: udp_usrreq.c,v 1.32 1997/01/04 04:20:03 proff Exp $
  */
 
+#include "opt_ipfw.h"
+
 #include <sys/param.h>
 #include <sys/queue.h>
 #include <sys/systm.h>
@@ -60,6 +62,9 @@
 #include <netinet/ip_icmp.h>
 #include <netinet/udp.h>
 #include <netinet/udp_var.h>
+#ifdef IPFIREWALL_CREDENTIALS
+#  include <netinet/ip_fw.h>
+#endif
 
 /*
  * UDP protocol implementation.
@@ -263,6 +268,28 @@
 			udpstat.udps_noportbcast++;
 			goto bad;
 		}
+#ifdef IPFIREWALL_CREDENTIALS
+		if (ip_fw_chk_ptr) {
+			/* in order to create the false-header for cksuming, parts
+			   of the original iphdr were cleared. restore them */
+			*ip=save_ip;
+			m->m_len += sizeof (struct udpiphdr);
+			m->m_data -= sizeof (struct udpiphdr);
+			switch ((*ip_fw_chk_ptr)(m, m->m_pkthdr.rcvif, IP_FW_IN|IP_FW_INPUT2, 0, last->inp_socket)) {
+				case -1:
+					if (opts)
+						m_freem(opts);
+					return;
+				case 0:
+					break;
+				default:
+					panic("udp_input ipfw divert attempt"); /* should have been diverted already */
+					break;
+			}
+			m->m_len -= sizeof (struct udpiphdr);
+			m->m_data += sizeof (struct udpiphdr);
+		}
+#endif
 		if (last->inp_flags & INP_CONTROLOPTS
 		    || last->inp_socket->so_options & SO_TIMESTAMP)
 			ip_savecontrol(last, &opts, ip, m);
@@ -299,6 +326,25 @@
 		icmp_error(m, ICMP_UNREACH, ICMP_UNREACH_PORT, 0, 0);
 		return;
 	}
+#ifdef IPFIREWALL_CREDENTIALS
+	if (ip_fw_chk_ptr) {
+		m->m_len += sizeof (struct udpiphdr);
+		m->m_data -= sizeof (struct udpiphdr);
+		switch ((*ip_fw_chk_ptr)(m, m->m_pkthdr.rcvif, IP_FW_IN|IP_FW_INPUT2, 0, inp->inp_socket)) {
+			case -1:
+				if (opts)
+					m_freem(opts);
+				return;
+			case 0:
+				break;
+			default:
+				panic("udp_input ipfw divert attempt"); /* should have been diverted already */
+				break;
+		}
+		m->m_len -= sizeof (struct udpiphdr);
+		m->m_data += sizeof (struct udpiphdr);
+	}
+#endif
 
 	/*
 	 * Construct sockaddr format source address.
@@ -441,7 +487,7 @@
 	udpstat.udps_opackets++;
 	error = ip_output(m, inp->inp_options, &inp->inp_route,
 	    inp->inp_socket->so_options & (SO_DONTROUTE | SO_BROADCAST),
-	    inp->inp_moptions);
+	    inp->inp_moptions, inp->inp_socket);
 
 	if (addr) {
 		in_pcbdisconnect(inp);
Index: src/sys/conf/options
diff -u src/sys/conf/options:1.23 src/sys/conf/options:1.24
--- src/sys/conf/options:1.23	Fri Dec 27 10:38:17 1996
+++ src/sys/conf/options	Sat Jan  4 15:20:15 1997
@@ -1,4 +1,4 @@
-#	$Id: options,v 1.23 1996/12/26 23:38:17 peter Exp $
+#	$Id: options,v 1.24 1997/01/04 04:20:15 proff Exp $
 
 # Format:
 # Option name	filename
@@ -87,3 +87,4 @@
 IPFIREWALL		opt_ipfw.h
 IPFIREWALL_VERBOSE	opt_ipfw.h
 IPFIREWALL_VERBOSE_LIMIT	opt_ipfw.h
+IPFIREWALL_CREDENTIALS		opt_ipfw.h
Index: src/sys/kern/uipc_socket.c
diff -u src/sys/kern/uipc_socket.c:1.21 src/sys/kern/uipc_socket.c:1.23
--- src/sys/kern/uipc_socket.c:1.21	Sat Nov 30 06:03:42 1996
+++ src/sys/kern/uipc_socket.c	Mon Jan  6 05:38:25 1997
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)uipc_socket.c	8.3 (Berkeley) 4/15/94
- * $Id: uipc_socket.c,v 1.21 1996/11/29 19:03:42 davidg Exp $
+ * $Id: uipc_socket.c,v 1.23 1997/01/05 18:38:25 proff Exp $
  */
 
 #include <sys/param.h>
@@ -88,6 +88,8 @@
 	so->so_type = type;
 	if (p->p_ucred->cr_uid == 0)
 		so->so_state = SS_PRIV;
+	so->so_ucred = *p->p_ucred;
+	so->so_pid = p->p_pid;
 	so->so_proto = prp;
 	error = (*prp->pr_usrreqs->pru_attach)(so, proto);
 	if (error) {
Index: src/sys/kern/uipc_syscalls.c
diff -u src/sys/kern/uipc_syscalls.c:1.20 src/sys/kern/uipc_syscalls.c:1.21
--- src/sys/kern/uipc_syscalls.c:1.20	Wed Oct 16 05:28:44 1996
+++ src/sys/kern/uipc_syscalls.c	Sat Jan  4 15:20:12 1997
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)uipc_syscalls.c	8.4 (Berkeley) 2/21/94
- * $Id: uipc_syscalls.c,v 1.20 1996/10/15 19:28:44 wollman Exp $
+ * $Id: uipc_syscalls.c,v 1.21 1997/01/04 04:20:12 proff Exp $
  */
 
 #include "opt_ktrace.h"
@@ -981,12 +981,17 @@
 	error = getsock(p->p_fd, uap->s, &fp);
 	if (error)
 		return (error);
-	if (uap->valsize > MLEN)
+	if (uap->valsize > MCLBYTES)
 		return (EINVAL);
 	if (uap->val) {
 		m = m_get(M_WAIT, MT_SOOPTS);
 		if (m == NULL)
 			return (ENOBUFS);
+		if (uap->valsize > MLEN) {
+			MCLGET(m, M_WAIT);
+			if (!(m->m_flags & M_EXT))
+				return (ENOBUFS);
+		}
 		error = copyin(uap->val, mtod(m, caddr_t), (u_int)uap->valsize);
 		if (error) {
 			(void) m_free(m);
Index: src/sys/sys/socketvar.h
diff -u src/sys/sys/socketvar.h:1.16 src/sys/sys/socketvar.h:1.18
--- src/sys/sys/socketvar.h:1.16	Tue Nov 12 21:26:37 1996
+++ src/sys/sys/socketvar.h	Mon Jan  6 05:38:46 1997
@@ -31,7 +31,7 @@
  * SUCH DAMAGE.
  *
  *	@(#)socketvar.h	8.3 (Berkeley) 2/19/95
- * $Id: socketvar.h,v 1.16 1996/11/12 10:26:37 bde Exp $
+ * $Id: socketvar.h,v 1.18 1997/01/05 18:38:46 proff Exp $
  */
 
 #ifndef _SYS_SOCKETVAR_H_
@@ -39,6 +39,7 @@
 
 #include <sys/queue.h>			/* for TAILQ macros */
 #include <sys/select.h>			/* for struct selinfo */
+#include <sys/ucred.h>			/* for struct u_cred */
 
 /*
  * Kernel structure per socket.
@@ -102,6 +103,8 @@
 	caddr_t	so_tpcb;		/* Wisc. protocol control block XXX */
 	void	(*so_upcall) __P((struct socket *so, caddr_t arg, int waitf));
 	caddr_t	so_upcallarg;		/* Arg for above */
+	struct	ucred so_ucred;		/* Creator credentials */
+	pid_t	so_pid;			/* Creator pid */
 };
 
 /*
Index: src/sys/sys/ucred.h
diff -u src/sys/sys/ucred.h:1.6 src/sys/sys/ucred.h:1.7
--- src/sys/sys/ucred.h:1.6	Mon Mar 11 13:11:48 1996
+++ src/sys/sys/ucred.h	Sat Jan  4 15:20:09 1997
@@ -31,11 +31,13 @@
  * SUCH DAMAGE.
  *
  *	@(#)ucred.h	8.4 (Berkeley) 1/9/95
- * $Id: ucred.h,v 1.6 1996/03/11 02:11:48 hsu Exp $
+ * $Id: ucred.h,v 1.7 1997/01/04 04:20:09 proff Exp $
  */
 
 #ifndef _SYS_UCRED_H_
 #define	_SYS_UCRED_H_
+
+#include <sys/param.h>
 
 /*
  * Credentials.
--- src/sbin/ipfw/ipfw.8.orig	Sat Jan  4 15:32:09 1997
+++ src/sbin/ipfw/ipfw.8	Mon Jan  6 08:16:14 1997
@@ -11,38 +11,28 @@
 flush
 .Nm ipfw
 zero
-.Oo
-.Ar number
-.Oc
+.Op Ar number
 .Nm ipfw
 delete
 .Ar number
 .Nm ipfw
-.Oo
-.Fl aftN
-.Oc
+.Op Fl aftN
 list
 .Nm ipfw
 add
-.Oo
-.Ar number
-.Oc
+.Op Ar number
 .Ar action 
-.Oo
-log
-.Oc
+.Op Ar log
 .Ar proto
 from
 .Ar src
 to
 .Ar dst
-.Oo 
+.Oo
 via
-.Ar name|ipno
-.Oc
-.Oo 
-.Ar options
+.Ar name | ipno
 .Oc
+.Op Ar options
 .Sh DESCRIPTION
 If used as shown in the first synopsis line, the
 .Ar file
@@ -58,7 +48,7 @@
 a byte count.
 These counters are updated when a packet matches the rule.
 .Pp
-The rules are ordered by a ``line-number'' from 1 to 65534 that is used
+The rules are ordered by a ``line-number'' from 1 to 65533 that is used
 to order and delete rules. Rules are tried in increasing order, and the
 first rule that matches a packet applies.
 Multiple rules may share the same number and apply in
@@ -66,7 +56,7 @@
 .Pp
 If a rule is added without a number, it numbered 100 higher
 than the previous rule. If the highest defined rule number is
-greater than 65434, new rules are appended to the last rule.
+greater than 65433, new rules are appended to the last rule.
 .Pp
 The delete operation deletes the first rule with number
 .Ar number ,
@@ -83,10 +73,18 @@
 .Bd -literal -offset center
 65535 deny all from any to any
 .Ed
-
+.Pp
 This rule is the default policy, i.e., don't allow anything at all.
 Your job in setting up rules is to modify this policy to match your needs.
 .Pp
+If the kernel was compiled with IPFIREWALL_CREDENTIALS, the ruleset
+also contains:
+.Bd -literal -offset center
+65534 deny all from any to any bind
+.Ed
+.Pp
+Which denies all bind() attempts.
+.Pp
 The following options are available:
 .Bl -tag -width flag
 .It Fl a
@@ -105,51 +103,58 @@
 .Pp
 .Ar action :
 .Bl -hang -offset flag -width 1234567890123456
-.It Nm allow
+.It Ar allow
 Allow packets that match rule.
 The search terminates.
-.It Nm pass
+.It Ar pass
 Same as allow.
-.It Nm accept
+.It Ar accept
 Same as allow.
-.It Nm count
+.It Ar count
 Update counters for all packets that match rule.
 The search continues with the next rule.
-.It Nm deny
+.It Ar deny
 Discard packets that match this rule.
 The search terminates.
-.It Nm reject
+.It Ar reject
 Discard packets that match this rule, and try to send an ICMP notice.
 The search terminates.
-.It Nm divert port
+.It Ar divert port
 Divert packets that match this rule to the divert socket bound to port
 .Ar port .
 The search terminates.
 .El
 .Pp
+If the keyword
+.Ar wormhole
+is specified immediately after an accept action, and the rule is a bind rule, 
+then permit the binding even if the IPPORT_RESERVED check would otherwise
+deny the bind() attempt. This is useful for punching holes in the reserved
+port range for programs running without privilage.
+.Pp
 When a packet matches a rule with the
-.Nm log
+.Ar log
 keyword, a message will be printed on the console.
 If the kernel was compiled with the
-.Nm IP_FIREWALL_VERBOSE_LIMIT
+.Dv IP_FIREWALL_VERBOSE_LIMIT
 option, then logging will cease after the number of packets
-specified by the option are recieved for that particular
+specified by the option are received for that particular
 chain entry.  Logging may then be re-enabled by clearing
 the packet counter for that entry.
 .Pp
 .Ar proto :
 .Bl -hang -offset flag -width 1234567890123456
-.It Nm ip
+.It Ar ip
 All packets match.
-.It Nm all
+.It Ar all
 All packets match.
-.It Nm tcp
+.It Ar tcp
 Only TCP packets match.
-.It Nm udp
+.It Ar udp
 Only UDP packets match.
-.It Nm icmp
+.It Ar icmp
 Only ICMP packets match.
-.It Nm <number|name>
+.It Ar <number|name>
 Only packets for the specified protocol matches (see
 .Pa /etc/protocols
 for a complete list).
@@ -193,8 +198,9 @@
 may not be used instead of a numeric port value.
 Also, note that a range may only be specified as the first value,
 and the port list is limited to
-.Nm IP_FW_MAX_PORTS
-(as defined in /usr/src/sys/netinet/ip_fw.h)
+.Dv IP_FW_MAX_PORTS
+(as defined in 
+.Pa /usr/src/sys/netinet/ip_fw.h )
 ports.
 .Pp
 If ``via''
@@ -225,13 +231,13 @@
 options specified in
 .Ar spec .
 The supported IP options are:
-.Nm ssrr 
+.Ar ssrr 
 (strict source route),
-.Nm lsrr 
+.Ar lsrr 
 (loose source route),
-.Nm rr 
+.Ar rr 
 (record packet route), and
-.Nm ts 
+.Ar ts 
 (timestamp).
 The absence of a particular option may be denoted
 with a ``!''.
@@ -246,13 +252,13 @@
 flags specified in
 .Ar spec .
 The supported TCP flags are:
-.Nm fin ,
-.Nm syn ,
-.Nm rst ,
-.Nm psh ,
-.Nm ack ,
+.Ar fin ,
+.Ar syn ,
+.Ar rst ,
+.Ar psh ,
+.Ar ack ,
 and
-.Nm urg .
+.Ar urg .
 The absence of a particular flag may be denoted
 with a ``!''.
 .It icmptypes Ar types
@@ -260,11 +266,82 @@
 .Ar types .
 The list may be specified as any combination of ranges
 or individual types separated by commas.
+.It uid Ar user
+Matches if the packet is associated with a socket created by
+.Ar user .
+The username
+.Ar any
+matches any user. 
+.It gid Ar group
+Matches if the packet is associated with a socket created by
+a user who at the time held the primary or secondary group
+.Ar group .
+The group
+.Ar any
+matches any group.
+.Pp
+Socket credential rule-matching on packets varies slightly according
+to the direction of the packet being examined. This is necessitated,
+as to start with we do not know if an incoming packet is associated
+with a local client, is being forwarded, or is to be handled by the
+kernel directly. First the incoming packet is matched against all
+non-credential rules. If the packet is accepted, it then passes to
+the protocol layer. If the protocol layer is sucessful in locating
+a socket on which to deliver the packet, then the
+packet is re-examined, passing through the firewall ruleset for the
+second time. On the second occasion only socket credential rules
+are matched against. If packet is accepted, it is delivered to the
+socket, otherwise it is dropped or rejected.
+.Pp
+Output is somewhat simpler, as we immediately know the
+socket credentials of the socket sending the packet. This means
+we can match against the ruleset in one pass.
+.Pp
+Socket credential matches are not enabled unless the kernel was compiled with
+IPFIREWALL_CREDENTIALS.
+.It bind
+Don't match this rule against packets, but against the
+system call bind(). 
+Only a specific set
+of information can be used for matches when this keyword is specified:
+.Ar protocol ,
+.Ar src ,
+.Ar sport ,
+.Ar interface ,
+.Ar uid 
+and
+.Ar gid .
+.Pp
+.Ar src
+is the interface address requested or 0.0.0.0 if no
+specific interface address was requested.
+.Pp
+.Ar interface
+is the interface address, if requested, unless
+the address belongs to a multi-cast group.
+.Pp
+.Ar sport
+is the port requested, unless no specific port was requested.
+In this latter case the source port will be the port
+is the port allocated by the system.
+.Pp
+.Ar uid
+and
+.Ar gid
+are those credentials held at the time
+of socket() creation,
+.Em not
+those held at the instant bind() was called.
+.Pp
+The 
+.Ar bind
+flag is not enabled unless the kernel was compiled with
+IPFIREWALL_CREDENTIALS.
 .El
 .Sh CHECKLIST
 Here are some important points to consider when designing your
 rules:
-.Bl -bullet -hang -offset flag -width 1234567890123456
+.Bl -bullet -hang -offset flag 
 .It 
 Remember that you filter both packets going in and out.
 Most connections need packets going in both directions.
@@ -288,12 +365,12 @@
 modload /lkm/ipfw_mod.o && \e
 ipfw add 32000 allow all from any to any
 .Ed
-
+.Pp
 Along the same lines, doing an
 .Bd -literal -offset center
 ipfw flush
 .Ed
-
+.Pp
 in similar surroundings is also a bad idea.
 .Sh PACKET DIVERSION
 A divert socket bound to the specified port will receive all packets diverted
@@ -346,6 +423,18 @@
 .Pp
 When manipulating/adding chain entries, service and protocol names are
 not accepted.
+.Pp
+In order to specify a user or group with the name "any" it is necessary to
+use the numeric uid or gid.
+.Pp
+Rules that match against socket credentials, will not reliably match
+against ip-options at the same time.
+.Pp
+Socket credentials currently do match against packets associated with
+.Em divert
+sockets or
+.Em BPF
+file descriptors. This is possibly a feature.
 .Sh AUTHORS
 Ugen J. S. Antsilevich,
 Poul-Henning Kamp,
--- src/sbin/ipfw/ipfw.c.orig	Thu Jan  2 13:56:56 1997
+++ src/sbin/ipfw/ipfw.c	Mon Jan  6 08:20:29 1997
@@ -25,6 +25,8 @@
 #include <sys/socket.h>
 #include <sys/sockio.h>
 #include <sys/time.h>
+#include <machine/param.h>
+#include <sys/mbuf.h>
 
 #include <ctype.h>
 #include <err.h>
@@ -35,6 +37,8 @@
 #include <string.h>
 #include <time.h>
 #include <unistd.h>
+#include <pwd.h>
+#include <grp.h>
 
 #include <net/if.h>
 #include <netinet/in.h>
@@ -152,6 +156,9 @@
 		default:
 			errx(1, "impossible");
 	}
+
+	if (chain->fw_flg & IP_FW_F_WORMHOLE)
+		printf(" wormhole");
    
 	if (chain->fw_flg & IP_FW_F_PRN)
 		printf(" log");
@@ -318,6 +325,32 @@
 				first = 0;
 			}
 	}
+	if (chain->fw_flg & IP_FW_F_UID) {
+		printf(" uid ");
+		if (chain->fw_uid == (uid_t)-1)
+			printf("any");
+		else {
+			struct	passwd *pw = getpwuid(chain->fw_uid);
+			if (pw && pw->pw_name && pw->pw_name[0])
+				printf("%s", pw->pw_name);
+			else
+				printf("%d", chain->fw_uid);
+		}
+	}
+	if (chain->fw_flg & IP_FW_F_GID) {
+		printf(" gid ");
+		if (chain->fw_gid == (gid_t)-1)
+			printf("any");
+		else {
+			struct	group *gr = getgrgid(chain->fw_gid);
+			if (gr && gr->gr_name && gr->gr_name[0])
+				printf("%s", gr->gr_name);
+			else
+				printf("%d", chain->fw_gid);
+		}
+	}
+	if (chain->fw_flg & IP_FW_F_BIND)
+		printf(" bind");
 	printf("\n");
 	if (do_resolv)
 		endservent();
@@ -356,7 +389,7 @@
 "\t\tlist [number]\n"
 "\t\tzero [number]\n"
 "\trule:\taction proto src dst extras...\n"
-"\t\taction: {allow|deny|reject|count|divert port} [log]\n"
+"\t\taction: {allow|deny|reject|count|divert port} [wormhole] [log]\n"
 "\t\tproto: {ip|tcp|udp|icmp|<number>}}\n"
 "\t\tsrc: from {any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n"
 "\t\tdst: to {any|ip[{/bits|:mask}]} [{port|port-port},[port],...]\n"
@@ -369,6 +402,9 @@
 "\t\tipoptions [!]{ssrr|lsrr|rr|ts},...\n"
 "\t\ticmptypes {type},...\n"
 "\t\tproto {ipproto},...\n"
+"\t\tuid {any|user},...\n"
+"\t\tgid {any|group},...\n"
+"\t\tbind,...\n"
 , progname
 );
 
@@ -662,6 +698,11 @@
 		show_usage("missing/unrecognized action\n");
 	}
 
+	/* [wormhole] */
+	if (ac && !strncmp(*av,"wormhole",strlen(*av))) {
+		rule.fw_flg |= IP_FW_F_WORMHOLE; av++; ac--;
+	}
+
 	/* [log] */
 	if (ac && !strncmp(*av,"log",strlen(*av))) {
 		rule.fw_flg |= IP_FW_F_PRN; av++; ac--;
@@ -776,6 +817,52 @@
 				fill_icmptypes(rule.fw_icmptypes, av, &rule.fw_flg);
 				av++; ac--; continue;
 			}
+		}
+		if (ac > 1 && !strncmp(*av,"uid",strlen(*av))) { 
+			char *p;
+			int uid;
+			av++; ac--;
+			rule.fw_flg |= IP_FW_F_UID;
+			uid=strtol(*av, &p, 10);
+			if (p==*av) {
+				if (strcmp(*av, "any")==0)
+					uid = (uid_t)-1;
+				else {
+					struct passwd *pw = getpwnam(*av);
+					if (!pw) {
+						perror(*av);
+						exit(1);
+					}
+					uid = pw->pw_uid;
+				}
+			}
+			rule.fw_uid = uid;
+			av++; ac--; continue;
+		}
+		if (ac > 1 && !strncmp(*av,"gid",strlen(*av))) { 
+			char *p;
+			int gid;
+			av++; ac--;
+			rule.fw_flg |= IP_FW_F_GID;
+			gid=strtol(*av, &p, 10);
+			if (p==*av) {
+				if (strcmp(*av, "any")==0)
+					gid = (gid_t)-1;
+				else {
+					struct group *gr = getgrnam(*av);
+					if (!gr) {
+						perror(*av);
+						exit(1);
+					}
+					gid = gr->gr_gid;
+				}
+			}
+			rule.fw_gid = gid;
+			av++; ac--; continue;
+		}
+		if (ac && !strncmp(*av,"bind",strlen(*av))) {
+			rule.fw_flg |= IP_FW_F_BIND; av++; ac--;
+			continue;
 		}
 		printf("%d %s\n",ac,*av);
 		show_usage("Unknown argument\n");
>Release-Note:
>Audit-Trail:
Responsible-Changed-From-To: gnats-admin->freebsd-bugs 
Responsible-Changed-By: gpalmer 
Responsible-Changed-When: Mon Jan 6 17:14:25 PST 1997 
Responsible-Changed-Why:  
Misfiled PR 
State-Changed-From-To: open->closed 
State-Changed-By: phk 
State-Changed-When: Sun Apr 26 10:30:58 PDT 1998 
State-Changed-Why:  
timed out 
>Unformatted:
