diff options
author | 2015-07-27 08:58:09 +0000 | |
---|---|---|
committer | 2015-07-27 08:58:09 +0000 | |
commit | 3d3cf35c34048a9033acbb73a64e5c0b8e4dfa9a (patch) | |
tree | 4240133ff571da15e077a8dec4942cb40ab464ec | |
parent | Make -q suppress ambiguous option warnings too, from Cam Hutchison. (diff) | |
download | wireguard-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.h | 7 | ||||
-rw-r--r-- | usr.sbin/radiusd/radiusd_bsdauth.c | 293 | ||||
-rw-r--r-- | usr.sbin/radiusd/radiusd_local.h | 4 | ||||
-rw-r--r-- | usr.sbin/radiusd/radiusd_module.c | 45 | ||||
-rw-r--r-- | usr.sbin/radiusd/radiusd_module.h | 1 | ||||
-rw-r--r-- | usr.sbin/radiusd/radiusd_radius.c | 9 |
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); } |