Allows run with restricted privileges.
Adds option -u and -g to specify user and group. When different user (than root) is specified, linux capabilities CAP_NET_* are kept.
This commit is contained in:
parent
46bb7e0d17
commit
1bc2695744
6 changed files with 150 additions and 2 deletions
|
@ -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_MULTIPLE_TABLES The kernel supports multiple routing tables
|
||||||
CONFIG_ALL_TABLES_AT_ONCE Kernel scanner wants to process all tables at once
|
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_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_IFACE Use Unix interface scanner
|
||||||
CONFIG_UNIX_SET Use Unix route setting
|
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_MREQN Linux: Use struct mreqn for multicasting
|
||||||
CONFIG_LINUX_MC_MREQ Linux: Use struct mreq
|
CONFIG_LINUX_MC_MREQ Linux: Use struct mreq
|
||||||
CONFIG_LINUX_MC_MREQ_BIND Linux: Use struct mreq and SO_BINDTODEVICE
|
CONFIG_LINUX_MC_MREQ_BIND Linux: Use struct mreq and SO_BINDTODEVICE
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,8 @@
|
||||||
#define CONFIG_LINUX_MC_MREQN
|
#define CONFIG_LINUX_MC_MREQN
|
||||||
#define CONFIG_UNIX_DONTROUTE
|
#define CONFIG_UNIX_DONTROUTE
|
||||||
|
|
||||||
|
#define CONFIG_RESTRICTED_PRIVILEGES
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Link: sysdep/linux/netlink
|
Link: sysdep/linux/netlink
|
||||||
Link: sysdep/linux
|
Link: sysdep/linux
|
||||||
|
|
|
@ -19,6 +19,8 @@
|
||||||
#define CONFIG_MULTIPLE_TABLES
|
#define CONFIG_MULTIPLE_TABLES
|
||||||
#define CONFIG_ALL_TABLES_AT_ONCE
|
#define CONFIG_ALL_TABLES_AT_ONCE
|
||||||
|
|
||||||
|
#define CONFIG_RESTRICTED_PRIVILEGES
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Link: sysdep/linux/netlink
|
Link: sysdep/linux/netlink
|
||||||
Link: sysdep/linux
|
Link: sysdep/linux
|
||||||
|
|
|
@ -3,3 +3,4 @@ krt-scan.c
|
||||||
krt-scan.h
|
krt-scan.h
|
||||||
#endif
|
#endif
|
||||||
sysio.h
|
sysio.h
|
||||||
|
syspriv.h
|
||||||
|
|
62
sysdep/linux/syspriv.h
Normal file
62
sysdep/linux/syspriv.h
Normal file
|
@ -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");
|
||||||
|
}
|
|
@ -8,11 +8,15 @@
|
||||||
|
|
||||||
#undef LOCAL_DEBUG
|
#undef LOCAL_DEBUG
|
||||||
|
|
||||||
|
#define _GNU_SOURCE 1
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <fcntl.h>
|
#include <fcntl.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <grp.h>
|
||||||
|
|
||||||
#include "nest/bird.h"
|
#include "nest/bird.h"
|
||||||
#include "lib/lists.h"
|
#include "lib/lists.h"
|
||||||
|
@ -58,6 +62,29 @@ async_dump(void)
|
||||||
debug("\n");
|
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
|
* Reading the Configuration
|
||||||
*/
|
*/
|
||||||
|
@ -444,14 +471,16 @@ signal_init(void)
|
||||||
* Parsing of command-line arguments
|
* 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;
|
static int parse_and_exit;
|
||||||
char *bird_name;
|
char *bird_name;
|
||||||
|
static char *use_user;
|
||||||
|
static char *use_group;
|
||||||
|
|
||||||
static void
|
static void
|
||||||
usage(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);
|
exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -469,6 +498,44 @@ get_bird_name(char *s, char *def)
|
||||||
return t+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
|
static void
|
||||||
parse_args(int argc, char **argv)
|
parse_args(int argc, char **argv)
|
||||||
{
|
{
|
||||||
|
@ -504,6 +571,12 @@ parse_args(int argc, char **argv)
|
||||||
case 's':
|
case 's':
|
||||||
path_control_socket = optarg;
|
path_control_socket = optarg;
|
||||||
break;
|
break;
|
||||||
|
case 'u':
|
||||||
|
use_user = optarg;
|
||||||
|
break;
|
||||||
|
case 'g':
|
||||||
|
use_group = optarg;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage();
|
usage();
|
||||||
}
|
}
|
||||||
|
@ -528,6 +601,12 @@ main(int argc, char **argv)
|
||||||
log_init_debug("");
|
log_init_debug("");
|
||||||
log_switch(debug_flag, NULL, NULL);
|
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)
|
if (!parse_and_exit)
|
||||||
test_old_bird(path_control_socket);
|
test_old_bird(path_control_socket);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue