[<prev] [next>] [day] [month] [year] [list]
Message-ID: <Pine.LNX.4.64.0712141116340.21142@atlantis>
Date: Fri, 14 Dec 2007 11:38:09 +0100 (CET)
From: Arnauld Michelizza <am@...c.net>
To: netdev@...r.kernel.org
Subject: [patch] authorize some users to bind on specifics priv ports
Really simpler and usable than POSIX/capabilities and I think it
covers basics needs for sysadmins... at least, it covers mine :-)
www-data$ nc -l -p 80 -v
Can't grab 0.0.0.0:80 with bind : Permission denied
root# id -u www-data
33
root# port_acl_set +80 www-data
root# cat /proc/net/port_acl
80: 33
www-data$ nc -l -p 80 -v
listening on [any] 80 ...
diff -r --unidirectional-new-file -u linux-2.6.23/arch/i386/kernel/syscall_table.S linux-2.6.23-patched/arch/i386/kernel/syscall_table.S
--- linux-2.6.23/arch/i386/kernel/syscall_table.S 2007-10-09 22:31:38.000000000 +0200
+++ linux-2.6.23-patched/arch/i386/kernel/syscall_table.S 2007-12-13 14:29:40.000000000 +0100
@@ -324,3 +324,4 @@
.long sys_timerfd
.long sys_eventfd
.long sys_fallocate
+ .long sys_port_acl_set /* 325 */
diff -r --unidirectional-new-file -u linux-2.6.23/include/asm-i386/unistd.h linux-2.6.23-patched/include/asm-i386/unistd.h
--- linux-2.6.23/include/asm-i386/unistd.h 2007-10-09 22:31:38.000000000 +0200
+++ linux-2.6.23-patched/include/asm-i386/unistd.h 2007-12-13 14:29:40.000000000 +0100
@@ -330,10 +330,11 @@
#define __NR_timerfd 322
#define __NR_eventfd 323
#define __NR_fallocate 324
+#define __NR_port_acl_set 325
#ifdef __KERNEL__
-#define NR_syscalls 325
+#define NR_syscalls 326
#define __ARCH_WANT_IPC_PARSE_VERSION
#define __ARCH_WANT_OLD_READDIR
diff -r --unidirectional-new-file -u linux-2.6.23/include/net/port_acl.h linux-2.6.23-patched/include/net/port_acl.h
--- linux-2.6.23/include/net/port_acl.h 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.23-patched/include/net/port_acl.h 2007-12-13 15:17:40.000000000 +0100
@@ -0,0 +1,15 @@
+#include <linux/types.h>
+
+struct port_acl {
+ uid_t uid;
+ struct port_acl *next;
+};
+
+#ifdef __PORT_ACL__
+ struct port_acl *port_acl_list[1024];
+#else
+ extern struct port_acl *port_acl_list[1024];
+#endif
+
+extern int port_acl(short int);
+extern int port_acl_get_info(char *, char **, off_t, int);
diff -r --unidirectional-new-file -u linux-2.6.23/kernel/sys.c linux-2.6.23-patched/kernel/sys.c
--- linux-2.6.23/kernel/sys.c 2007-10-09 22:31:38.000000000 +0200
+++ linux-2.6.23-patched/kernel/sys.c 2007-12-13 16:01:24.000000000 +0100
@@ -43,6 +43,9 @@
#include <asm/io.h>
#include <asm/unistd.h>
+#define __PORT_ACL__
+#include <net/port_acl.h>
+
#ifndef SET_UNALIGN_CTL
# define SET_UNALIGN_CTL(a,b) (-EINVAL)
#endif
@@ -2356,4 +2359,89 @@
return ret;
}
+
+/*
+ * The following lines were added to implement port_acl secured
+ * mecanism :
+ * port_acl_add - add to a user the authorisation to acces a particular port
+ * port_acl_remove - remove to a user that authorisation
+ * sys_port_acl_set - front end for port_acl_add and port_acl_remove
+ */
+long port_acl_add(short int snum, uid_t uid)
+{
+ struct port_acl *ptr, *new;
+
+ /* we verify if the permition is already set for that user */
+ ptr = port_acl_list[snum];
+
+ while (ptr != NULL) {
+ if (ptr->uid == uid)
+ return -EBUSY;
+ if (ptr->next == NULL)
+ break;
+ ptr = ptr->next;
+ }
+
+ /* ok, we haven't found the user and ptr is a pointer on the
+ last structure */
+ new = kmalloc( sizeof(struct port_acl), GFP_KERNEL);
+ new->next = NULL;
+ new->uid = uid;
+
+ if(ptr == NULL)
+ port_acl_list[snum] = new;
+ else
+ ptr->next = new;
+
+ return 0;
+}
+
+long port_acl_remove(short int snum, uid_t uid)
+{
+ struct port_acl *ptr, *prev = 0;
+
+ /* we verify if the permition is already set for that user */
+ ptr = port_acl_list[snum];
+
+ while (ptr != NULL) {
+ /* we found the user */
+ if (ptr->uid == uid) {
+ if (ptr == port_acl_list[snum]) {
+ port_acl_list[snum] = ptr->next;
+ }
+ else {
+ prev->next = ptr->next;
+ }
+ kfree(ptr);
+ return 0;
+ }
+ prev = ptr;
+ ptr = ptr->next;
+ }
+
+ return -ENODATA;
+}
+
+asmlinkage long sys_port_acl_set(short int snum, uid_t uid, int act)
+{
+ /* the owner of the process must be root */
+ if (current->uid != 0)
+ return -EACCES;
+
+ /* we verify that the port is valid */
+ if (snum<0 || snum>1023)
+ return -EINVAL;
+
+ if (uid<1 || uid>65534)
+ return -EINVAL;
+
+ if (act == 0)
+ return port_acl_remove(snum, uid);
+ else if (act == 1)
+ return port_acl_add(snum, uid);
+ else
+ return -EPERM;
+}
+
+
EXPORT_SYMBOL_GPL(orderly_poweroff);
diff -r --unidirectional-new-file -u linux-2.6.23/net/ipv4/af_inet.c linux-2.6.23-patched/net/ipv4/af_inet.c
--- linux-2.6.23/net/ipv4/af_inet.c 2007-10-09 22:31:38.000000000 +0200
+++ linux-2.6.23-patched/net/ipv4/af_inet.c 2007-12-13 15:58:55.000000000 +0100
@@ -112,6 +112,7 @@
#include <net/ipip.h>
#include <net/inet_common.h>
#include <net/xfrm.h>
+#include <net/port_acl.h>
#ifdef CONFIG_IP_MROUTE
#include <linux/mroute.h>
#endif
@@ -457,7 +458,7 @@
snum = ntohs(addr->sin_port);
err = -EACCES;
- if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE))
+ if (snum && snum < PROT_SOCK && !capable(CAP_NET_BIND_SERVICE) && !port_acl(snum))
goto out;
/* We keep a pair of addresses. rcv_saddr is the one
@@ -1456,6 +1457,8 @@
{
int rc = 0;
+ proc_net_create ("port_acl", 0, port_acl_get_info);
+
if (raw_proc_init())
goto out_raw;
if (tcp4_proc_init())
@@ -1466,6 +1469,7 @@
goto out_fib;
if (ip_misc_proc_init())
goto out_misc;
+
out:
return rc;
out_misc:
@@ -1486,6 +1490,7 @@
{
return 0;
}
+
#endif /* CONFIG_PROC_FS */
MODULE_ALIAS_NETPROTO(PF_INET);
diff -r --unidirectional-new-file -u linux-2.6.23/net/ipv4/Makefile linux-2.6.23-patched/net/ipv4/Makefile
--- linux-2.6.23/net/ipv4/Makefile 2007-10-09 22:31:38.000000000 +0200
+++ linux-2.6.23-patched/net/ipv4/Makefile 2007-12-13 14:29:40.000000000 +0100
@@ -10,7 +10,7 @@
tcp_minisocks.o tcp_cong.o \
datagram.o raw.o udp.o udplite.o \
arp.o icmp.o devinet.o af_inet.o igmp.o \
- sysctl_net_ipv4.o fib_frontend.o fib_semantics.o
+ sysctl_net_ipv4.o fib_frontend.o fib_semantics.o port_acl.o
obj-$(CONFIG_IP_FIB_HASH) += fib_hash.o
obj-$(CONFIG_IP_FIB_TRIE) += fib_trie.o
diff -r --unidirectional-new-file -u linux-2.6.23/net/ipv4/port_acl.c linux-2.6.23-patched/net/ipv4/port_acl.c
--- linux-2.6.23/net/ipv4/port_acl.c 1970-01-01 01:00:00.000000000 +0100
+++ linux-2.6.23-patched/net/ipv4/port_acl.c 2007-12-13 16:01:12.000000000 +0100
@@ -0,0 +1,54 @@
+/*
+ * This is an implementation of acces list applied
+ * to privileged ports.
+ */
+#include <linux/sched.h>
+#include <linux/stddef.h>
+#include <linux/types.h>
+#include <net/port_acl.h>
+
+/*
+ * yields 1 if the owner of the current process is authorized to
+ * bind the port given in argument
+ */
+int port_acl(short int snum)
+{
+ struct port_acl *ptr;
+ ptr = port_acl_list[snum];
+
+ while (ptr != NULL) {
+ if (ptr->uid == current->uid)
+ return 1;
+ ptr = ptr->next;
+ }
+
+ return 0;
+}
+
+
+/*
+ * Report privileged port authorization
+ */
+int port_acl_get_info(char *buffer, char **start, off_t offset, int length)
+{
+ int p;
+ int len = 0;
+ int limit = length - 80;
+ struct port_acl *ptr;
+
+ /* for every port below 1024, we search privileged uid */
+ for (p=0;p<1024;p++) {
+ ptr = port_acl_list[p];
+ if (ptr != NULL) {
+ len += sprintf(buffer+len,"%d:", p);
+ do {
+ len += sprintf(buffer+len," %d", ptr->uid);
+ ptr = ptr->next;
+ } while (ptr != NULL && len < limit);
+ len += sprintf(buffer+len,"\n");
+ }
+ }
+
+ return len;
+}
port_acl_set.c
---
/*
* Add or remove to a user the authorisation to acces
* a particular port via the following system call :
* int sys_port_acl_set(short int snum, uid_t uid, int act)
*/
#include <syscall.h>
#include <linux/unistd.h>
#include <pwd.h>
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
int main(int argc, char **argv)
{
int ret;
int pnum, action;
struct passwd *user;
/* parse args */
if (argc<3) {
fprintf(stderr, "usage : %s <+->service login\n", argv[0]);
exit(1);
}
switch (*argv[1]) {
case '+' :
action = 1 ; break;
case '-' :
action = 0 ; break;
default :
fprintf(stderr,"action '%c' is not valid\n", *argv[1]);
exit(1);
}
pnum = atoi(argv[1]+1);
user = getpwnam(argv[2]);
if (!user) {
fprintf(stderr,"%s is not a valid user\n", argv[2]);
exit(1);
}
/* display a nice message */
if (action == 1) {
printf("add access on port %d to user: %s(%d)\n", pnum, argv[2], user->pw_uid);
}
else {
printf("remove access on port %d to user: %s(%d)\n", pnum, argv[2], user->pw_uid);
}
ret = syscall(__NR_port_acl_set, pnum, user->pw_uid, action);
if (ret!=0) {
perror("");
exit(2);
}
return 0;
}
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
Powered by blists - more mailing lists