patch-2.4.20 linux-2.4.20/net/netlink/af_netlink.c

Next file: linux-2.4.20/net/netsyms.c
Previous file: linux-2.4.20/net/khttpd/waitheaders.c
Back to the patch index
Back to the overall index

diff -urN linux-2.4.19/net/netlink/af_netlink.c linux-2.4.20/net/netlink/af_netlink.c
@@ -39,6 +39,7 @@
 #include <linux/rtnetlink.h>
 #include <linux/proc_fs.h>
 #include <linux/smp_lock.h>
+#include <linux/notifier.h>
 #include <net/sock.h>
 #include <net/scm.h>
 
@@ -64,6 +65,7 @@
 
 static struct sock *nl_table[MAX_LINKS];
 static DECLARE_WAIT_QUEUE_HEAD(nl_table_wait);
+static unsigned nl_nonroot[MAX_LINKS];
 
 #ifdef NL_EMULATE_DEV
 static struct socket *netlink_kernel[MAX_LINKS];
@@ -77,6 +79,8 @@
 static rwlock_t nl_table_lock = RW_LOCK_UNLOCKED;
 static atomic_t nl_table_users = ATOMIC_INIT(0);
 
+static struct notifier_block *netlink_chain;
+
 static void netlink_sock_destruct(struct sock *sk)
 {
 	skb_queue_purge(&sk->receive_queue);
@@ -269,6 +273,12 @@
 
 	skb_queue_purge(&sk->write_queue);
 
+	if (sk->protinfo.af_netlink->pid && !sk->protinfo.af_netlink->groups) {
+		struct netlink_notify n = { protocol:sk->protocol,
+		                            pid:sk->protinfo.af_netlink->pid };
+		notifier_call_chain(&netlink_chain, NETLINK_URELEASE, &n);
+	}	
+	
 	sock_put(sk);
 	return 0;
 }
@@ -301,6 +311,11 @@
 	return 0;
 }
 
+static inline int netlink_capable(struct socket *sock, unsigned flag) 
+{ 
+	return (nl_nonroot[sock->sk->protocol] & flag) || capable(CAP_NET_ADMIN);
+} 
+
 static int netlink_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
 {
 	struct sock *sk = sock->sk;
@@ -311,7 +326,7 @@
 		return -EINVAL;
 
 	/* Only superuser is allowed to listen multicasts */
-	if (nladdr->nl_groups && !capable(CAP_NET_ADMIN))
+	if (nladdr->nl_groups && !netlink_capable(sock, NL_NONROOT_RECV))
 		return -EPERM;
 
 	if (sk->protinfo.af_netlink->pid) {
@@ -350,7 +365,7 @@
 		return -EINVAL;
 
 	/* Only superuser is allowed to send multicasts */
-	if (nladdr->nl_groups && !capable(CAP_NET_ADMIN))
+	if (nladdr->nl_groups && !netlink_capable(sock, NL_NONROOT_SEND))
 		return -EPERM;
 
 	if (!sk->protinfo.af_netlink->pid)
@@ -565,7 +580,7 @@
 			return -EINVAL;
 		dst_pid = addr->nl_pid;
 		dst_groups = addr->nl_groups;
-		if (dst_groups && !capable(CAP_NET_ADMIN))
+		if (dst_groups && !netlink_capable(sock, NL_NONROOT_SEND))
 			return -EPERM;
 	} else {
 		dst_pid = sk->protinfo.af_netlink->dst_pid;
@@ -715,6 +730,12 @@
 	return sk;
 }
 
+void netlink_set_nonroot(int protocol, unsigned flags)
+{ 
+	if ((unsigned)protocol < MAX_LINKS) 
+		nl_nonroot[protocol] = flags;
+} 
+
 static void netlink_destroy_callback(struct netlink_callback *cb)
 {
 	if (cb->skb)
@@ -945,6 +966,16 @@
 }
 #endif
 
+int netlink_register_notifier(struct notifier_block *nb)
+{
+	return notifier_chain_register(&netlink_chain, nb);
+}
+
+int netlink_unregister_notifier(struct notifier_block *nb)
+{
+	return notifier_chain_unregister(&netlink_chain, nb);
+}
+                
 struct proto_ops netlink_ops = {
 	family:		PF_NETLINK,
 

FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)