about summary refs log tree commit diff
diff options
context:
space:
mode:
authorEelco Dolstra <eelco.dolstra@logicblox.com>2014-07-17T14·57+0200
committerEelco Dolstra <eelco.dolstra@logicblox.com>2014-07-17T14·57+0200
commit049c0eb49c621ae50f49c8a06dc6c3a9839ef388 (patch)
tree63c0f299510adda0e21c7d323917eefcd5e1f6ce
parent0c730887c4ec4a03fb854490e422c134a1bf8139 (diff)
nix-daemon: Add trusted-users and allowed-users options
‘trusted-users’ is a list of users and groups that have elevated
rights, such as the ability to specify binary caches. It defaults to
‘root’. A typical value would be ‘@wheel’ to specify all users in the
wheel group.

‘allowed-users’ is a list of users and groups that are allowed to
connect to the daemon. It defaults to ‘*’. A typical value would be
‘@users’ to specify the ‘users’ group.
-rw-r--r--doc/manual/conf-file.xml42
-rw-r--r--src/libstore/globals.cc4
-rw-r--r--src/libstore/globals.hh9
-rw-r--r--src/nix-daemon/nix-daemon.cc38
4 files changed, 90 insertions, 3 deletions
diff --git a/doc/manual/conf-file.xml b/doc/manual/conf-file.xml
index 29f7f9c51aea..6af4c776548d 100644
--- a/doc/manual/conf-file.xml
+++ b/doc/manual/conf-file.xml
@@ -479,6 +479,48 @@ flag, e.g. <literal>--option gc-keep-outputs false</literal>.</para>
   </varlistentry>
 
 
+  <varlistentry xml:id="conf-trusted-users"><term><literal>trusted-users</literal></term>
+
+    <listitem>
+
+      <para>A list of names of users (separated by whitespace) that
+      have additional rights when connecting to the Nix daemon, such
+      as the ability to specify additional binary caches, or to import
+      unsigned NARs. You can also specify groups by prefixing them
+      with <literal>@</literal>; for instance,
+      <literal>@wheel</literal> means all users in the
+      <literal>wheel</literal> group. The default is
+      <literal>root</literal>.</para>
+
+      <warning><para>The users listed here have the ability to
+      compromise the security of a multi-user Nix store. For instance,
+      they could install Trojan horses subsequently executed by other
+      users. So you should consider carefully whether to add users to
+      this list.</para></warning>
+
+    </listitem>
+
+  </varlistentry>
+
+
+  <varlistentry xml:id="conf-allowed-users"><term><literal>allowed-users</literal></term>
+
+    <listitem>
+
+      <para>A list of names of users (separated by whitespace) that
+      are allowed to connect to the Nix daemon. As with the
+      <option>trusted-users</option> option, you can specify groups by
+      prefixing them with <literal>@</literal>. Also, you can allow
+      all users by specifying <literal>*</literal>. The default is
+      <literal>*</literal>.</para>
+
+      <para>Note that trusted users are always allowed to connect.</para>
+
+    </listitem>
+
+  </varlistentry>
+
+
 </variablelist>
 
 </para>
diff --git a/src/libstore/globals.cc b/src/libstore/globals.cc
index 60bc1dba13ff..2bfebb77a130 100644
--- a/src/libstore/globals.cc
+++ b/src/libstore/globals.cc
@@ -63,6 +63,8 @@ Settings::Settings()
     lockCPU = getEnv("NIX_AFFINITY_HACK", "1") == "1";
     showTrace = false;
     enableImportNative = false;
+    trustedUsers = Strings({"root"});
+    allowedUsers = Strings({"*"});
 }
 
 
@@ -152,6 +154,8 @@ void Settings::update()
     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") {
diff --git a/src/libstore/globals.hh b/src/libstore/globals.hh
index 8dd59a9c7967..f1748336fdac 100644
--- a/src/libstore/globals.hh
+++ b/src/libstore/globals.hh
@@ -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;
 
diff --git a/src/nix-daemon/nix-daemon.cc b/src/nix-daemon/nix-daemon.cc
index fd030fe47674..dde501d30990 100644
--- a/src/nix-daemon/nix-daemon.cc
+++ b/src/nix-daemon/nix-daemon.cc
@@ -7,6 +7,8 @@
 #include "affinity.hh"
 #include "globals.hh"
 
+#include <algorithm>
+
 #include <cstring>
 #include <unistd.h>
 #include <signal.h>
@@ -18,6 +20,7 @@
 #include <fcntl.h>
 #include <errno.h>
 #include <pwd.h>
+#include <grp.h>
 
 using namespace nix;
 
@@ -451,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;
@@ -770,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
 
 
@@ -870,9 +894,17 @@ static void daemonLoop()
             struct passwd * pw = getpwuid(cred.uid);
             string user = pw ? pw->pw_name : int2String(cred.uid);
 
-            if (cred.uid == 0) trusted = true;
+            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("accepted connection from pid %1%, user %2%") % clientPid % user);
+            printMsg(lvlInfo, format((string) "accepted connection from pid %1%, user %2%"
+                    + (trusted ? " (trusted)" : "")) % clientPid % user);
 #endif
 
             /* Fork a child to handle the connection. */