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>2019-07-21 20:59:35 +0100
commit9b983823e867cfc951ccaa45832bddb5e945cc24 (patch)
treedcb138ff7b46e1aad8841359050020308228dca5
parentb837e35335414f4ff0a987311c5a59386aab5c77 (diff)
Initial libcap capability support
-rw-r--r--src/Makefile.in2
-rw-r--r--src/ircd.c76
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 \
diff --git a/src/ircd.c b/src/ircd.c
index bcf6b70..d7bb5e9 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"
@@ -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 */