diff options
author | Russell King <rmk+kernel@arm.linux.org.uk> | 2016-06-05 14:24:51 +0100 |
---|---|---|
committer | Russell King <rmk+kernel@armlinux.org.uk> | 2016-06-05 17:47:57 +0100 |
commit | 38b49b8eb23738f78776db1e3263175e760b66c2 (patch) | |
tree | 44bc031900fb0ea0d12f6d01f9fe9faa2432c3b2 | |
parent | c494df77a36b8055457979446b87fdb1f0c073a2 (diff) |
Initial libcap capability support
-rw-r--r-- | src/Makefile.in | 2 | ||||
-rw-r--r-- | src/ircd.c | 74 |
2 files changed, 74 insertions, 2 deletions
diff --git a/src/Makefile.in b/src/Makefile.in index e645add..7e5ef3d 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -355,7 +355,7 @@ AUTOMAKE_OPTIONS = foreign AM_YFLAGS = -d AM_CPPFLAGS = $(LTDLINCL) -I$(top_srcdir)/include ircd_LDFLAGS = -export-dynamic -ircd_LDADD = $(LIBLTDL) +ircd_LDADD = $(LIBLTDL) -lcap ircd_DEPENDENCIES = $(LTDLDEPS) ircd_SOURCES = channel.c \ channel_mode.c \ @@ -23,7 +23,8 @@ * \brief Starts up and runs the ircd. * \version $Id$ */ - +#define USE_LINUX_CAP +#define _GNU_SOURCE #include "stdinc.h" #include "s_user.h" #include "list.h" @@ -63,6 +64,13 @@ #include "conf_db.h" #include "conf_class.h" +#ifdef USE_LINUX_CAP +#include <pwd.h> +#include <grp.h> +#include <sys/prctl.h> +#include <sys/capability.h> +#include <unistd.h> +#endif #ifdef HAVE_LIBGEOIP GeoIP *geoip_ctx; @@ -458,14 +466,78 @@ ssl_init(void) #endif /* HAVE_LIBCRYPTO */ } +#ifdef USE_LINUX_CAP +/* This drops ALL privs except for CAP_NET_BIND_SERVICE */ +static int drop_priv(char *user, char *group) +{ + struct passwd *u; + struct group *g; + cap_t cap; + + if (!user || !group) { + fprintf(stderr, "You must set IRCD_USER and IRCD_GROUP environment variables\n"); + return -1; + } + + if ((u = getpwnam(user)) == NULL) { + fprintf(stderr, "Unknown user: %s\n", user); + return -1; + } + + if ((g = getgrnam(group)) == NULL) { + fprintf(stderr, "Unknown group: %s\n", group); + return -1; + } + + if (prctl(PR_SET_KEEPCAPS, 1)) { + fprintf(stderr, "prctl(PR_SET_KEEPCAPS): %s\n", strerror(errno)); + return -1; + } + + if (setgroups(0, 0)) { + fprintf(stderr, "setgroups(): %s\n", strerror(errno)); + return -1; + } + + if (setresgid(g->gr_gid, g->gr_gid, g->gr_gid)) { + fprintf(stderr, "setresgid(): %s\n", strerror(errno)); + return -1; + } + + if (setresuid(u->pw_uid, u->pw_uid, u->pw_uid)) { + fprintf(stderr, "setresuid(): %s\n", strerror(errno)); + return -1; + } + + cap = cap_from_text("cap_net_bind_service=ep"); + if (!cap) { + fprintf(stderr, "cap_from_text(): %s\n", strerror(errno)); + return -1; + } + + if (cap_set_proc(cap)) { + fprintf(stderr, "cap_set_proc(): %s\n", strerror(errno)); + return -1; + } + cap_free(cap); + + return 0; +} +#endif + int main(int argc, char *argv[]) { /* Check to see if the user is running us as root, which is a nono */ if (geteuid() == 0) { +#ifdef USE_LINUX_CAP + if (drop_priv(getenv("IRCD_USER"), getenv("IRCD_GROUP"))) + fprintf(stderr, "Unable to drop capabilities\n"); +#else fprintf(stderr, "Don't run ircd as root!!!\n"); return -1; +#endif } /* Setup corefile size immediately after boot -kre */ |