Merge commit 'fdee1ced43fb495d612a29e955141cdf6b9a95ba' into nix

This commit is contained in:
Ludovic Courtès 2015-05-11 17:04:26 +02:00
commit 766481d606
10 changed files with 184 additions and 103 deletions

View File

@ -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();
@ -2075,9 +2077,9 @@ void DerivationGoal::initChild()
throw SysError("mounting /dev/pts");
createSymlink("/dev/pts/ptmx", chrootRootDir + "/dev/ptmx");
/* Make sure /dev/pts/ptmx is world-writable. With some
Linux versions, it is created with permissions 0. */
chmod_(chrootRootDir + "/dev/pts/ptmx", 0666);
/* Make sure /dev/pts/ptmx is world-writable. With some
Linux versions, it is created with permissions 0. */
chmod_(chrootRootDir + "/dev/pts/ptmx", 0666);
}
/* Do the chroot(). Below we do a chdir() to the

View File

@ -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") {

View File

@ -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;

View File

@ -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);

View File

@ -133,8 +133,6 @@ RemoteStore::~RemoteStore()
try {
to.flush();
fdSocket.close();
if (child != -1)
child.wait(true);
} catch (...) {
ignoreException();
}

View File

@ -87,7 +87,6 @@ private:
AutoCloseFD fdSocket;
FdSink to;
FdSource from;
Pid child;
unsigned int daemonVersion;
bool initialised;

View File

@ -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,39 +22,21 @@
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,
static void dumpContents(const Path & path, size_t size,
Sink & sink)
{
writeString("contents", sink);
@ -58,7 +44,7 @@ static void dumpContents(const Path & path, size_t size,
AutoCloseFD fd = open(path.c_str(), O_RDONLY);
if (fd == -1) throw SysError(format("opening file `%1%'") % path);
unsigned char buf[65536];
size_t left = size;
@ -89,12 +75,41 @@ static void dump(const Path & path, Sink & sink, PathFilter & filter)
writeString("", sink);
}
dumpContents(path, (size_t) st.st_size, sink);
}
}
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,43 +146,13 @@ 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)
{
unsigned long long size = readLongLong(source);
sink.preallocateContents(size);
unsigned long long left = size;
@ -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();
@ -221,9 +218,9 @@ static void parse(ParseSink & sink, Source & source, const Path & path)
else if (t == "symlink") {
type = tpSymlink;
}
else throw badArchive("unknown file type " + t);
}
else if (s == "contents" && type == tpRegular) {
@ -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,17 +274,15 @@ static void parse(ParseSink & sink, Source & source, const Path & path)
sink.createSymlink(path, target);
}
else {
else
throw badArchive("unknown field " + s);
skipGeneric(source);
}
}
}
void parseDump(ParseSink & sink, Source & source)
{
string version;
string version;
try {
version = readString(source);
} catch (SerialisationError & e) {
@ -323,7 +351,7 @@ struct RestoreSink : ParseSink
}
};
void restorePath(const Path & path, Source & source)
{
RestoreSink sink;
@ -331,5 +359,5 @@ void restorePath(const Path & path, Source & source)
parseDump(sink, source);
}
}

View File

@ -28,7 +28,7 @@ namespace nix {
where:
attrs(as) = concat(map(attr, as)) + encN(0)
attrs(as) = concat(map(attr, as)) + encN(0)
attrs((a, b)) = encS(a) + encS(b)
encS(s) = encN(len(s)) + s + (padding until next 64-bit boundary)
@ -58,7 +58,7 @@ void dumpPath(const Path & path, Sink & sink,
struct ParseSink
{
virtual void createDirectory(const Path & path) { };
virtual void createRegularFile(const Path & path) { };
virtual void isExecutable() { };
virtual void preallocateContents(unsigned long long size) { };
@ -66,10 +66,14 @@ struct ParseSink
virtual void createSymlink(const Path & path, const string & target) { };
};
void parseDump(ParseSink & sink, Source & source);
void restorePath(const Path & path, Source & source);
// FIXME: global variables are bad m'kay.
extern bool useCaseHack;
}

View File

@ -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);
}

View File

@ -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([&]() {