Adds option -u and -g to specify user and group.
When different user (than root) is specified,
linux capabilities CAP_NET_* are kept.
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
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
+
#define CONFIG_LINUX_MC_MREQN
#define CONFIG_UNIX_DONTROUTE
+#define CONFIG_RESTRICTED_PRIVILEGES
+
/*
Link: sysdep/linux/netlink
Link: sysdep/linux
#define CONFIG_MULTIPLE_TABLES
#define CONFIG_ALL_TABLES_AT_ONCE
+#define CONFIG_RESTRICTED_PRIVILEGES
+
/*
Link: sysdep/linux/netlink
Link: sysdep/linux
krt-scan.h
#endif
sysio.h
+syspriv.h
--- /dev/null
+
+#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");
+}
#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"
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
*/
* 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);
}
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)
{
case 's':
path_control_socket = optarg;
break;
+ case 'u':
+ use_user = optarg;
+ break;
+ case 'g':
+ use_group = optarg;
+ break;
default:
usage();
}
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);