summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/bird.sgml32
-rw-r--r--sysdep/linux/syspriv.h5
-rw-r--r--sysdep/unix/main.c47
3 files changed, 69 insertions, 15 deletions
diff --git a/doc/bird.sgml b/doc/bird.sgml
index 31b2c03f..01e70e82 100644
--- a/doc/bird.sgml
+++ b/doc/bird.sgml
@@ -145,10 +145,42 @@ options. The most important ones are:
<tag>-s <m/name of communication socket/</tag>
use given filename for a socket for communications with the client, default is <it/prefix/<file>/var/run/bird.ctl</file>.
+
+ <tag>-u <m/user/</tag>
+ drop privileges and use that user ID, see the next section for details.
+
+ <tag>-g <m/group/</tag>
+ use that group ID, see the next section for details.
</descrip>
<p>BIRD writes messages about its work to log files or syslog (according to config).
+<sect>Privileges
+
+<p>BIRD, as a routing daemon, uses several privileged operations (like
+setting routing table and using raw sockets). Traditionally, BIRD is
+executed and runs with root privileges, which may be prone to security
+problems. The recommended way is to use a privilege restriction
+(options <cf/-u/, <cf/-g/). In that case BIRD is executed with root
+privileges, but it changes its user and group ID to an unprivileged
+ones, while using Linux capabilities to retain just required
+privileges (capabilities CAP_NET_*). Note that the control socket is
+created before the privileges are dropped, but the config file is read
+after that. The privilege restriction is not implemented in BSD port
+of BIRD.
+
+<p>A nonprivileged user (as an argument to <cf/-u/ options) may be the
+user <cf/nobody/, but it is suggested to use a new dedicated user
+account (like <cf/bird/). The similar considerations apply for
+the group option, but there is one more condition -- the users
+in the same group can use <file/birdc/ to control BIRD.
+
+<p>Finally, there is a possibility to use external tools to run BIRD in
+an environment with restricted privileges. This may need some
+configuration, but it is generally easy -- BIRD needs just the
+standard library, privileges to read the config file and create the
+control socket and the CAP_NET_* capabilities.
+
<chapt>About routing tables
<p>BIRD has one or more routing tables which may or may not be
diff --git a/sysdep/linux/syspriv.h b/sysdep/linux/syspriv.h
index bfe19ac3..b2cdde85 100644
--- a/sysdep/linux/syspriv.h
+++ b/sysdep/linux/syspriv.h
@@ -48,15 +48,20 @@ drop_uid(uid_t uid)
CAP_TO_MASK(CAP_NET_ADMIN) |
CAP_TO_MASK(CAP_NET_RAW);
+ /* change effective user ID to be able to switch to that
+ user ID completely after dropping CAP_SETUID */
if (seteuid(uid) < 0)
die("seteuid: %m");
+ /* restrict the capabilities */
if (set_capabilities(caps) < 0)
die("capset: %m");
+ /* keep the capabilities after dropping root ID */
if (prctl(PR_SET_KEEPCAPS, 1) < 0)
die("prctl: %m");
+ /* completely switch to the unprivileged user ID */
if (setresuid(uid, uid, uid) < 0)
die("setresuid: %m");
}
diff --git a/sysdep/unix/main.c b/sysdep/unix/main.c
index 744062b4..610d207d 100644
--- a/sysdep/unix/main.c
+++ b/sysdep/unix/main.c
@@ -383,7 +383,7 @@ cli_connect(sock *s, int size UNUSED)
}
static void
-cli_init_unix(void)
+cli_init_unix(uid_t use_uid, gid_t use_gid)
{
sock *s;
@@ -393,6 +393,13 @@ cli_init_unix(void)
s->rx_hook = cli_connect;
s->rbsize = 1024;
sk_open_unix(s, path_control_socket);
+
+ if (use_uid || use_gid)
+ if (chown(path_control_socket, use_uid, use_gid) < 0)
+ die("chown: %m");
+
+ if (chmod(path_control_socket, 0660) < 0)
+ die("chmod: %m");
}
/*
@@ -503,9 +510,13 @@ get_uid(const char *s)
{
struct passwd *pw;
char *endptr;
-
+ long int rv;
+
+ if (!s)
+ return 0;
+
errno = 0;
- long int rv = strtol(s, &endptr, 10);
+ rv = strtol(s, &endptr, 10);
if (!errno && !*endptr)
return rv;
@@ -522,9 +533,13 @@ get_gid(const char *s)
{
struct group *gr;
char *endptr;
+ long int rv;
+
+ if (!s)
+ return 0;
errno = 0;
- long int rv = strtol(s, &endptr, 10);
+ rv = strtol(s, &endptr, 10);
if (!errno && !*endptr)
return rv;
@@ -601,24 +616,26 @@ 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);
-
- DBG("Initializing.\n");
resource_init();
olock_init();
io_init();
rt_init();
if_init();
+ uid_t use_uid = get_uid(use_user);
+ gid_t use_gid = get_gid(use_group);
+
if (!parse_and_exit)
- cli_init_unix();
+ {
+ test_old_bird(path_control_socket);
+ cli_init_unix(use_uid, use_gid);
+ }
+
+ if (use_gid)
+ drop_gid(use_gid);
+
+ if (use_uid)
+ drop_uid(use_uid);
protos_build();
proto_build(&proto_unix_kernel);