Merge commit 'fdee1ced43fb495d612a29e955141cdf6b9a95ba' into nix
This commit is contained in:
commit
766481d606
|
@ -590,7 +590,9 @@ HookInstance::HookInstance()
|
|||
{
|
||||
debug("starting build hook");
|
||||
|
||||
Path buildHook = absPath(getEnv("NIX_BUILD_HOOK"));
|
||||
Path buildHook = getEnv("NIX_BUILD_HOOK");
|
||||
if (string(buildHook, 0, 1) != "/") buildHook = settings.nixLibexecDir + "/nix/" + buildHook;
|
||||
buildHook = canonPath(buildHook);
|
||||
|
||||
/* Create a pipe to get the output of the child. */
|
||||
fromHook.create();
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
|
||||
#include "globals.hh"
|
||||
#include "util.hh"
|
||||
#include "archive.hh"
|
||||
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
|
@ -56,6 +57,8 @@ Settings::Settings()
|
|||
lockCPU = getEnv("NIX_AFFINITY_HACK", "1") == "1";
|
||||
showTrace = false;
|
||||
enableImportNative = false;
|
||||
trustedUsers = Strings({"root"});
|
||||
allowedUsers = Strings({"*"});
|
||||
}
|
||||
|
||||
|
||||
|
@ -144,6 +147,9 @@ void Settings::update()
|
|||
get(useSshSubstituter, "use-ssh-substituter");
|
||||
get(logServers, "log-servers");
|
||||
get(enableImportNative, "allow-unsafe-native-code-during-evaluation");
|
||||
get(useCaseHack, "use-case-hack");
|
||||
get(trustedUsers, "trusted-users");
|
||||
get(allowedUsers, "allowed-users");
|
||||
|
||||
string subs = getEnv("NIX_SUBSTITUTERS", "default");
|
||||
if (subs == "default") {
|
||||
|
|
|
@ -203,6 +203,15 @@ struct Settings {
|
|||
/* Whether the importNative primop should be enabled */
|
||||
bool enableImportNative;
|
||||
|
||||
/* List of users that have elevated rights in the Nix daemon, such
|
||||
as the ability to specify additional binary caches, or to
|
||||
import unsigned NARs. */
|
||||
Strings trustedUsers;
|
||||
|
||||
/* List of users that are allowed to connect to the daemon, in
|
||||
addition to the trusted users. These have normal rights. */
|
||||
Strings allowedUsers;
|
||||
|
||||
private:
|
||||
SettingsMap settings, overrides;
|
||||
|
||||
|
|
|
@ -1486,6 +1486,8 @@ void LocalStore::exportPath(const Path & path, bool sign,
|
|||
{
|
||||
assertStorePath(path);
|
||||
|
||||
printMsg(lvlInfo, format("exporting path `%1%'") % path);
|
||||
|
||||
addTempRoot(path);
|
||||
if (!isValidPath(path))
|
||||
throw Error(format("path `%1%' is not valid") % path);
|
||||
|
@ -1596,8 +1598,6 @@ Path LocalStore::importPath(bool requireSignature, Source & source)
|
|||
|
||||
Path dstPath = readStorePath(hashAndReadSource);
|
||||
|
||||
printMsg(lvlInfo, format("importing path `%1%'") % dstPath);
|
||||
|
||||
PathSet references = readStorePaths<PathSet>(hashAndReadSource);
|
||||
|
||||
Path deriver = readString(hashAndReadSource);
|
||||
|
|
|
@ -133,8 +133,6 @@ RemoteStore::~RemoteStore()
|
|||
try {
|
||||
to.flush();
|
||||
fdSocket.close();
|
||||
if (child != -1)
|
||||
child.wait(true);
|
||||
} catch (...) {
|
||||
ignoreException();
|
||||
}
|
||||
|
|
|
@ -87,7 +87,6 @@ private:
|
|||
AutoCloseFD fdSocket;
|
||||
FdSink to;
|
||||
FdSource from;
|
||||
Pid child;
|
||||
unsigned int daemonVersion;
|
||||
bool initialised;
|
||||
|
||||
|
|
|
@ -1,10 +1,14 @@
|
|||
#define _XOPEN_SOURCE 600
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <cerrno>
|
||||
#include <algorithm>
|
||||
#include <vector>
|
||||
#include <map>
|
||||
|
||||
#include <strings.h> // for strcasecmp
|
||||
|
||||
#define _XOPEN_SOURCE 600
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <unistd.h>
|
||||
|
@ -18,38 +22,20 @@
|
|||
namespace nix {
|
||||
|
||||
|
||||
bool useCaseHack =
|
||||
#if __APPLE__
|
||||
true;
|
||||
#else
|
||||
false;
|
||||
#endif
|
||||
|
||||
static string archiveVersion1 = "nix-archive-1";
|
||||
|
||||
static string caseHackSuffix = "~nix~case~hack~";
|
||||
|
||||
PathFilter defaultPathFilter;
|
||||
|
||||
|
||||
static void dump(const string & path, Sink & sink, PathFilter & filter);
|
||||
|
||||
|
||||
static void dumpEntries(const Path & path, Sink & sink, PathFilter & filter)
|
||||
{
|
||||
Strings names = readDirectory(path);
|
||||
vector<string> names2(names.begin(), names.end());
|
||||
sort(names2.begin(), names2.end());
|
||||
|
||||
for (vector<string>::iterator i = names2.begin();
|
||||
i != names2.end(); ++i)
|
||||
{
|
||||
Path entry = path + "/" + *i;
|
||||
if (filter(entry)) {
|
||||
writeString("entry", sink);
|
||||
writeString("(", sink);
|
||||
writeString("name", sink);
|
||||
writeString(*i, sink);
|
||||
writeString("node", sink);
|
||||
dump(entry, sink, filter);
|
||||
writeString(")", sink);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void dumpContents(const Path & path, size_t size,
|
||||
Sink & sink)
|
||||
{
|
||||
|
@ -94,7 +80,36 @@ static void dump(const Path & path, Sink & sink, PathFilter & filter)
|
|||
else if (S_ISDIR(st.st_mode)) {
|
||||
writeString("type", sink);
|
||||
writeString("directory", sink);
|
||||
dumpEntries(path, sink, filter);
|
||||
|
||||
/* If we're on a case-insensitive system like Mac OS X, undo
|
||||
the case hack applied by restorePath(). */
|
||||
Strings names = readDirectory(path);
|
||||
std::map<string, string> unhacked;
|
||||
for (auto & i : names)
|
||||
if (useCaseHack) {
|
||||
string name(i);
|
||||
size_t pos = i.find(caseHackSuffix);
|
||||
if (pos != string::npos) {
|
||||
printMsg(lvlDebug, format("removing case hack suffix from `%1%'") % (path + "/" + i));
|
||||
name.erase(pos);
|
||||
}
|
||||
if (unhacked.find(name) != unhacked.end())
|
||||
throw Error(format("file name collision in between `%1%' and `%2%'")
|
||||
% (path + "/" + unhacked[name]) % (path + "/" + i));
|
||||
unhacked[name] = i;
|
||||
} else
|
||||
unhacked[i] = i;
|
||||
|
||||
for (auto & i : unhacked)
|
||||
if (filter(path + "/" + i.first)) {
|
||||
writeString("entry", sink);
|
||||
writeString("(", sink);
|
||||
writeString("name", sink);
|
||||
writeString(i.first, sink);
|
||||
writeString("node", sink);
|
||||
dump(path + "/" + i.second, sink, filter);
|
||||
writeString(")", sink);
|
||||
}
|
||||
}
|
||||
|
||||
else if (S_ISLNK(st.st_mode)) {
|
||||
|
@ -123,6 +138,7 @@ static SerialisationError badArchive(string s)
|
|||
}
|
||||
|
||||
|
||||
#if 0
|
||||
static void skipGeneric(Source & source)
|
||||
{
|
||||
if (readString(source) == "(") {
|
||||
|
@ -130,37 +146,7 @@ static void skipGeneric(Source & source)
|
|||
skipGeneric(source);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
static void parse(ParseSink & sink, Source & source, const Path & path);
|
||||
|
||||
|
||||
|
||||
static void parseEntry(ParseSink & sink, Source & source, const Path & path)
|
||||
{
|
||||
string s, name;
|
||||
|
||||
s = readString(source);
|
||||
if (s != "(") throw badArchive("expected open tag");
|
||||
|
||||
while (1) {
|
||||
checkInterrupt();
|
||||
|
||||
s = readString(source);
|
||||
|
||||
if (s == ")") {
|
||||
break;
|
||||
} else if (s == "name") {
|
||||
name = readString(source);
|
||||
} else if (s == "node") {
|
||||
if (s == "") throw badArchive("entry name missing");
|
||||
parse(sink, source, path + "/" + name);
|
||||
} else {
|
||||
throw badArchive("unknown field " + s);
|
||||
skipGeneric(source);
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static void parseContents(ParseSink & sink, Source & source, const Path & path)
|
||||
|
@ -185,6 +171,15 @@ static void parseContents(ParseSink & sink, Source & source, const Path & path)
|
|||
}
|
||||
|
||||
|
||||
struct CaseInsensitiveCompare
|
||||
{
|
||||
bool operator() (const string & a, const string & b) const
|
||||
{
|
||||
return strcasecmp(a.c_str(), b.c_str()) < 0;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
static void parse(ParseSink & sink, Source & source, const Path & path)
|
||||
{
|
||||
string s;
|
||||
|
@ -194,6 +189,8 @@ static void parse(ParseSink & sink, Source & source, const Path & path)
|
|||
|
||||
enum { tpUnknown, tpRegular, tpDirectory, tpSymlink } type = tpUnknown;
|
||||
|
||||
std::map<Path, int, CaseInsensitiveCompare> names;
|
||||
|
||||
while (1) {
|
||||
checkInterrupt();
|
||||
|
||||
|
@ -236,7 +233,40 @@ static void parse(ParseSink & sink, Source & source, const Path & path)
|
|||
}
|
||||
|
||||
else if (s == "entry" && type == tpDirectory) {
|
||||
parseEntry(sink, source, path);
|
||||
string name, prevName;
|
||||
|
||||
s = readString(source);
|
||||
if (s != "(") throw badArchive("expected open tag");
|
||||
|
||||
while (1) {
|
||||
checkInterrupt();
|
||||
|
||||
s = readString(source);
|
||||
|
||||
if (s == ")") {
|
||||
break;
|
||||
} else if (s == "name") {
|
||||
name = readString(source);
|
||||
if (name.empty() || name == "." || name == ".." || name.find('/') != string::npos || name.find((char) 0) != string::npos)
|
||||
throw Error(format("NAR contains invalid file name `%1%'") % name);
|
||||
if (name <= prevName)
|
||||
throw Error("NAR directory is not sorted");
|
||||
prevName = name;
|
||||
if (useCaseHack) {
|
||||
auto i = names.find(name);
|
||||
if (i != names.end()) {
|
||||
printMsg(lvlDebug, format("case collision between `%1%' and `%2%'") % i->first % name);
|
||||
name += caseHackSuffix;
|
||||
name += int2String(++i->second);
|
||||
} else
|
||||
names[name] = 0;
|
||||
}
|
||||
} else if (s == "node") {
|
||||
if (s.empty()) throw badArchive("entry name missing");
|
||||
parse(sink, source, path + "/" + name);
|
||||
} else
|
||||
throw badArchive("unknown field " + s);
|
||||
}
|
||||
}
|
||||
|
||||
else if (s == "target" && type == tpSymlink) {
|
||||
|
@ -244,10 +274,8 @@ static void parse(ParseSink & sink, Source & source, const Path & path)
|
|||
sink.createSymlink(path, target);
|
||||
}
|
||||
|
||||
else {
|
||||
else
|
||||
throw badArchive("unknown field " + s);
|
||||
skipGeneric(source);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -72,4 +72,8 @@ void parseDump(ParseSink & sink, Source & source);
|
|||
void restorePath(const Path & path, Source & source);
|
||||
|
||||
|
||||
// FIXME: global variables are bad m'kay.
|
||||
extern bool useCaseHack;
|
||||
|
||||
|
||||
}
|
||||
|
|
|
@ -708,17 +708,14 @@ void AutoCloseDir::close()
|
|||
|
||||
|
||||
Pid::Pid()
|
||||
: pid(-1), separatePG(false), killSignal(SIGKILL)
|
||||
{
|
||||
pid = -1;
|
||||
separatePG = false;
|
||||
killSignal = SIGKILL;
|
||||
}
|
||||
|
||||
|
||||
Pid::Pid(pid_t pid)
|
||||
: pid(pid), separatePG(false), killSignal(SIGKILL)
|
||||
{
|
||||
Pid();
|
||||
*this = pid;
|
||||
}
|
||||
|
||||
|
||||
|
@ -857,8 +854,10 @@ pid_t startProcess(std::function<void()> fun, const string & errorPrefix)
|
|||
restoreAffinity();
|
||||
fun();
|
||||
} catch (std::exception & e) {
|
||||
writeToStderr(errorPrefix + string(e.what()) + "\n");
|
||||
}
|
||||
try {
|
||||
std::cerr << errorPrefix << e.what() << "\n";
|
||||
} catch (...) { }
|
||||
} catch (...) { }
|
||||
_exit(1);
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,8 @@
|
|||
#include "affinity.hh"
|
||||
#include "globals.hh"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
#include <cstring>
|
||||
#include <unistd.h>
|
||||
#include <signal.h>
|
||||
|
@ -17,6 +19,8 @@
|
|||
#include <sys/un.h>
|
||||
#include <fcntl.h>
|
||||
#include <errno.h>
|
||||
#include <pwd.h>
|
||||
#include <grp.h>
|
||||
|
||||
using namespace nix;
|
||||
|
||||
|
@ -450,7 +454,7 @@ static void performOp(bool trusted, unsigned int clientVersion,
|
|||
case wopImportPaths: {
|
||||
startWork();
|
||||
TunnelSource source(from);
|
||||
Paths paths = store->importPaths(true, source);
|
||||
Paths paths = store->importPaths(!trusted, source);
|
||||
stopWork();
|
||||
writeStrings(paths, to);
|
||||
break;
|
||||
|
@ -769,6 +773,27 @@ static void setSigChldAction(bool autoReap)
|
|||
}
|
||||
|
||||
|
||||
bool matchUser(const string & user, const string & group, const Strings & users)
|
||||
{
|
||||
if (find(users.begin(), users.end(), "*") != users.end())
|
||||
return true;
|
||||
|
||||
if (find(users.begin(), users.end(), user) != users.end())
|
||||
return true;
|
||||
|
||||
for (auto & i : users)
|
||||
if (string(i, 0, 1) == "@") {
|
||||
if (group == string(i, 1)) return true;
|
||||
struct group * gr = getgrnam(i.c_str() + 1);
|
||||
if (!gr) continue;
|
||||
for (char * * mem = gr->gr_mem; *mem; mem++)
|
||||
if (user == string(*mem)) return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
#define SD_LISTEN_FDS_START 3
|
||||
|
||||
|
||||
|
@ -854,22 +879,33 @@ static void daemonLoop()
|
|||
|
||||
closeOnExec(remote);
|
||||
|
||||
/* Get the identity of the caller, if possible. */
|
||||
uid_t clientUid = -1;
|
||||
pid_t clientPid = -1;
|
||||
bool trusted = false;
|
||||
pid_t clientPid = -1;
|
||||
|
||||
#if defined(SO_PEERCRED)
|
||||
/* Get the identity of the caller, if possible. */
|
||||
ucred cred;
|
||||
socklen_t credLen = sizeof(cred);
|
||||
if (getsockopt(remote, SOL_SOCKET, SO_PEERCRED, &cred, &credLen) != -1) {
|
||||
clientPid = cred.pid;
|
||||
clientUid = cred.uid;
|
||||
if (clientUid == 0) trusted = true;
|
||||
}
|
||||
#endif
|
||||
if (getsockopt(remote, SOL_SOCKET, SO_PEERCRED, &cred, &credLen) == -1)
|
||||
throw SysError("getting peer credentials");
|
||||
|
||||
printMsg(lvlInfo, format("accepted connection from pid %1%, uid %2%") % clientPid % clientUid);
|
||||
clientPid = cred.pid;
|
||||
|
||||
struct passwd * pw = getpwuid(cred.uid);
|
||||
string user = pw ? pw->pw_name : int2String(cred.uid);
|
||||
|
||||
struct group * gr = getgrgid(cred.gid);
|
||||
string group = gr ? gr->gr_name : int2String(cred.gid);
|
||||
|
||||
if (matchUser(user, group, settings.trustedUsers))
|
||||
trusted = true;
|
||||
|
||||
if (!trusted && !matchUser(user, group, settings.allowedUsers))
|
||||
throw Error(format("user `%1%' is not allowed to connect to the Nix daemon") % user);
|
||||
|
||||
printMsg(lvlInfo, format((string) "accepted connection from pid %1%, user %2%"
|
||||
+ (trusted ? " (trusted)" : "")) % clientPid % user);
|
||||
#endif
|
||||
|
||||
/* Fork a child to handle the connection. */
|
||||
startProcess([&]() {
|
||||
|
|
Loading…
Reference in New Issue