diff -Nurd linux-orig/Documentation/Configure.help linux/Documentation/Configure.help
--- linux-orig/Documentation/Configure.help	Fri Nov  2 08:39:05 2001
+++ linux/Documentation/Configure.help	Fri Nov  2 22:58:38 2001
@@ -3485,7 +3485,75 @@
   through the old netlink interface. However, a better option is to
   say Y to "Kernel/User network link driver" and to "Routing
   messages" instead.
-  
+
+IP: port/socket pseudo ACLs
+CONFIG_PSEUDO_ACLS
+  If you say yes here, config will ask a few more questions about port
+  and socket ACLs.
+
+IP: port pseudo ACLs
+CONFIG_PORT_ACLS
+  This simple hack allows root to delegate the ability to bind to
+  a reserved port (port < 1024) to non-privileged users, much like
+  CAP_NET_BIND_SERVICE; however, it allows much finer access control
+  than the capability.  By setgid-ing any binary owned by the gid
+  specified in /proc/sys/net/ipv[46]/port_acl_gid, non-root users will
+  be able to use that binary to bind to the tcp or udp port equal to
+  their system uid.
+
+  For instance, perhaps one would like to run snmpd as non-privileged
+  user "snmp," simply:
+
+    Say yes here and compile a new kernel, then reboot into it.
+    Create a user "snmp" in /etc/passwd with a uid of 161.
+    Create a group "portacl" with an unused gid, $gid here.
+    # echo $gid > /proc/sys/net/ipv4/ip_port_acl_gid
+    # chown root.$gid /usr/sbin/snmpd
+    # chmod 2755 /usr/sbin/snmpd
+    # su - snmp -c /usr/sbin/snmpd -r
+
+  You will most likely need to tweak the snmpd configs a bit, too.
+
+  For more info, check http://original.killa.net/infosec/acls/index.html
+
+IP: Raw socket group
+CONFIG_SOCK_RAW_GROUP
+  Say yes here if you wish to give a special group access to raw sockets.
+  Any raw-socket-needing binary setgid this group will not require root
+  access to do its duty.  This may mitigate any as yet unknown exploits
+  for a class of setuid zero networking applications, such as ping,
+  traceroute or mtr.
+
+  SOCK_RAW sockets work at the IP level, layer 3 (Network) in the
+  OSI model.
+
+  You will need to setgid any binaries needing raw sockets to a new gid,
+  and specify that gid in /proc/sys/net/ipv[46]/ip_sock_raw_gid for it to
+  take effect.
+
+  For more info, check http://original.killa.net/infosec/acls/index.html
+
+IP: Packet socket group
+CONFIG_SOCK_PACKET_GROUP
+  This option allows you to split off packet socket privileges to a
+  seperate group.  Unlike CAP_NET_RAW, you will have finer control over
+  which binaries will get SOCK_PACKET privs and which get SOCK_RAW privs.
+
+  SOCK_PACKET sockets work at the device driver level, layer 2 (data link)
+  in the OSI model.  As such, it is a lower level interface than SOCK_RAW.
+  The most common binaries that require packet socket access are those
+  which use the functionality of libpcap (e.g. tcpdump).
+
+  You will need to setgid any binaries needing packet sockets to a new
+  gid, and specify that gid in /proc/sys/net/sock_packet_gid for it to
+  take effect.
+
+  NOTE: I recommend you say yes, unless you have a (weird) application
+  that needs both raw and packet sockets.  This will protect you from
+  any ping/traceroute exploits leading to a sniffer attack.
+
+  For more info, check http://original.killa.net/infosec/acls/index.html
+
 IPX networking
 CONFIG_IPX
   This is support for the Novell networking protocol, IPX, commonly
diff -Nurd linux-orig/include/linux/sysctl.h linux/include/linux/sysctl.h
--- linux-orig/include/linux/sysctl.h	Sun Mar 25 08:37:40 2001
+++ linux/include/linux/sysctl.h	Fri Nov  2 22:58:39 2001
@@ -231,7 +231,11 @@
 	NET_IPV4_ICMP_IGNORE_BOGUS_ERROR_RESPONSES=64,
 	NET_IPV4_IGMP_MAX_MEMBERSHIPS=65,
 	NET_IPV4_ALWAYS_DEFRAG=67,
-	NET_IPV4_IP_MASQ_UDP_DLOOSE=68
+	NET_IPV4_IP_MASQ_UDP_DLOOSE=68,
+	NET_IP_PORT_ACL_GID=69,
+	NET_IP_SOCK_RAW_GID=70,
+	NET_IP_SOCK_PACKET_GID=71
+
 };
 
 enum {
diff -Nurd linux-orig/net/ipv4/Config.in linux/net/ipv4/Config.in
--- linux-orig/net/ipv4/Config.in	Sun Mar 25 08:31:12 2001
+++ linux/net/ipv4/Config.in	Fri Nov  2 22:58:40 2001
@@ -74,6 +74,16 @@
   fi
 fi
 bool 'IP: TCP syncookie support (not enabled per default)' CONFIG_SYN_COOKIES
+if [ "$CONFIG_SYSCTL" = "y" ]; then 
+	bool 'IP: Socket/port pseudo acls' CONFIG_PSEUDO_ACLS
+	if [ "$CONFIG_PSEUDO_ACLS" = "y" ]; then 
+		bool 'IP:   Port ACLs' CONFIG_PORT_ACLS
+  		bool 'IP:   Raw socket group' CONFIG_SOCK_RAW_GROUP
+		if [ "$CONFIG_SOCK_RAW_GROUP" = "y" -a "$CONFIG_PACKET" != "n" ]; then 
+			bool 'IP:     Packet socket group' CONFIG_SOCK_PACKET_GROUP
+		fi
+	fi
+fi
 comment '(it is safe to leave these untouched)'
 #bool 'IP: PC/TCP compatibility mode' CONFIG_INET_PCTCP
 tristate 'IP: Reverse ARP' CONFIG_INET_RARP
@@ -83,4 +93,3 @@
 #if [ "$CONFIG_EXPERIMENTAL" = "y" ]; then 
 #bool 'IP: support experimental checksum copy to user for UDP'  CONFIG_UDP_DELAY_CSUM
 #fi
-
diff -Nurd linux-orig/net/ipv4/af_inet.c linux/net/ipv4/af_inet.c
--- linux-orig/net/ipv4/af_inet.c	Fri Nov  2 08:39:16 2001
+++ linux/net/ipv4/af_inet.c	Fri Nov  2 22:58:40 2001
@@ -123,6 +123,14 @@
 
 #define min(a,b)	((a)<(b)?(a):(b))
 
+#ifdef CONFIG_PORT_ACLS
+int sysctl_port_acl_gid;
+#endif
+
+#ifdef CONFIG_SOCK_RAW_GROUP
+int sysctl_sock_raw_gid;
+#endif
+
 extern int raw_get_info(char *, char **, off_t, int, int);
 extern int snmp_get_info(char *, char **, off_t, int, int);
 extern int netstat_get_info(char *, char **, off_t, int, int);
@@ -380,7 +388,11 @@
 		sock->ops = &inet_dgram_ops;
 		break;
 	case SOCK_RAW:
-		if (!capable(CAP_NET_RAW))
+		if (!capable(CAP_NET_RAW)
+#ifdef CONFIG_SOCK_RAW_GROUP
+			&& current->egid != sysctl_sock_raw_gid
+#endif
+			)
 			goto free_and_badperm;
 		if (!protocol)
 			goto free_and_noproto;
@@ -545,7 +557,12 @@
 	   chk_addr_ret != RTN_MULTICAST)
 		return -EADDRINUSE;
 #endif		 
-	if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
+	if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)
+#ifdef CONFIG_PORT_ACLS
+		&& !(current->uid == snum
+			&& current->egid == sysctl_port_acl_gid)
+#endif
+	)
 		return(-EACCES);
 	
 	/* Make sure we are allowed to bind here. */
diff -Nurd linux-orig/net/ipv4/sysctl_net_ipv4.c linux/net/ipv4/sysctl_net_ipv4.c
--- linux-orig/net/ipv4/sysctl_net_ipv4.c	Fri Nov  2 08:39:16 2001
+++ linux/net/ipv4/sysctl_net_ipv4.c	Fri Nov  2 22:58:40 2001
@@ -61,6 +61,14 @@
 /* From igmp.c */
 extern int sysctl_igmp_max_memberships;
 
+#ifdef CONFIG_PORT_ACLS
+extern int sysctl_port_acl_gid;
+#endif
+ 
+#ifdef CONFIG_SOCK_RAW_GROUP
+extern int sysctl_sock_raw_gid;
+#endif
+ 
 static int tcp_retr1_max = 255; 
 
 static int ip_local_port_range_min[] = { 1, 1 };
@@ -197,6 +205,14 @@
 #ifdef CONFIG_IP_MULTICAST
 	{NET_IPV4_IGMP_MAX_MEMBERSHIPS, "igmp_max_memberships",
 	 &sysctl_igmp_max_memberships, sizeof(int), 0644, NULL, &proc_dointvec},
+#endif
+#ifdef CONFIG_PORT_ACLS
+	{NET_IP_PORT_ACL_GID, "ip_port_acl_gid", &sysctl_port_acl_gid,
+	 sizeof(int), 0644, NULL, &proc_dointvec},
+#endif
+#ifdef CONFIG_SOCK_RAW_GROUP
+	{NET_IP_SOCK_RAW_GID, "ip_sock_raw_gid", &sysctl_sock_raw_gid,
+	 sizeof(int), 0644, NULL, &proc_dointvec},
 #endif
 	{0}
 };
diff -Nurd linux-orig/net/ipv6/af_inet6.c linux/net/ipv6/af_inet6.c
--- linux-orig/net/ipv6/af_inet6.c	Sun Mar 25 08:31:13 2001
+++ linux/net/ipv6/af_inet6.c	Fri Nov  2 22:58:40 2001
@@ -82,8 +82,17 @@
 #ifdef CONFIG_SYSCTL
 extern void ipv6_sysctl_register(void);
 extern void ipv6_sysctl_unregister(void);
+
+#ifdef CONFIG_PORT_ACLS
+int sysctl_port_acl_gid;
 #endif
 
+#ifdef CONFIG_SOCK_RAW_GROUP
+int sysctl_sock_raw_gid;
+#endif
+
+#endif /* CONFIG_SYSCTL */
+
 static int inet6_create(struct socket *sock, int protocol)
 {
 	struct sock *sk;
@@ -107,7 +116,11 @@
 		prot=&udpv6_prot;
 		sock->ops = &inet6_dgram_ops;
 	} else if(sock->type == SOCK_RAW) {
-		if (!capable(CAP_NET_RAW))
+		if (!capable(CAP_NET_RAW)
+#ifdef CONFIG_SOCK_RAW_GROUP
+			&& current->egid != sysctl_sock_raw_gid
+#endif
+		)
 			goto free_and_badperm;
 		if (!protocol) 
 			goto free_and_noproto;
@@ -236,7 +249,12 @@
 		       sizeof(struct in6_addr));
 
 	snum = ntohs(addr->sin6_port);
-	if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
+	if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE)
+#ifdef CONFIG_PORT_ACLS
+		&& !(current->uid == snum
+			&& current->egid == sysctl_port_acl_gid)
+#endif /* CONFIG_PORT_ACLS */
+		)
 		return(-EACCES);
 
 	/* Make sure we are allowed to bind here. */
diff -Nurd linux-orig/net/ipv6/sysctl_net_ipv6.c linux/net/ipv6/sysctl_net_ipv6.c
--- linux-orig/net/ipv6/sysctl_net_ipv6.c	Sun Mar 25 08:31:13 2001
+++ linux/net/ipv6/sysctl_net_ipv6.c	Fri Nov  2 22:58:40 2001
@@ -15,8 +15,24 @@
 
 #ifdef CONFIG_SYSCTL
 
+#ifdef CONFIG_PORT_ACLS
+int sysctl_port_acl_gid;
+#endif
+
+#ifdef CONFIG_SOCK_RAW_GROUP
+extern int sysctl_sock_raw_gid;
+#endif
+
 ctl_table ipv6_table[] = {
 	{NET_IPV6_ROUTE, "route", NULL, 0, 0555, ipv6_route_table},
+#ifdef CONFIG_PORT_ACLS
+	{NET_IP_PORT_ACL_GID, "ip_port_acl_gid", &sysctl_port_acl_gid,
+         sizeof(int), 0644, NULL, &proc_dointvec},
+#endif
+#ifdef CONFIG_SOCK_RAW_GROUP
+	{NET_IP_SOCK_RAW_GID, "ip_sock_raw_gid", &sysctl_sock_raw_gid,
+	 sizeof(int), 0644, NULL, &proc_dointvec},
+#endif
 	{0}
 };
 
diff -Nurd linux-orig/net/packet/af_packet.c linux/net/packet/af_packet.c
--- linux-orig/net/packet/af_packet.c	Sun Mar 25 08:31:14 2001
+++ linux/net/packet/af_packet.c	Fri Nov  2 22:58:40 2001
@@ -80,6 +80,14 @@
 extern int dlci_ioctl(unsigned int, void*);
 #endif
 
+#ifdef CONFIG_SOCK_RAW_GROUP
+#ifdef CONFIG_SOCK_PACKET_GROUP
+int sysctl_sock_packet_gid;
+#else
+int sysctl_sock_raw_gid;
+#endif /* CONFIG_SOCK_PACKET_GROUP */
+#endif /* CONFIG_SOCK_RAW_GROUP */
+
 /*
    Old SOCK_PACKET. Do exist programs, which use it?
    (not counting tcpdump) - lots of them yes - AC. 
@@ -692,7 +700,15 @@
 	struct sock *sk;
 	int err;
 
-	if (!capable(CAP_NET_RAW))
+	if (!capable(CAP_NET_RAW)
+#ifdef CONFIG_SOCK_RAW_GROUP
+#ifdef CONFIG_SOCK_PACKET_GROUP
+		&& current->egid != sysctl_sock_packet_gid
+#else
+		&& current->egid != sysctl_sock_raw_gid
+#endif /* CONFIG_SOCK_PACKET_GROUP */
+#endif /* CONFIG_SOCK_RAW_GROUP */
+		)
 		return -EPERM;
 	if (sock->type != SOCK_DGRAM && sock->type != SOCK_RAW
 #ifdef CONFIG_SOCK_PACKET
diff -Nurd linux-orig/net/sysctl_net.c linux/net/sysctl_net.c
--- linux-orig/net/sysctl_net.c	Sun Mar 25 08:31:13 2001
+++ linux/net/sysctl_net.c	Fri Nov  2 22:58:41 2001
@@ -46,6 +46,10 @@
 extern ctl_table tr_table[];
 #endif
 
+#ifdef CONFIG_SOCK_PACKET_GROUP
+extern int sysctl_sock_packet_gid;
+#endif
+
 ctl_table net_table[] = {
 	{NET_CORE,   "core",      NULL, 0, 0555, core_table},      
 #ifdef CONFIG_UNIX
@@ -70,5 +74,11 @@
 #ifdef CONFIG_TR
 	{NET_TR, "token-ring", NULL, 0, 0555, tr_table},
 #endif
+#ifdef CONFIG_SOCK_PACKET_GROUP
+	{NET_IP_SOCK_PACKET_GID, "ip_sock_packet_gid", &sysctl_sock_packet_gid,
+	 sizeof(int), 0644, NULL, &proc_dointvec},
+#endif
 	{0}
 };
+
+
