* nix-setuid-helper: allow running programs under a different uid.

This commit is contained in:
Eelco Dolstra 2006-12-06 17:29:10 +00:00
parent 9f0efa6611
commit 751f6d2157
3 changed files with 140 additions and 11 deletions

View 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();
}
}
}

View file

@ -14,7 +14,7 @@
#include <aterm2.h> #include <aterm2.h>
extern char * * environ; #include "setuid-common.hh"
namespace nix { namespace nix {
@ -218,20 +218,11 @@ static void setuidInit()
uid_t nixUid = geteuid(); uid_t nixUid = geteuid();
gid_t nixGid = getegid(); gid_t nixGid = getegid();
fprintf(stderr, "<<< setuid mode >>>\n"); setuidCleanup();
/* Don't trust the environment. */
environ = 0;
/* Don't trust the current directory. */ /* Don't trust the current directory. */
if (chdir("/") == -1) abort(); 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 /* Set the real (and preferably also the save) uid/gid to the
effective uid/gid. This matters mostly when we're not using effective uid/gid. This matters mostly when we're not using
build-users (bad!), since some builders (like Perl) complain build-users (bad!), since some builders (like Perl) complain

View file

@ -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) int main(int argc, char * * argv)
{ {
try {
run(argc, argv);
} catch (Error & e) {
std::cerr << e.msg() << std::endl;
return 1;
}
} }