]> git.ipfire.org Git - thirdparty/bird.git/commitdiff
Allows run with restricted privileges.
authorOndrej Zajicek <santiago@crfreenet.org>
Tue, 10 May 2011 00:42:17 +0000 (02:42 +0200)
committerOndrej Zajicek <santiago@crfreenet.org>
Tue, 10 May 2011 00:42:17 +0000 (02:42 +0200)
Adds option -u and -g to specify user and group.
When different user (than root) is specified,
linux capabilities CAP_NET_* are kept.

sysdep/cf/README
sysdep/cf/linux-22.h
sysdep/cf/linux-v6.h
sysdep/linux/Modules
sysdep/linux/syspriv.h [new file with mode: 0644]
sysdep/unix/main.c

index 15a45a65444a6ad5735044f0ba9ca869d0298b2b..3b5bcd4f005583eacc77c8d38ac97c8aad13029a 100644 (file)
@@ -6,6 +6,7 @@ CONFIG_SELF_CONSCIOUS   We're able to recognize whether route was installed by us
 CONFIG_MULTIPLE_TABLES The kernel supports multiple routing tables
 CONFIG_ALL_TABLES_AT_ONCE      Kernel scanner wants to process all tables at once
 CONFIG_MC_PROPER_SRC   Multicast packets have source address according to socket saddr field
+CONFIG_RESTRICTED_PRIVILEGES   Implements restricted privileges using drop_uid()
 
 CONFIG_UNIX_IFACE      Use Unix interface scanner
 CONFIG_UNIX_SET                Use Unix route setting
@@ -19,3 +20,4 @@ CONFIG_UNNUM_MULTICAST        krt-iface: We support multicasts on unnumbered PtP device
 CONFIG_LINUX_MC_MREQN  Linux: Use struct mreqn for multicasting
 CONFIG_LINUX_MC_MREQ   Linux: Use struct mreq
 CONFIG_LINUX_MC_MREQ_BIND      Linux: Use struct mreq and SO_BINDTODEVICE
+
index 9ccab648f7b4e39729a45d8d5d32c0904c82f985..51b339d1bd28a6b363d7247dc9577be3f72f6b93 100644 (file)
@@ -17,6 +17,8 @@
 #define CONFIG_LINUX_MC_MREQN
 #define CONFIG_UNIX_DONTROUTE
 
+#define CONFIG_RESTRICTED_PRIVILEGES
+
 /*
 Link: sysdep/linux/netlink
 Link: sysdep/linux
index ef52ee460eb758672271a42f244eab39df39760a..467d7728a2006eaf48e23f02f65520385a9a678e 100644 (file)
@@ -19,6 +19,8 @@
 #define CONFIG_MULTIPLE_TABLES
 #define CONFIG_ALL_TABLES_AT_ONCE
 
+#define CONFIG_RESTRICTED_PRIVILEGES
+
 /*
 Link: sysdep/linux/netlink
 Link: sysdep/linux
index 1b867d819fe34ece5a345c236ab29cce2878466b..09f4a47091119818a4348a5d20489f7107f5f09f 100644 (file)
@@ -3,3 +3,4 @@ krt-scan.c
 krt-scan.h
 #endif
 sysio.h
+syspriv.h
diff --git a/sysdep/linux/syspriv.h b/sysdep/linux/syspriv.h
new file mode 100644 (file)
index 0000000..bfe19ac
--- /dev/null
@@ -0,0 +1,62 @@
+
+#include <sys/prctl.h>
+#include <linux/capability.h>
+
+#ifndef _LINUX_CAPABILITY_VERSION_3
+#define _LINUX_CAPABILITY_VERSION_3  0x20080522
+#define _LINUX_CAPABILITY_U32S_3     2
+#endif
+
+/* capset() prototype is missing ... */
+int capset(cap_user_header_t hdrp, const cap_user_data_t datap);
+
+static inline int
+set_capabilities(u32 caps)
+{
+  struct __user_cap_header_struct cap_hdr;
+  struct __user_cap_data_struct cap_dat[_LINUX_CAPABILITY_U32S_3];
+  int err;
+
+  cap_hdr.version = _LINUX_CAPABILITY_VERSION_3;
+  cap_hdr.pid = 0;
+
+  memset(cap_dat, 0, sizeof(cap_dat));
+  cap_dat[0].effective = cap_dat[0].permitted = caps;
+
+  err = capset(&cap_hdr, cap_dat);
+  if (!err)
+    return 0;
+
+  /* Kernel may support do not support our version of capability interface.
+       The last call returned supported version so we just retry it. */
+  if (errno == EINVAL)
+  {
+    err = capset(&cap_hdr, cap_dat);
+    if (!err)
+      return 0;
+  }
+
+  return -1;
+}
+
+static void
+drop_uid(uid_t uid)
+{
+  u32 caps =
+    CAP_TO_MASK(CAP_NET_BIND_SERVICE) |
+    CAP_TO_MASK(CAP_NET_BROADCAST) |
+    CAP_TO_MASK(CAP_NET_ADMIN) |
+    CAP_TO_MASK(CAP_NET_RAW);
+
+  if (seteuid(uid) < 0)
+    die("seteuid: %m");
+
+  if (set_capabilities(caps) < 0)
+    die("capset: %m");
+
+  if (prctl(PR_SET_KEEPCAPS, 1) < 0)
+    die("prctl: %m");
+
+  if (setresuid(uid, uid, uid) < 0)
+    die("setresuid: %m");
+}
index fd921acebf3dbb54d87516abfd90620459f01a15..744062b4e6e8c3ea3ef260a2a0ad8f8f20d56116 100644 (file)
@@ -8,11 +8,15 @@
 
 #undef LOCAL_DEBUG
 
