diff options
Diffstat (limited to 'src/nix-setuid-helper')
-rw-r--r-- | src/nix-setuid-helper/main.cc | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/src/nix-setuid-helper/main.cc b/src/nix-setuid-helper/main.cc index ff70fa6560a8..50a059f50476 100644 --- a/src/nix-setuid-helper/main.cc +++ b/src/nix-setuid-helper/main.cc @@ -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; + } } |