* Check that the caller is allowed to call the setuid helper. The
allowed uid is specified in a configuration file in /etc/nix-setuid.conf.
This commit is contained in:
parent
173d328351
commit
f07ac41656
1 changed files with 50 additions and 13 deletions
|
@ -1,6 +1,7 @@
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
|
#include <fcntl.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include <pwd.h>
|
#include <pwd.h>
|
||||||
|
@ -25,20 +26,26 @@ static void secureChown(uid_t uidTarget, gid_t gidTarget,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void runBuilder(string userName,
|
static uid_t nameToUid(const string & userName)
|
||||||
string program, int argc, char * * argv)
|
|
||||||
{
|
{
|
||||||
struct passwd * pw = getpwnam(userName.c_str());
|
struct passwd * pw = getpwnam(userName.c_str());
|
||||||
if (!pw)
|
if (!pw)
|
||||||
throw Error(format("the user `%1%' does not exist") % userName);
|
throw Error(format("user `%1%' does not exist") % userName);
|
||||||
|
return pw->pw_uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void runBuilder(const string & targetUser,
|
||||||
|
string program, int argc, char * * argv)
|
||||||
|
{
|
||||||
|
uid_t uidTargetUser = nameToUid(targetUser);
|
||||||
gid_t gidBuilders = 1234;
|
gid_t gidBuilders = 1234;
|
||||||
|
|
||||||
/* Chown the current directory, *if* it is owned by the Nix
|
/* Chown the current directory, *if* it is owned by the Nix
|
||||||
account. The idea is that the current directory is the
|
account. The idea is that the current directory is the
|
||||||
temporary build directory in /tmp or somewhere else, and we
|
temporary build directory in /tmp or somewhere else, and we
|
||||||
don't want to create that directory here. */
|
don't want to create that directory here. */
|
||||||
secureChown(pw->pw_uid, gidBuilders, ".");
|
secureChown(uidTargetUser, gidBuilders, ".");
|
||||||
|
|
||||||
|
|
||||||
/* Set the real, effective and saved gid. Must be done before
|
/* Set the real, effective and saved gid. Must be done before
|
||||||
|
@ -48,9 +55,9 @@ static void runBuilder(string userName,
|
||||||
//setgid(gidBuilders);
|
//setgid(gidBuilders);
|
||||||
|
|
||||||
/* Set the real, effective and saved uid. */
|
/* Set the real, effective and saved uid. */
|
||||||
if (setuid(pw->pw_uid) == -1 ||
|
if (setuid(uidTargetUser) == -1 ||
|
||||||
getuid() != pw->pw_uid ||
|
getuid() != uidTargetUser ||
|
||||||
geteuid() != pw->pw_uid)
|
geteuid() != uidTargetUser)
|
||||||
throw SysError("setuid failed");
|
throw SysError("setuid failed");
|
||||||
|
|
||||||
/* Execute the program. */
|
/* Execute the program. */
|
||||||
|
@ -65,6 +72,11 @@ static void runBuilder(string userName,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#ifndef NIX_SETUID_CONFIG_FILE
|
||||||
|
#define NIX_SETUID_CONFIG_FILE "/etc/nix-setuid.conf"
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
||||||
static void run(int argc, char * * argv)
|
static void run(int argc, char * * argv)
|
||||||
{
|
{
|
||||||
char * * oldEnviron = environ;
|
char * * oldEnviron = environ;
|
||||||
|
@ -83,13 +95,38 @@ static void run(int argc, char * * argv)
|
||||||
processes run (i.e., the supposed caller). It should match our
|
processes run (i.e., the supposed caller). It should match our
|
||||||
real uid. The second is the Unix group to which the Nix
|
real uid. The second is the Unix group to which the Nix
|
||||||
builders belong (and nothing else!). */
|
builders belong (and nothing else!). */
|
||||||
/* !!! */
|
string configFile = NIX_SETUID_CONFIG_FILE;
|
||||||
|
AutoCloseFD fdConfig = open(configFile.c_str(), O_RDONLY);
|
||||||
|
if (fdConfig == -1)
|
||||||
/* Make sure that we are called by the Nix account, not by someone
|
throw SysError(format("opening `%1%'") % configFile);
|
||||||
else. */
|
|
||||||
// ...
|
|
||||||
|
|
||||||
|
/* Config file should be owned by root. */
|
||||||
|
struct stat st;
|
||||||
|
if (fstat(fdConfig, &st) == -1) throw SysError("statting file");
|
||||||
|
if (st.st_uid != 0)
|
||||||
|
throw Error(format("`%1%' not owned by root") % configFile);
|
||||||
|
if (st.st_mode & (S_IWGRP | S_IWOTH))
|
||||||
|
throw Error(format("`%1%' should not be group or world-writable") % configFile);
|
||||||
|
|
||||||
|
Strings tokens = tokenizeString(readFile(fdConfig));
|
||||||
|
|
||||||
|
fdConfig.close();
|
||||||
|
|
||||||
|
if (tokens.size() != 2)
|
||||||
|
throw Error(format("parse error in `%1%'") % configFile);
|
||||||
|
|
||||||
|
Strings::iterator i = tokens.begin();
|
||||||
|
string allowedUser = *i++;
|
||||||
|
string buildUsersGroup = *i++;
|
||||||
|
|
||||||
|
|
||||||
|
/* Check that the caller (real uid) is the one allowed to call
|
||||||
|
this program. */
|
||||||
|
uid_t uidAllowedUser = nameToUid(allowedUser);
|
||||||
|
if (uidAllowedUser != getuid())
|
||||||
|
throw Error("you are not allowed to call this program, go away");
|
||||||
|
|
||||||
|
|
||||||
/* Perform the desired command. */
|
/* Perform the desired command. */
|
||||||
if (argc < 2)
|
if (argc < 2)
|
||||||
throw Error("invalid arguments");
|
throw Error("invalid arguments");
|
||||||
|
|
Loading…
Reference in a new issue