+#define _GNU_SOURCE 1
+
 #include <stdio.h>
 #include <stdlib.h>
 #include <fcntl.h>
 #include <unistd.h>
 #include <signal.h>
+#include <pwd.h>
+#include <grp.h>
 
 #include "nest/bird.h"
 #include "lib/lists.h"
@@ -58,6 +62,29 @@ async_dump(void)
   debug("\n");
 }
 
+/*
+ *     Dropping privileges
+ */
+
+#ifdef CONFIG_RESTRICTED_PRIVILEGES
+#include "lib/syspriv.h"
+#else
+
+static inline void
+drop_uid(uid_t uid)
+{
+  die("Cannot change user on this platform");
+}
+
+#endif
+
+static inline void
+drop_gid(gid_t gid)
+{
+  if (setgid(gid) < 0)
+    die("setgid: %m");
+}
+
 /*
  *     Reading the Configuration
  */
@@ -444,14 +471,16 @@ signal_init(void)
  *     Parsing of command-line arguments
  */
 
-static char *opt_list = "c:dD:ps:";
+static char *opt_list = "c:dD:ps:u:g:";
 static int parse_and_exit;
 char *bird_name;
+static char *use_user;
+static char *use_group;
 
 static void
 usage(void)
 {
-  fprintf(stderr, "Usage: %s [-c <config-file>] [-d] [-D <debug-file>] [-p] [-s <control-socket>]\n", bird_name);
+  fprintf(stderr, "Usage: %s [-c <config-file>] [-d] [-D <debug-file>] [-p] [-s <control-socket>] [-u <user>] [-g <group>]\n", bird_name);
   exit(1);
 }
 
@@ -469,6 +498,44 @@ get_bird_name(char *s, char *def)
   return t+1;
 }
 
+static inline uid_t
+get_uid(const char *s)
+{
+  struct passwd *pw;
+  char *endptr;
+  
+  errno = 0;
+  long int rv = strtol(s, &endptr, 10);
+
+  if (!errno && !*endptr)
+    return rv;
+
+  pw = getpwnam(s);
+  if (!pw)
+    die("Cannot find user '%s'", s);
+
+  return pw->pw_uid;
+}
+
+static inline gid_t
+get_gid(const char *s)
+{
+  struct group *gr;
+  char *endptr;
+  
+  errno = 0;
+  long int rv = strtol(s, &endptr, 10);
+
+  if (!errno && !*endptr)
+    return rv;
+
+  gr = getgrnam(s);
+  if (!gr)
+    die("Cannot find group '%s'", s);
+
+  return gr->gr_gid;
+}
+
 static void
 parse_args(int argc, char **argv)
 {
@@ -504,6 +571,12 @@ parse_args(int argc, char **argv)
       case 's':
        path_control_socket = optarg;
        break;
+      case 'u':
+       use_user = optarg;
+       break;
+      case 'g':
+       use_group = optarg;
+       break;
       default:
        usage();
       }
@@ -528,6 +601,12 @@ main(int argc, char **argv)
     log_init_debug("");
   log_switch(debug_flag, NULL, NULL);
 
+  if (use_group)
+    drop_gid(get_gid(use_group));
+
+  if (use_user)
+    drop_uid(get_uid(use_user));
+
   if (!parse_and_exit)
     test_old_bird(path_control_socket);