diff -ur bfilter-0.10.1/main/daemon/Daemon.cpp bfilter-0.10.1-droppriv/main/daemon/Daemon.cpp --- bfilter-0.10.1/main/daemon/Daemon.cpp 2005-10-10 23:52:20.000000000 +0100 +++ bfilter-0.10.1-droppriv/main/daemon/Daemon.cpp 2005-11-14 20:05:40.000000000 +0000 @@ -52,6 +52,10 @@ #include #include #include +#include +#include +#include +#include namespace po = boost::program_options; using namespace std; @@ -340,6 +344,69 @@ } bool +Daemon::droppriv(std::string const& chrootdir, std::string const& user, std::string const& group) +{ + uid_t uid = 0; + uid_t gid = 0; + + if (!chrootdir.empty() || !user.empty() || !group.empty()) { + struct stat stat_r; + struct passwd *user_r; + struct group *group_r; + + if (getuid()) { + std::cerr << "Cannot lower privileges, not running as root" << std::endl; + return false; + } + if (!chrootdir.empty() && stat(chrootdir.c_str(), &stat_r)) { + if (!S_ISDIR(stat_r.st_mode)) { + std::cerr << "Cannot lower privileges, chroot directory does not exist" << std::endl; + return false; + } + } + if (!user.empty()) { + user_r = getpwnam(user.c_str()); + if (user_r) { + uid = user_r->pw_uid; + } else { + std::cerr << "Cannot lower privileges, unknown user" << std::endl; + return false; + } + } + if (!group.empty()) { + group_r = getgrnam(group.c_str()); + if (group_r) { + gid = group_r->gr_gid; + } else { + std::cerr << "Cannot lower privileges, unknown group" << std::endl; + return false; + } + } + } + + if (!chrootdir.empty()) { + // Using gethostbyname before chrooting means that the chroot + // directory can be empty (no etc/resolv.conf or dynamically + // loaded lib/libnss* libraries). Using localhost here to + // prevent remote name resolution does not work. + gethostbyname("slashdot.org"); + if (chroot(chrootdir.c_str())) { + std::cerr << "Cannot lower privileges, chroot directory no longer exists" << std::endl; + return false; + } + chdir("/"); + } + if (gid) { + setgroups(0, NULL); + setgid(gid); + } + if (uid) { + setuid(uid); + } + return true; +} + +bool Daemon::run(bool nodaemon) { if (!nodaemon) { @@ -447,13 +514,19 @@ { bool nodaemon = false; std::string confdir = string(SYSCONFDIR) + "/bfilter"; - + std::string chrootdir; + std::string user; + std::string group; + try { po::options_description desc("Allowed options"); desc.add_options() ("help,h", "Print help message") ("version,v", "Print version") ("confdir,c", po::value(&confdir), "Set custom config directory") + ("chroot,r", po::value(&chrootdir), "Set chroot directory") + ("user,u", po::value(&user), "Set unprivileged user") + ("group,g", po::value(&group), "Set unprivileged group") ("nodaemon,n", po::bool_switch(&nodaemon), "Disable background daemon mode") ; po::variables_map vm; @@ -476,6 +549,9 @@ if (!daemon.init(confdir)) { exit(EXIT_FAILURE); } + if (!daemon.droppriv(chrootdir, user, group)) { + exit(EXIT_FAILURE); + } if (!daemon.run(nodaemon)) { exit(EXIT_FAILURE); } diff -ur bfilter-0.10.1/main/daemon/Daemon.h bfilter-0.10.1-droppriv/main/daemon/Daemon.h --- bfilter-0.10.1/main/daemon/Daemon.h 2005-01-14 16:54:32.000000000 +0000 +++ bfilter-0.10.1-droppriv/main/daemon/Daemon.h 2005-11-14 18:22:58.000000000 +0000 @@ -33,7 +33,7 @@ { public: bool init(std::string const& confdir); - + bool droppriv(std::string const& chrootdir, std::string const& user, std::string const& group); bool run(bool nodaemon); private: class ConfigErrorHandler;