summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2016-06-05 14:24:51 +0100
committerRussell King <rmk+kernel@armlinux.org.uk>2016-06-05 17:47:57 +0100
commit38b49b8eb23738f78776db1e3263175e760b66c2 (patch)
tree44bc031900fb0ea0d12f6d01f9fe9faa2432c3b2
parentc494df77a36b8055457979446b87fdb1f0c073a2 (diff)
Initial libcap capability support
-rw-r--r--src/Makefile.in2
-rw-r--r--src/ircd.c74
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 \
diff --git a/src/ircd.c b/src/ircd.c
index cc65818..1862d6d 100644
--- a/src/ircd.c
+++ b/src/ircd.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 */