aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2010-08-19 20:08:23 +0100
committerAvatar Ciaran McCreesh <ciaran.mccreesh@googlemail.com> 2010-08-21 14:58:16 +0100
commitb17e35dcdbd14c3a73511b19c0e82cd52d212499 (patch)
tree364f3cf12893e0661af2a0de126d26b9ee99bd9d
parent322fc9a9acd2cfed2c3b7c70ee022e34fc1fd1f7 (diff)
downloadpaludis-b17e35dcdbd14c3a73511b19c0e82cd52d212499.tar.gz
paludis-b17e35dcdbd14c3a73511b19c0e82cd52d212499.tar.xz
Process::setuid_setgid
-rw-r--r--paludis/util/process.cc38
-rw-r--r--paludis/util/process.hh2
-rw-r--r--paludis/util/process_TEST.cc26
3 files changed, 64 insertions, 2 deletions
diff --git a/paludis/util/process.cc b/paludis/util/process.cc
index f93eeb8..ced2c2b 100644
--- a/paludis/util/process.cc
+++ b/paludis/util/process.cc
@@ -33,6 +33,8 @@
#include <cstdlib>
#include <unistd.h>
+#include <grp.h>
+#include <pwd.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/select.h>
@@ -211,13 +213,17 @@ namespace paludis
std::map<std::string, std::string> setenvs;
std::string chdir;
+ uid_t setuid;
+ gid_t setgid;
Imp(ProcessCommand && c) :
command(std::move(c)),
need_thread(false),
use_ptys(false),
capture_stdout(0),
- capture_stderr(0)
+ capture_stderr(0),
+ setuid(getuid()),
+ setgid(getgid())
{
}
};
@@ -286,6 +292,28 @@ Process::run()
if (-1 == ::chdir(_imp->chdir.c_str()))
throw ProcessError("chdir() failed");
+ if (_imp->setuid != getuid() || _imp->setgid != getgid())
+ {
+ if (0 != ::setgid(_imp->setgid))
+ throw ProcessError("setgid() failed");
+
+ int buflen(::sysconf(_SC_GETPW_R_SIZE_MAX));
+ if (-1 == buflen)
+ buflen = 1 << 16;
+
+ std::unique_ptr<char []> buf(new char[buflen]);
+ struct passwd pw;
+ struct passwd * pw_result(0);
+ if (0 != getpwuid_r(_imp->setuid, &pw, buf.get(), buflen, &pw_result) || 0 == pw_result)
+ throw ProcessError("getpwuid_r() failed");
+
+ if (0 != ::initgroups(pw_result->pw_name, getgid()))
+ throw ProcessError("initgroups() failed");
+
+ if (0 != ::setuid(_imp->setuid))
+ throw ProcessError("setuid() failed");
+ }
+
_imp->command.exec();
}
catch (const ProcessError & e)
@@ -339,6 +367,14 @@ Process::use_ptys()
return *this;
}
+Process &
+Process::setuid_setgid(uid_t u, gid_t g)
+{
+ _imp->setuid = u;
+ _imp->setgid = g;
+ return *this;
+}
+
namespace paludis
{
template <>
diff --git a/paludis/util/process.hh b/paludis/util/process.hh
index 0478b9b..0cc62e8 100644
--- a/paludis/util/process.hh
+++ b/paludis/util/process.hh
@@ -31,6 +31,7 @@
#include <memory>
#include <initializer_list>
+#include <sys/types.h>
#include <unistd.h>
namespace paludis
@@ -77,6 +78,7 @@ namespace paludis
Process & setenv(const std::string &, const std::string &);
Process & chdir(const FSEntry &);
Process & use_ptys();
+ Process & setuid_setgid(uid_t, gid_t);
};
class PALUDIS_VISIBLE RunningProcessHandle :
diff --git a/paludis/util/process_TEST.cc b/paludis/util/process_TEST.cc
index 1c344b0..a7361f3 100644
--- a/paludis/util/process_TEST.cc
+++ b/paludis/util/process_TEST.cc
@@ -22,11 +22,12 @@
#include <test/test_framework.hh>
#include <test/test_runner.hh>
#include <sstream>
+#include <sys/types.h>
+#include <pwd.h>
using namespace paludis;
using namespace test;
-
namespace test_cases
{
struct TrueTest : TestCase
@@ -208,5 +209,28 @@ namespace test_cases
TEST_CHECK_EQUAL(test_t_process.run().wait(), 0);
}
} test_ptys;
+
+ struct SetuidTest : TestCase
+ {
+ SetuidTest() : TestCase("setuid") { }
+
+ void run()
+ {
+ if (0 != getuid())
+ return;
+
+ std::stringstream stdout_stream;
+ Process whoami_process(ProcessCommand({"sh", "-c", "whoami ; groups"}));
+ whoami_process.capture_stdout(stdout_stream);
+
+ struct passwd * nobody(getpwnam("nobody"));
+ if (nobody)
+ {
+ whoami_process.setuid_setgid(nobody->pw_uid, nobody->pw_gid);
+ TEST_CHECK_EQUAL(whoami_process.run().wait(), 0);
+ TEST_CHECK_EQUAL(stdout_stream.str(), "nobody\nnobody\n");
+ }
+ }
+ } test_setuid;
}