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> | 2019-07-21 20:59:35 +0100 |
commit | 9b983823e867cfc951ccaa45832bddb5e945cc24 (patch) | |
tree | dcb138ff7b46e1aad8841359050020308228dca5 | |
parent | b837e35335414f4ff0a987311c5a59386aab5c77 (diff) |
Initial libcap capability support
-rw-r--r-- | src/Makefile.in | 2 | ||||
-rw-r--r-- | src/ircd.c | 76 |
2 files changed, 76 insertions, 2 deletions
diff --git a/src/Makefile.in b/src/Makefile.in index d758c1c..c9990c8 100644 --- a/src/Makefile.in +++ b/src/Makefile.in @@ -356,7 +356,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" @@ -61,6 +62,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; @@ -456,14 +464,80 @@ 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"); + return -1; + } +#else fprintf(stderr, "ERROR: This server won't run as root/superuser\n"); return -1; +#endif } /* Setup corefile size immediately after boot -kre */ |