From 90246b4a7e51d5baeeb5fbbc8ffb4f5e5b3af9af Mon Sep 17 00:00:00 2001 From: Thomas Jarosch Date: Mon, 7 Apr 2008 16:49:34 +0000 Subject: [PATCH] libi2ncommon: (tomj) implemented drop_root_priviledges using new User/Group classes --- src/Makefile.am | 4 +- src/daemonfunc.cpp | 152 ++++++++++++++++++++++++++---------------------- src/daemonfunc.hpp | 27 +++++++++ src/daemonfunc.hxx | 27 --------- src/filefunc.hxx | 2 +- src/userfunc.cpp | 2 +- src/userfunc.hpp | 87 +++++++++++++++++++++++++++ src/userfunc.hxx | 87 --------------------------- test/test_filefunc.cpp | 2 +- test/test_pidfile.cpp | 22 ++++--- 10 files changed, 214 insertions(+), 198 deletions(-) create mode 100644 src/daemonfunc.hpp delete mode 100644 src/daemonfunc.hxx create mode 100644 src/userfunc.hpp delete mode 100644 src/userfunc.hxx diff --git a/src/Makefile.am b/src/Makefile.am index 6c8882a..ced5609 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,9 +4,9 @@ INCLUDES = -I$(top_srcdir)/src @LIBGETTEXT_CFLAGS@ @LIBICONV_CFLAGS@ $(all_inclu # the library search path. lib_LTLIBRARIES = libi2ncommon.la -include_HEADERS = containerfunc.hpp daemonfunc.hxx filefunc.hxx \ +include_HEADERS = containerfunc.hpp daemonfunc.hpp filefunc.hxx \ insocketstream.hxx ip_type.hxx ipfunc.hxx logread.hxx oftmpstream.hxx pidfile.hpp \ - pipestream.hxx stringfunc.hxx timefunc.hxx userfunc.hxx + pipestream.hxx stringfunc.hxx timefunc.hxx userfunc.hpp libi2ncommon_la_SOURCES = containerfunc.cpp daemonfunc.cpp filefunc.cpp \ ipfunc.cpp logread.cpp oftmpstream.cpp pidfile.cpp stringfunc.cpp timefunc.cpp \ userfunc.cpp diff --git a/src/daemonfunc.cpp b/src/daemonfunc.cpp index 979920e..680ef96 100644 --- a/src/daemonfunc.cpp +++ b/src/daemonfunc.cpp @@ -27,41 +27,55 @@ using namespace std; */ void daemonize() { - int pid=fork(); - - if (pid < 0) - { - throw runtime_error("fork() failed"); - } - if (pid > 0) - { - // parent process - exit (0); - } - // pid==0 -> child process: continue + int pid=fork(); + + if (pid < 0) + { + throw runtime_error("fork() failed"); + } + if (pid > 0) + { + // parent process + exit (0); + } + // pid==0 -> child process: continue } /** * Drop root privileges * @param username User to become. Don't change user if empty * @param group Group to become. Don't change group if empty + * @param get_group_from_user Get group GID from user information if group is empty. + * @return true if all is fine, false otherwise */ -void drop_root_privileges(const std::string &username, - const std::string &group) +bool drop_root_privileges(const std::string &username, + const std::string &group, bool get_group_from_user) { -/* - if (!group.empty()) { - if (setgid(daemon::lookup_gid(group))) { - throw runtime_error("Can't change to group " + group); - } - } - - if (!username.empty()) { - if (setuid(daemon::lookup_uid(username))) { - throw runtime_error("Can't change to user " + username); - } - } -*/ + if (!group.empty()) + { + Group my_group(group); + if (!my_group.is_valid()) + return false; + + if (setgid((my_group.Gid))) + return false; + } + + if (!username.empty()) + { + User my_user(username); + if (!my_user.is_valid()) + return false; + + if (get_group_from_user && group.empty()) + { + if (setgid((my_user.Gid))) + return false; + } + + if (setuid(my_user.Uid)) + return false; + } } /** @@ -79,48 +93,48 @@ void drop_root_privileges(const std::string &username, */ bool pid_of(const std::string& name, std::vector< pid_t >& result) { - std::vector< std::string > entries; - std::vector< pid_t > fuzz1_result; - std::vector< pid_t > fuzz2_result; - result.clear(); - if (!get_dir("/proc", entries)) return false; - for(std::vector< std::string >::const_iterator it= entries.begin(); - it != entries.end(); - ++it) - { - pid_t pid; - if (! string_to(*it, pid)) continue; - std::string base_path= std::string("/proc/") + *it; - std::string exe_path= base_path + "/exe"; - I2n::Stat stat(exe_path, false); - if (not stat or not stat.is_link()) continue; - std::string real_exe= read_link(exe_path); - if (real_exe == name) - { - result.push_back( pid ); - continue; - } - - std::string proc_stat= read_file( base_path + "/stat"); - if (proc_stat.empty()) continue; // process vanished - - //TODO some more fuzz tests here?! (cmdline, stat(us)) - - if (basename(real_exe) == name) - { - fuzz2_result.push_back(pid); - continue; - } - } - if (result.empty()) - { - result.swap(fuzz1_result); - } - if (result.empty()) - { - result.swap(fuzz2_result); - } - return true; + std::vector< std::string > entries; + std::vector< pid_t > fuzz1_result; + std::vector< pid_t > fuzz2_result; + result.clear(); + if (!get_dir("/proc", entries)) return false; + for (std::vector< std::string >::const_iterator it= entries.begin(); + it != entries.end(); + ++it) + { + pid_t pid; + if (! string_to(*it, pid)) continue; + std::string base_path= std::string("/proc/") + *it; + std::string exe_path= base_path + "/exe"; + I2n::Stat stat(exe_path, false); + if (not stat or not stat.is_link()) continue; + std::string real_exe= read_link(exe_path); + if (real_exe == name) + { + result.push_back( pid ); + continue; + } + + std::string proc_stat= read_file( base_path + "/stat"); + if (proc_stat.empty()) continue; // process vanished + + //TODO some more fuzz tests here?! (cmdline, stat(us)) + + if (basename(real_exe) == name) + { + fuzz2_result.push_back(pid); + continue; + } + } + if (result.empty()) + { + result.swap(fuzz1_result); + } + if (result.empty()) + { + result.swap(fuzz2_result); + } + return true; } // eo pidOf(const std::string&,std::vector< pid_t >&) } diff --git a/src/daemonfunc.hpp b/src/daemonfunc.hpp new file mode 100644 index 0000000..e8698b7 --- /dev/null +++ b/src/daemonfunc.hpp @@ -0,0 +1,27 @@ +/*************************************************************************** + * Copyright (C) 2008 by Intra2net AG - Thomas Jarosch * + * thomas.jarosch@intra2net.com * + * http://www.intra2net.com * + ***************************************************************************/ +#ifndef DAEMONFUNC_H +#define DAEMONFUNC_H + +#include +#include +#include + +/// Collection of functions for daemons +namespace I2n +{ +namespace daemon +{ +void daemonize(); + +bool drop_root_privileges(const std::string &username, + const std::string &group, bool get_group_from_user=false); + +bool pid_of(const std::string& name, std::vector< pid_t >& result); +} +} + +#endif diff --git a/src/daemonfunc.hxx b/src/daemonfunc.hxx deleted file mode 100644 index 14deeb1..0000000 --- a/src/daemonfunc.hxx +++ /dev/null @@ -1,27 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Intra2net AG - Thomas Jarosch * - * thomas.jarosch@intra2net.com * - * http://www.intra2net.com * - ***************************************************************************/ -#ifndef DAEMONFUNC_H -#define DAEMONFUNC_H - -#include -#include -#include - -/// Collection of functions for daemons -namespace I2n -{ -namespace daemon -{ - void daemonize(); - - void drop_root_privileges(const std::string &username, - const std::string &group); - - bool pid_of(const std::string& name, std::vector< pid_t >& result); -} -} - -#endif diff --git a/src/filefunc.hxx b/src/filefunc.hxx index b2216af..9de7873 100644 --- a/src/filefunc.hxx +++ b/src/filefunc.hxx @@ -7,7 +7,7 @@ #ifndef __FILEFUNC_HXX #define __FILEFUNC_HXX -#include "userfunc.hxx" +#include "userfunc.hpp" namespace I2n { diff --git a/src/userfunc.cpp b/src/userfunc.cpp index 2930ecd..c11ec20 100644 --- a/src/userfunc.cpp +++ b/src/userfunc.cpp @@ -11,7 +11,7 @@ * */ -#include "userfunc.hxx" +#include "userfunc.hpp" #include #include diff --git a/src/userfunc.hpp b/src/userfunc.hpp new file mode 100644 index 0000000..4ac1008 --- /dev/null +++ b/src/userfunc.hpp @@ -0,0 +1,87 @@ +/** @file + * @brief provides wrapper and tools for (system) user and group information. + * + * @copyright Intra2net AG + * + * @license commercial + * + * (c) Copyright 2007-2008 by Intra2net AG + * + * info@intra2net.com + * + */ + +#ifndef _I2N_USERFUNC_HPP_ +#define _I2N_USERFUNC_HPP_ + +#include +#include + +#include +#include + +namespace I2n +{ + +/** + * @brief structure similar to "struct passwd", but more C++ like. + */ +struct User +{ + std::string Name; + std::string Password; + uid_t Uid; + gid_t Gid; + std::string Gecos; + std::string Homedir; + std::string Shell; + + User(); + User(const std::string& name); + User(const char* name); + User(uid_t uid); + void clear(); + + bool is_valid() const; + + operator bool() const { return is_valid(); } +}; // eo struct User + + + +/** + * @brief structure similar to "struct group", but more C++ like. + */ +struct Group +{ + std::string Name; + std::string Password; + gid_t Gid; + std::vector< std::string > Members; + + Group(); + Group(const std::string& name); + Group(const char* name); + Group(gid_t gid); + void clear(); + + bool is_valid() const; + + operator bool() const { return is_valid(); } +}; // eo struct Group + +bool get_user(const std::string& name, User& result); +bool get_user(uid_t uid, User& result); + +User get_user(const std::string& name); +User get_user(uid_t uid); + +bool get_group(const std::string& name, Group& result); +bool get_group(gid_t gid, Group& result); + +Group get_group(const std::string& name); +Group get_group(gid_t gid); + +} // eo namespace I2n + +#endif diff --git a/src/userfunc.hxx b/src/userfunc.hxx deleted file mode 100644 index 4ac1008..0000000 --- a/src/userfunc.hxx +++ /dev/null @@ -1,87 +0,0 @@ -/** @file - * @brief provides wrapper and tools for (system) user and group information. - * - * @copyright Intra2net AG - * - * @license commercial - * - * (c) Copyright 2007-2008 by Intra2net AG - * - * info@intra2net.com - * - */ - -#ifndef _I2N_USERFUNC_HPP_ -#define _I2N_USERFUNC_HPP_ - -#include -#include - -#include -#include - -namespace I2n -{ - -/** - * @brief structure similar to "struct passwd", but more C++ like. - */ -struct User -{ - std::string Name; - std::string Password; - uid_t Uid; - gid_t Gid; - std::string Gecos; - std::string Homedir; - std::string Shell; - - User(); - User(const std::string& name); - User(const char* name); - User(uid_t uid); - void clear(); - - bool is_valid() const; - - operator bool() const { return is_valid(); } -}; // eo struct User - - - -/** - * @brief structure similar to "struct group", but more C++ like. - */ -struct Group -{ - std::string Name; - std::string Password; - gid_t Gid; - std::vector< std::string > Members; - - Group(); - Group(const std::string& name); - Group(const char* name); - Group(gid_t gid); - void clear(); - - bool is_valid() const; - - operator bool() const { return is_valid(); } -}; // eo struct Group - -bool get_user(const std::string& name, User& result); -bool get_user(uid_t uid, User& result); - -User get_user(const std::string& name); -User get_user(uid_t uid); - -bool get_group(const std::string& name, Group& result); -bool get_group(gid_t gid, Group& result); - -Group get_group(const std::string& name); -Group get_group(gid_t gid); - -} // eo namespace I2n - -#endif diff --git a/test/test_filefunc.cpp b/test/test_filefunc.cpp index e315df3..e011060 100644 --- a/test/test_filefunc.cpp +++ b/test/test_filefunc.cpp @@ -22,7 +22,7 @@ #include #include -#include +#include #ifdef NOISEDEBUG #define DOUT(msg) std::cout << msg << std::endl diff --git a/test/test_pidfile.cpp b/test/test_pidfile.cpp index 477072d..815ae85 100644 --- a/test/test_pidfile.cpp +++ b/test/test_pidfile.cpp @@ -52,7 +52,7 @@ public: PidFile pidfile(Filename); bool rtn_write = pidfile.write(); - CPPUNIT_ASSERT_EQUAL(rtn_write, true); + CPPUNIT_ASSERT_EQUAL(true, rtn_write); } void AutoRemoval() @@ -64,8 +64,8 @@ public: } bool exists = I2n::file_exists(Filename); - CPPUNIT_ASSERT_EQUAL(rtn_write, true); - CPPUNIT_ASSERT_EQUAL(exists, false); + CPPUNIT_ASSERT_EQUAL(true, rtn_write); + CPPUNIT_ASSERT_EQUAL(false, exists); } void NoAutoRemoval() @@ -78,8 +78,8 @@ public: bool exists = I2n::file_exists(Filename); I2n::unlink(Filename); - CPPUNIT_ASSERT_EQUAL(rtn_write, true); - CPPUNIT_ASSERT_EQUAL(exists, true); + CPPUNIT_ASSERT_EQUAL(true, rtn_write); + CPPUNIT_ASSERT_EQUAL(true, exists); } void NotRunning() @@ -87,7 +87,7 @@ public: PidFile pidfile(Filename); bool rtn_check = pidfile.check_already_running(); - CPPUNIT_ASSERT_EQUAL(rtn_check, false); + CPPUNIT_ASSERT_EQUAL(false, rtn_check); } void IsAlreadyRunning() @@ -96,13 +96,15 @@ public: bool rtn_file1_check = pidfile1.check_already_running(); bool rtn_file1_write = pidfile1.write(); - CPPUNIT_ASSERT_EQUAL(rtn_file1_check, false); - CPPUNIT_ASSERT_EQUAL(rtn_file1_write, true); + CPPUNIT_ASSERT_EQUAL(false, rtn_file1_check); + CPPUNIT_ASSERT_EQUAL(true, rtn_file1_write); PidFile pidfile2(Filename); - bool rtn_file2_check = pidfile2.check_already_running(); + pid_t my_pid = 0; + bool rtn_file2_check = pidfile2.check_already_running(&my_pid); - CPPUNIT_ASSERT_EQUAL(rtn_file2_check, true); + CPPUNIT_ASSERT_EQUAL(true, rtn_file2_check); + CPPUNIT_ASSERT_EQUAL(getpid(), my_pid); } private: -- 1.7.1