summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryasuoka <yasuoka@openbsd.org>2015-07-27 08:58:09 +0000
committeryasuoka <yasuoka@openbsd.org>2015-07-27 08:58:09 +0000
commit3d3cf35c34048a9033acbb73a64e5c0b8e4dfa9a (patch)
tree4240133ff571da15e077a8dec4942cb40ab464ec
parentMake -q suppress ambiguous option warnings too, from Cam Hutchison. (diff)
downloadwireguard-openbsd-3d3cf35c34048a9033acbb73a64e5c0b8e4dfa9a.tar.xz
wireguard-openbsd-3d3cf35c34048a9033acbb73a64e5c0b8e4dfa9a.zip
Drop the privilege from modules. "radiusd_radius" could simply run
without root. "radiusd_bsdauth" uses some functions which needs root. So separate its process into a privileged process and a non-privileged process.
-rw-r--r--usr.sbin/radiusd/radiusd.h7
-rw-r--r--usr.sbin/radiusd/radiusd_bsdauth.c293
-rw-r--r--usr.sbin/radiusd/radiusd_local.h4
-rw-r--r--usr.sbin/radiusd/radiusd_module.c45
-rw-r--r--usr.sbin/radiusd/radiusd_module.h1
-rw-r--r--usr.sbin/radiusd/radiusd_radius.c9
6 files changed, 293 insertions, 66 deletions
diff --git a/usr.sbin/radiusd/radiusd.h b/usr.sbin/radiusd/radiusd.h
index e31b8c47097..267d51ed81f 100644
--- a/usr.sbin/radiusd/radiusd.h
+++ b/usr.sbin/radiusd/radiusd.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: radiusd.h,v 1.1 2015/07/21 04:06:04 yasuoka Exp $ */
+/* $OpenBSD: radiusd.h,v 1.2 2015/07/27 08:58:09 yasuoka Exp $ */
#ifndef RADIUSD_H
#define RADIUSD_H 1
@@ -19,8 +19,9 @@
*/
#include <stdbool.h>
-#define RADIUSD_MODULE_NAME_LEN 32
-#define RADIUSD_SECRET_MAX 128
+#define RADIUSD_MODULE_NAME_LEN 32
+#define RADIUSD_SECRET_MAX 128
+#define RADIUSD_USER "_radiusd"
enum imsg_type {
IMSG_NONE = 0,
diff --git a/usr.sbin/radiusd/radiusd_bsdauth.c b/usr.sbin/radiusd/radiusd_bsdauth.c
index fccdbaf62a6..9800c50e53a 100644
--- a/usr.sbin/radiusd/radiusd_bsdauth.c
+++ b/usr.sbin/radiusd/radiusd_bsdauth.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: radiusd_bsdauth.c,v 1.1 2015/07/21 04:06:04 yasuoka Exp $ */
+/* $OpenBSD: radiusd_bsdauth.c,v 1.2 2015/07/27 08:58:09 yasuoka Exp $ */
/*
* Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
@@ -18,13 +18,18 @@
#include <sys/types.h>
#include <sys/queue.h>
+#include <sys/socket.h>
+#include <sys/uio.h>
+#include <sys/wait.h>
#include <bsd_auth.h>
#include <err.h>
#include <grp.h>
+#include <imsg.h>
#include <login_cap.h>
#include <pwd.h>
#include <stdbool.h>
+#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <syslog.h>
@@ -35,12 +40,33 @@
struct module_bsdauth {
struct module_base *base;
+ struct imsgbuf ibuf;
char **okgroups;
};
-static void module_bsdauth_config_set(void *, const char *, int,
- char * const *);
-static void module_bsdauth_userpass(void *, u_int, const char *, const char *);
+/* IPC between priv and main */
+enum {
+ IMSG_BSDAUTH_OK = 1000,
+ IMSG_BSDAUTH_NG,
+ IMSG_BSDAUTH_USERCHECK,
+ IMSG_BSDAUTH_GROUPCHECK
+};
+struct auth_usercheck_args {
+ size_t userlen;
+ size_t passlen;
+};
+struct auth_groupcheck_args {
+ size_t userlen;
+ size_t grouplen;
+};
+
+static void module_bsdauth_main(int, int);
+static void module_bsdauth_config_set(void *, const char *, int,
+ char * const *);
+static void module_bsdauth_userpass(void *, u_int, const char *,
+ const char *);
+__dead static void
+ fatal(const char *);
static struct module_handlers module_bsdauth_handlers = {
.userpass = module_bsdauth_userpass,
@@ -50,23 +76,173 @@ static struct module_handlers module_bsdauth_handlers = {
int
main(int argc, char *argv[])
{
- struct module_bsdauth module_bsdauth;
+ int pipe_chld, pairsock[2], status;
+ struct imsgbuf ibuf;
+ struct imsg imsg;
+ ssize_t n;
+ size_t datalen;
- memset(&module_bsdauth, 0, sizeof(module_bsdauth));
+ if (socketpair(AF_UNIX, SOCK_STREAM, PF_UNSPEC, pairsock) == -1)
+ err(EXIT_FAILURE, "socketpair");
+
+ pipe_chld = pairsock[1];
+ module_bsdauth_main(pairsock[0], pairsock[1]);
+ /*
+ * Priviledged process
+ */
openlog(NULL, LOG_PID, LOG_DAEMON);
+ setproctitle("[priv]");
+ imsg_init(&ibuf, pipe_chld);
+ for (;;) {
+ if ((n = imsg_read(&ibuf)) <= 0)
+ break;
+ for (;;) {
+ if ((n = imsg_get(&ibuf, &imsg)) == -1)
+ break;
+ if (n == 0)
+ break;
+ datalen = imsg.hdr.len - IMSG_HEADER_SIZE;
+ switch (imsg.hdr.type) {
+ case IMSG_BSDAUTH_USERCHECK:
+ {
+ char *user, *pass;
+ bool authok = false;
+ struct auth_usercheck_args
+ *args;
+
+ if (datalen < sizeof(
+ struct auth_usercheck_args)) {
+ syslog(LOG_ERR, "Short message");
+ break;
+ }
+ args = (struct auth_usercheck_args *)imsg.data;
+
+ if (datalen < sizeof(struct auth_usercheck_args)
+ + args->userlen + args->passlen) {
+ syslog(LOG_ERR, "Short message");
+ break;
+ }
+ user = (char *)(args + 1);
+ user[args->userlen - 1] = '\0';
+ pass = user + args->userlen;
+ pass[args->passlen - 1] = '\0';
+
+ if (auth_userokay(user, NULL, NULL, pass))
+ authok = true;
+ explicit_bzero(pass, args->passlen);
+
+ imsg_compose(&ibuf, (authok)
+ ? IMSG_BSDAUTH_OK : IMSG_BSDAUTH_NG,
+ 0, 0, -1, NULL, 0);
+ break;
+ }
+ case IMSG_BSDAUTH_GROUPCHECK:
+ {
+ int i;
+ char *user, *group;
+ struct passwd *pw;
+ struct group gr0, *gr;
+ char g_buf[4096];
+ bool group_ok = false;
+ struct auth_groupcheck_args
+ *args;
+
+ if (datalen < sizeof(
+ struct auth_groupcheck_args)) {
+ syslog(LOG_ERR, "Short message");
+ break;
+ }
+ args = (struct auth_groupcheck_args *)imsg.data;
+ if (datalen < sizeof(
+ struct auth_groupcheck_args) +
+ args->userlen + args->grouplen) {
+ syslog(LOG_ERR, "Short message");
+ break;
+ }
+ user = (char *)(args + 1);
+ user[args->userlen - 1] = '\0';
+ group = user + args->userlen;
+ group[args->grouplen - 1] = '\0';
+
+ pw = getpwnam(user);
+ if (getgrnam_r(group, &gr0, g_buf,
+ sizeof(g_buf), &gr) == -1)
+ goto group_done;
+
+ if (gr->gr_gid == pw->pw_gid) {
+ group_ok = true;
+ goto group_done;
+ }
+ for (i = 0; gr->gr_mem[i] != NULL; i++) {
+ if (strcmp(gr->gr_mem[i], pw->pw_name)
+ == 0) {
+ group_ok = true;
+ goto group_done;
+ }
+ }
+group_done:
+ endgrent();
+
+ imsg_compose(&ibuf, (group_ok)
+ ? IMSG_BSDAUTH_OK : IMSG_BSDAUTH_NG,
+ 0, 0, -1, NULL, 0);
+ break;
+ }
+ imsg_free(&imsg);
+ }
+ imsg_flush(&ibuf);
+ }
+ imsg_flush(&ibuf);
+ }
+ imsg_clear(&ibuf);
+ wait(&status);
+
+ exit(WEXITSTATUS(status));
+}
+static void
+module_bsdauth_main(int pipe_prnt, int pipe_chld)
+{
+ int i;
+ pid_t pid;
+ struct module_bsdauth module_bsdauth;
+
+ pid = fork();
+ if (pid == -1)
+ err(EXIT_FAILURE, "fork");
+
+ if (pid > 0) {
+ close(pipe_prnt);
+ return;
+ }
+ close(pipe_chld);
+
+ /* main process */
+ setproctitle("[main]");
+ openlog(NULL, LOG_PID, LOG_DAEMON);
+ memset(&module_bsdauth, 0, sizeof(module_bsdauth));
if ((module_bsdauth.base = module_create(STDIN_FILENO, &module_bsdauth,
&module_bsdauth_handlers)) == NULL)
err(1, "Could not create a module instance");
+ module_drop_privilege(module_bsdauth.base);
+
module_load(module_bsdauth.base);
+ imsg_init(&module_bsdauth.ibuf, pipe_prnt);
while (module_run(module_bsdauth.base) == 0)
;
module_destroy(module_bsdauth.base);
+ imsg_clear(&module_bsdauth.ibuf);
- exit(EXIT_SUCCESS);
+ if (module_bsdauth.okgroups) {
+ for (i = 0; module_bsdauth.okgroups[i] != NULL; i++)
+ free(module_bsdauth.okgroups[i]);
+ }
+ free(module_bsdauth.okgroups);
+
+ _exit(EXIT_SUCCESS);
}
static void
@@ -89,23 +265,14 @@ module_bsdauth_config_set(void *ctx, const char *name, int argc,
goto on_error;
}
for (i = 0; i < argc; i++) {
- if (getgrnam(argv[i]) == NULL) {
- module_send_message(_this->base, IMSG_NG,
- "group `%s' is not found", argv[i]);
- endgrent();
+ if ((groups[i] = strdup(argv[i])) == NULL) {
+ module_send_message(_this->base,
+ IMSG_NG, "Out of memory");
goto on_error;
- } else {
- if ((groups[i] = strdup(argv[i])) == NULL) {
- endgrent();
- module_send_message(_this->base,
- IMSG_NG, "Out of memory");
- goto on_error;
- }
}
}
groups[i] = NULL;
_this->okgroups = groups;
- endgrent();
module_send_message(_this->base, IMSG_OK, NULL);
} else
module_send_message(_this->base, IMSG_NG,
@@ -126,55 +293,81 @@ module_bsdauth_userpass(void *ctx, u_int q_id, const char *user,
const char *pass)
{
struct module_bsdauth *_this = ctx;
- u_int i, j;
- auth_session_t *auth = NULL;
- struct passwd *pw;
- struct group gr0, *gr;
- char g_buf[4096];
+ struct auth_usercheck_args
+ usercheck;
+ struct auth_groupcheck_args
+ groupcheck;
+ struct iovec iov[4];
+ const char *group;
+ u_int i;
const char *reason;
+ struct imsg imsg;
+ ssize_t n;
+ memset(&imsg, 0, sizeof(imsg));
if (pass == NULL)
pass = "";
- if ((auth = auth_usercheck((char *)user, NULL, NULL, (char *)pass))
- == NULL || (auth_getstate(auth) & AUTH_OKAY) == 0) {
+ usercheck.userlen = strlen(user) + 1;
+ usercheck.passlen = strlen(pass) + 1;
+ iov[0].iov_base = &usercheck;
+ iov[0].iov_len = sizeof(usercheck);
+ iov[1].iov_base = (char *)user;
+ iov[1].iov_len = usercheck.userlen;
+ iov[2].iov_base = (char *)pass;
+ iov[2].iov_len = usercheck.passlen;
+
+ imsg_composev(&_this->ibuf, IMSG_BSDAUTH_USERCHECK, 0, 0, -1, iov, 3);
+ imsg_flush(&_this->ibuf);
+ if ((n = imsg_read(&_this->ibuf)) == -1 || n == 0)
+ fatal("imsg_read() failed in module_bsdauth_userpass()");
+ if ((n = imsg_get(&_this->ibuf, &imsg)) <= 0)
+ fatal("imsg_get() failed in module_bsdauth_userpass()");
+
+ if (imsg.hdr.type != IMSG_BSDAUTH_OK) {
reason = "Authentication failed";
goto auth_ng;
}
if (_this->okgroups != NULL) {
reason = "Group restriction is not allowed";
- auth_setpwd(auth, NULL);
- if ((pw = auth_getpwd(auth)) == NULL) {
- syslog(LOG_WARNING, "auth_getpwd() for user %s "
- "failed: %m", user);
- goto auth_ng;
- }
for (i = 0; _this->okgroups[i] != NULL; i++) {
- if (getgrnam_r(_this->okgroups[i], &gr0, g_buf,
- sizeof(g_buf), &gr) == -1) {
- syslog(LOG_DEBUG, "group %s is not found",
- _this->okgroups[i]);
- continue;
- }
- if (gr->gr_gid == pw->pw_gid)
+ group = _this->okgroups[i];
+
+ groupcheck.userlen = strlen(user) + 1;
+ groupcheck.grouplen = strlen(group) + 1;
+ iov[0].iov_base = &groupcheck;
+ iov[0].iov_len = sizeof(groupcheck);
+ iov[1].iov_base = (char *)user;
+ iov[1].iov_len = groupcheck.userlen;
+ iov[2].iov_base = (char *)group;
+ iov[2].iov_len = groupcheck.grouplen;
+ imsg_composev(&_this->ibuf, IMSG_BSDAUTH_GROUPCHECK,
+ 0, 0, -1, iov, 3);
+ imsg_flush(&_this->ibuf);
+ if ((n = imsg_read(&_this->ibuf)) == -1 || n == 0)
+ fatal("imsg_read() failed in "
+ "module_bsdauth_userpass()");
+ if ((n = imsg_get(&_this->ibuf, &imsg)) <= 0)
+ fatal("imsg_get() failed in "
+ "module_bsdauth_userpass()");
+ if (imsg.hdr.type == IMSG_BSDAUTH_OK)
goto group_ok;
- for (j = 0; gr->gr_mem[j] != NULL; j++) {
- if (strcmp(gr->gr_mem[j], pw->pw_name) == 0)
- goto group_ok;
- }
}
- endgrent();
goto auth_ng;
-group_ok:
- endgrent();
}
+group_ok:
module_userpass_ok(_this->base, q_id, "Authentication succeeded");
- if (auth != NULL)
- auth_close(auth);
+ imsg_free(&imsg);
return;
auth_ng:
module_userpass_fail(_this->base, q_id, reason);
- if (auth != NULL)
- auth_close(auth);
+ imsg_free(&imsg);
return;
}
+
+static void
+fatal(const char *msg)
+{
+ syslog(LOG_ERR, "%s: %m", msg);
+ abort();
+}
diff --git a/usr.sbin/radiusd/radiusd_local.h b/usr.sbin/radiusd/radiusd_local.h
index 26b3754b3f9..0195a6413d9 100644
--- a/usr.sbin/radiusd/radiusd_local.h
+++ b/usr.sbin/radiusd/radiusd_local.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: radiusd_local.h,v 1.1 2015/07/21 04:06:04 yasuoka Exp $ */
+/* $OpenBSD: radiusd_local.h,v 1.2 2015/07/27 08:58:09 yasuoka Exp $ */
/*
* Copyright (c) 2013 Internet Initiative Japan Inc.
@@ -128,8 +128,6 @@ struct radius_query {
#define nitems(_x) (sizeof((_x)) / sizeof((_x)[0]))
#endif
-#define RADIUSD_USER "_radiusd"
-
#ifdef RADIUSD_DEBUG
#define RADIUSD_DBG(x) log_debug x
#else
diff --git a/usr.sbin/radiusd/radiusd_module.c b/usr.sbin/radiusd/radiusd_module.c
index c99df5c7228..3e932577ff4 100644
--- a/usr.sbin/radiusd/radiusd_module.c
+++ b/usr.sbin/radiusd/radiusd_module.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: radiusd_module.c,v 1.1 2015/07/21 04:06:04 yasuoka Exp $ */
+/* $OpenBSD: radiusd_module.c,v 1.2 2015/07/27 08:58:09 yasuoka Exp $ */
/*
* Copyright (c) 2015 YASUOKA Masahiko <yasuoka@yasuoka.net>
@@ -33,6 +33,7 @@
#include <string.h>
#include <syslog.h>
#include <unistd.h>
+#include <pwd.h>
#include "radiusd.h"
#include "radiusd_module.h"
@@ -50,10 +51,11 @@ static void (*module_access_request) (void *, u_int, const u_char *,
struct module_base {
void *ctx;
struct imsgbuf ibuf;
+ bool priv_dropped;
/* Buffer for receiving the RADIUS packet */
u_char *radpkt;
- int radpktsiz;
+ int radpktsiz;
int radpktoff;
#ifdef USE_LIBEVENT
@@ -76,7 +78,7 @@ static void module_reset_event(struct module_base *);
struct module_base *
module_create(int sock, void *ctx, struct module_handlers *handler)
{
- struct module_base *base;
+ struct module_base *base;
if ((base = calloc(1, sizeof(struct module_base))) == NULL)
return (NULL);
@@ -140,6 +142,28 @@ module_load(struct module_base *base)
imsg_flush(&base->ibuf);
}
+void
+module_drop_privilege(struct module_base *base)
+{
+ struct passwd *pw;
+
+ /* Drop the privilege */
+ if ((pw = getpwnam(RADIUSD_USER)) == NULL)
+ goto on_fail;
+ if (chroot(pw->pw_dir) == -1)
+ goto on_fail;
+ if (chdir("/") == -1)
+ goto on_fail;
+ if (setgroups(1, &pw->pw_gid) ||
+ setresgid(pw->pw_gid, pw->pw_gid, pw->pw_gid) ||
+ setresuid(pw->pw_uid, pw->pw_uid, pw->pw_uid))
+ goto on_fail;
+ base->priv_dropped = true;
+
+on_fail:
+ return;
+}
+
int
module_notify_secret(struct module_base *base, const char *secret)
{
@@ -336,10 +360,21 @@ module_imsg_handler(struct module_base *base, struct imsg *imsg)
break;
}
case IMSG_RADIUSD_MODULE_START:
- if (module_start_module != NULL)
+ if (module_start_module != NULL) {
module_start_module(base->ctx);
- else
+ if (!base->priv_dropped) {
+ syslog(LOG_ERR, "Module tried to start with "
+ "root priviledge");
+ abort();
+ }
+ } else {
+ if (!base->priv_dropped) {
+ syslog(LOG_ERR, "Module tried to start with "
+ "root priviledge");
+ abort();
+ }
module_send_message(base, IMSG_OK, NULL);
+ }
break;
case IMSG_RADIUSD_MODULE_STOP:
if (module_stop_module != NULL)
diff --git a/usr.sbin/radiusd/radiusd_module.h b/usr.sbin/radiusd/radiusd_module.h
index 99158611c90..daa3728ee4a 100644
--- a/usr.sbin/radiusd/radiusd_module.h
+++ b/usr.sbin/radiusd/radiusd_module.h
@@ -55,6 +55,7 @@ void module_start(struct module_base *);
int module_run(struct module_base *);
void module_destroy(struct module_base *);
void module_load(struct module_base *);
+void module_drop_privilege(struct module_base *);
int module_notify_secret(struct module_base *,
const char *);
int module_send_message(struct module_base *, uint32_t,
diff --git a/usr.sbin/radiusd/radiusd_radius.c b/usr.sbin/radiusd/radiusd_radius.c
index d3a224bc56f..1711fa87f52 100644
--- a/usr.sbin/radiusd/radiusd_radius.c
+++ b/usr.sbin/radiusd/radiusd_radius.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: radiusd_radius.c,v 1.1 2015/07/21 04:06:04 yasuoka Exp $ */
+/* $OpenBSD: radiusd_radius.c,v 1.2 2015/07/27 08:58:09 yasuoka Exp $ */
/*
* Copyright (c) 2013 Internet Initiative Japan Inc.
@@ -120,12 +120,11 @@ main(int argc, char *argv[])
module_radius_init(&module_radius);
openlog(NULL, LOG_PID, LOG_DAEMON);
- // XXX drop privilledge
- // XXX change root
-
if ((module_radius.base = module_create(
STDIN_FILENO, &module_radius, &module_radius_handlers)) == NULL)
err(1, "Could not create a module instance");
+ module_drop_privilege(module_radius.base);
+ setproctitle("[main]");
module_load(module_radius.base);
log_init(1);
@@ -523,7 +522,7 @@ module_radius_req_reset_event(struct module_radius_req *req)
"Cannot proccess the request for q=%u: "
"evtimer_add() failed: %m", req->q_id);
module_radius_req_on_failure(req);
- return(-1);
+ return (-1);
}
return (0);
}