diff options
author | pjd <pjd@FreeBSD.org> | 2011-01-28 22:33:47 +0000 |
---|---|---|
committer | pjd <pjd@FreeBSD.org> | 2011-01-28 22:33:47 +0000 |
commit | 1d4238ea6d7bb3df80ae2d80f0563eb3b688c32f (patch) | |
tree | 9e1f37d4547c7063d6f249104a2aa450d7ef0cdb | |
parent | b28599779707d219cdb016a8fbde16168a52faed (diff) | |
download | FreeBSD-src-1d4238ea6d7bb3df80ae2d80f0563eb3b688c32f.zip FreeBSD-src-1d4238ea6d7bb3df80ae2d80f0563eb3b688c32f.tar.gz |
Implement function that drops privileges by:
- chrooting to /var/empty (user hast home directory),
- setting groups to 'hast' (user hast primary group),
- setting real group id, effective group id and saved group id to 'hast',
- setting real user id, effective user id and saved user id to 'hast'.
At the end verify that those operations where successfull.
MFC after: 1 week
-rw-r--r-- | sbin/hastd/hast.h | 1 | ||||
-rw-r--r-- | sbin/hastd/subr.c | 72 | ||||
-rw-r--r-- | sbin/hastd/subr.h | 1 |
3 files changed, 74 insertions, 0 deletions
diff --git a/sbin/hastd/hast.h b/sbin/hastd/hast.h index b86ed62..dbbe0da 100644 --- a/sbin/hastd/hast.h +++ b/sbin/hastd/hast.h @@ -81,6 +81,7 @@ #define HIO_FLUSH 4 #define HIO_KEEPALIVE 5 +#define HAST_USER "hast" #define HAST_TIMEOUT 5 #define HAST_CONFIG "/etc/hast.conf" #define HAST_CONTROL "/var/run/hastctl" diff --git a/sbin/hastd/subr.c b/sbin/hastd/subr.c index 16ea93f..ddd4a5b 100644 --- a/sbin/hastd/subr.c +++ b/sbin/hastd/subr.c @@ -38,6 +38,8 @@ __FBSDID("$FreeBSD$"); #include <assert.h> #include <errno.h> #include <fcntl.h> +#include <pwd.h> +#include <unistd.h> #include <pjdlog.h> @@ -116,3 +118,73 @@ role2str(int role) } return ("unknown"); } + +int +drop_privs(void) +{ + struct passwd *pw; + uid_t ruid, euid, suid; + gid_t rgid, egid, sgid; + gid_t gidset[1]; + + /* + * According to getpwnam(3) we have to clear errno before calling the + * function to be able to distinguish between an error and missing + * entry (with is not treated as error by getpwnam(3)). + */ + errno = 0; + pw = getpwnam(HAST_USER); + if (pw == NULL) { + if (errno != 0) { + KEEP_ERRNO(pjdlog_errno(LOG_ERR, + "Unable to find info about '%s' user", HAST_USER)); + return (-1); + } else { + pjdlog_error("'%s' user doesn't exist.", HAST_USER); + errno = ENOENT; + return (-1); + } + } + if (chroot(pw->pw_dir) == -1) { + KEEP_ERRNO(pjdlog_errno(LOG_ERR, + "Unable to change root directory to %s", pw->pw_dir)); + return (-1); + } + PJDLOG_VERIFY(chdir("/") == 0); + gidset[0] = pw->pw_gid; + if (setgroups(1, gidset) == -1) { + KEEP_ERRNO(pjdlog_errno(LOG_ERR, + "Unable to set groups to gid %u", + (unsigned int)pw->pw_gid)); + return (-1); + } + if (setgid(pw->pw_gid) == -1) { + KEEP_ERRNO(pjdlog_errno(LOG_ERR, "Unable to set gid to %u", + (unsigned int)pw->pw_gid)); + return (-1); + } + if (setuid(pw->pw_uid) == -1) { + KEEP_ERRNO(pjdlog_errno(LOG_ERR, "Unable to set uid to %u", + (unsigned int)pw->pw_uid)); + return (-1); + } + + /* + * Better be sure that everything succeeded. + */ + PJDLOG_VERIFY(getresuid(&ruid, &euid, &suid) == 0); + PJDLOG_VERIFY(ruid == pw->pw_uid); + PJDLOG_VERIFY(euid == pw->pw_uid); + PJDLOG_VERIFY(suid == pw->pw_uid); + PJDLOG_VERIFY(getresgid(&rgid, &egid, &sgid) == 0); + PJDLOG_VERIFY(rgid == pw->pw_gid); + PJDLOG_VERIFY(egid == pw->pw_gid); + PJDLOG_VERIFY(sgid == pw->pw_gid); + PJDLOG_VERIFY(getgroups(0, NULL) == 1); + PJDLOG_VERIFY(getgroups(1, gidset) == 1); + PJDLOG_VERIFY(gidset[0] == pw->pw_gid); + + pjdlog_info("Privileges successfully dropped."); + + return (0); +} diff --git a/sbin/hastd/subr.h b/sbin/hastd/subr.h index c486f5c..913d2a4 100644 --- a/sbin/hastd/subr.h +++ b/sbin/hastd/subr.h @@ -47,5 +47,6 @@ int provinfo(struct hast_resource *res, bool dowrite); const char *role2str(int role); +int drop_privs(void); #endif /* !_SUBR_H_ */ |