* nix-setuid-helper: allow running programs under a different uid.
This commit is contained in:
parent
9f0efa6611
commit
751f6d2157
22
src/libmain/setuid-common.hh
Normal file
22
src/libmain/setuid-common.hh
Normal file
|
@ -0,0 +1,22 @@
|
|||
/* Code shared between libmain and nix-setuid-helper. */
|
||||
|
||||
extern char * * environ;
|
||||
|
||||
|
||||
namespace nix {
|
||||
|
||||
|
||||
void setuidCleanup()
|
||||
{
|
||||
/* Don't trust the environment. */
|
||||
environ = 0;
|
||||
|
||||
/* Make sure that file descriptors 0, 1, 2 are open. */
|
||||
for (int fd = 0; fd <= 2; ++fd) {
|
||||
struct stat st;
|
||||
if (fstat(fd, &st) == -1) abort();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
|
@ -14,7 +14,7 @@
|
|||
#include <aterm2.h>
|
||||
|
||||
|
||||
extern char * * environ;
|
||||
#include "setuid-common.hh"
|
||||
|
||||
|
||||
namespace nix {
|
||||
|
@ -218,20 +218,11 @@ static void setuidInit()
|
|||
uid_t nixUid = geteuid();
|
||||
gid_t nixGid = getegid();
|
||||
|
||||
fprintf(stderr, "<<< setuid mode >>>\n");
|
||||
|
||||
/* Don't trust the environment. */
|
||||
environ = 0;
|
||||
setuidCleanup();
|
||||
|
||||
/* Don't trust the current directory. */
|
||||
if (chdir("/") == -1) abort();
|
||||
|
||||
/* Make sure that file descriptors 0, 1, 2 are open. */
|
||||
for (int fd = 0; fd <= 2; ++fd) {
|
||||
struct stat st;
|
||||
if (fstat(fd, &st) == -1) abort();
|
||||
}
|
||||
|
||||
/* Set the real (and preferably also the save) uid/gid to the
|
||||
effective uid/gid. This matters mostly when we're not using
|
||||
build-users (bad!), since some builders (like Perl) complain
|
||||
|
|
|
@ -1,3 +1,119 @@
|
|||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <vector>
|
||||
|
||||
#include "util.hh"
|
||||
|
||||
#include "../libmain/setuid-common.hh"
|
||||
|
||||
using namespace nix;
|
||||
|
||||
|
||||
static void secureChown(uid_t uidTarget, gid_t gidTarget,
|
||||
const Path & path)
|
||||
{
|
||||
/* Recursively chown `path' to the specified uid and gid, but only
|
||||
if it is currently owned by the Nix account. */
|
||||
/* !!! */
|
||||
}
|
||||
|
||||
|
||||
static void runBuilder(string userName,
|
||||
string program, int argc, char * * argv)
|
||||
{
|
||||
struct passwd * pw = getpwnam(userName.c_str());
|
||||
if (!pw)
|
||||
throw Error(format("the user `%1%' does not exist") % userName);
|
||||
|
||||
gid_t gidBuilders = 1234;
|
||||
|
||||
/* Chown the current directory, *if* it is owned by the Nix
|
||||
account. The idea is that the current directory is the
|
||||
temporary build directory in /tmp or somewhere else, and we
|
||||
don't want to create that directory here. */
|
||||
secureChown(pw->pw_uid, gidBuilders, ".");
|
||||
|
||||
/* Set the real, effective and saved gid. Must be done before
|
||||
setuid(), otherwise it won't set the real and saved gids. */
|
||||
//setgid(gidBuilders);
|
||||
|
||||
/* Set the real, effective and saved uid. */
|
||||
setuid(pw->pw_uid);
|
||||
if (getuid() != pw->pw_uid || geteuid() != pw->pw_uid)
|
||||
throw Error("cannot setuid");
|
||||
|
||||
/* Execute the program. */
|
||||
std::vector<const char *> args;
|
||||
args.push_back(program.c_str());
|
||||
for (int i = 0; i < argc; ++i)
|
||||
args.push_back(argv[i]);
|
||||
args.push_back(0);
|
||||
|
||||
if (execve(program.c_str(), (char * *) &args[0], 0) == -1)
|
||||
throw SysError(format("cannot execute `%1%'") % program);
|
||||
}
|
||||
|
||||
|
||||
static void run(int argc, char * * argv)
|
||||
{
|
||||
char * * oldEnviron = environ;
|
||||
|
||||
setuidCleanup();
|
||||
|
||||
if (geteuid() != 0)
|
||||
throw Error("nix-setuid-wrapper must be setuid root");
|
||||
|
||||
|
||||
/* Read the configuration file. It should consist of two words:
|
||||
|
||||
<nix-user-name> <nix-builders-group>
|
||||
|
||||
The first is the privileged account under which the main Nix
|
||||
processes run (i.e., the supposed caller). It should match our
|
||||
real uid. The second is the Unix group to which the Nix
|
||||
builders belong (and nothing else!). */
|
||||
/* !!! */
|
||||
|
||||
|
||||
/* Make sure that we are called by the Nix account, not by someone
|
||||
else. */
|
||||
// ...
|
||||
|
||||
/* Perform the desired command. */
|
||||
if (argc < 2)
|
||||
throw Error("invalid arguments");
|
||||
|
||||
string command(argv[1]);
|
||||
|
||||
if (command == "run-builder") {
|
||||
/* Syntax: nix-setuid-helper run-builder <username> <program>
|
||||
<args...> */
|
||||
if (argc < 4) throw Error("missing user name / program name");
|
||||
runBuilder(argv[2], argv[3], argc - 4, argv + 4);
|
||||
}
|
||||
|
||||
else if (command == "fix-ownership") {
|
||||
/* Syntax: nix-setuid-helper <fix-ownership> <path> */
|
||||
}
|
||||
|
||||
else throw Error ("invalid command");
|
||||
}
|
||||
|
||||
|
||||
|
||||
int main(int argc, char * * argv)
|
||||
{
|
||||
try {
|
||||
run(argc, argv);
|
||||
} catch (Error & e) {
|
||||
std::cerr << e.msg() << std::endl;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue