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 [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to