aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorEelco Dolstra <e.dolstra@tudelft.nl>2006-12-02 15:45:51 +0000
committerEelco Dolstra <e.dolstra@tudelft.nl>2006-12-02 15:45:51 +0000
commit536595b072e73f72c421400c35d09089e7d54ca4 (patch)
treeda17bf21c7d101ca5d4a1ff30bb236d920807b25 /src
parent9c9cdb06d095ea91e10be8dae3a85f06a99c51bf (diff)
* Remove most of the old setuid code.
* Much simpler setuid code for the worker in slave mode.
Diffstat (limited to 'src')
-rw-r--r--src/libmain/shared.cc60
-rw-r--r--src/libutil/util.cc131
-rw-r--r--src/libutil/util.hh4
3 files changed, 57 insertions, 138 deletions
diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc
index 33576d69c..b4a0f774a 100644
--- a/src/libmain/shared.cc
+++ b/src/libmain/shared.cc
@@ -15,6 +15,9 @@
#include <aterm2.h>
+extern char * * environ;
+
+
namespace nix {
@@ -204,6 +207,54 @@ static void initAndRun(int argc, char * * argv)
}
+static void setuidInit()
+{
+ /* Don't do anything if this is not a setuid binary. */
+ if (getuid() == geteuid() && getgid() == getegid()) return;
+
+ uid_t nixUid = geteuid();
+ gid_t nixGid = getegid();
+
+ fprintf(stderr, "<<< setuid mode >>>\n");
+
+ /* Don't trust the environment. */
+ environ = 0;
+
+ /* Don't trust the current directory. */
+ if (chdir("/") == -1) abort();
+
+ /* Make sure that file descriptors 0, 1, 2 are open. */
+ for (int fd = 0; fd <= 2; ++fd) {
+ struct stat st;
+ if (fstat(fd, &st) == -1) abort();
+ }
+
+ /* Set the real (and preferably also the save) uid/gid to the
+ effective uid/gid. This matters mostly when we're not using
+ build-users (bad!), since some builders (like Perl) complain
+ when real != effective.
+
+ On systems where setresuid is unavailable, we can't drop the
+ saved uid/gid. This means that we could go back to the
+ original real uid (i.e., the uid of the caller). That's not
+ really a problem, except maybe when we execute a builder and
+ we're not using build-users. In that case, the builder may be
+ able to switch to the uid of the caller and possibly do bad
+ stuff. But note that when not using build-users, the builder
+ could also modify the Nix executables (say, replace them by a
+ Trojan horse), so the problem is already there. */
+
+#if HAVE_SETRESUID
+ setresuid(nixUid, nixUid, nixUid);
+ setresgid(nixGid, nixGid, nixGid);
+#else
+ /* Note: doesn't set saved uid/gid! */
+ setuid(nixUid);
+ setgid(nixGid);
+#endif
+}
+
+
}
@@ -212,10 +263,11 @@ static char buf[1024];
int main(int argc, char * * argv)
{
using namespace nix;
-
- /* If we are setuid root, we have to get rid of the excess
- privileges ASAP. */
- switchToNixUser();
+
+ /* If we're setuid, then we need to take some security precautions
+ right away. */
+ if (argc == 0) abort();
+ setuidInit();
/* ATerm setup. */
ATerm bottomOfStack;
diff --git a/src/libutil/util.cc b/src/libutil/util.cc
index 375e0e1df..5623b0131 100644
--- a/src/libutil/util.cc
+++ b/src/libutil/util.cc
@@ -11,11 +11,8 @@
#include <sys/stat.h>
#include <sys/wait.h>
-#include <fcntl.h>
-
#include <sys/types.h>
-#include <pwd.h>
-#include <grp.h>
+#include <fcntl.h>
#include "util.hh"
@@ -891,130 +888,4 @@ bool string2Int(const string & s, int & n)
}
-//////////////////////////////////////////////////////////////////////
-
-
-static bool haveSwitched;
-static uid_t savedUid, nixUid;
-static gid_t savedGid, nixGid;
-
-
-#if HAVE_SETRESUID
-#define _setuid(uid) setresuid(uid, uid, savedUid)
-#define _setgid(gid) setresgid(gid, gid, savedGid)
-#else
-/* Only works properly when run by root. */
-#define _setuid(uid) setuid(uid)
-#define _setgid(gid) setgid(gid)
-#endif
-
-
-void switchToNixUser()
-{
-#if 0
- fprintf(stderr, "real = %d/%d, effective = %d/%d\n",
- getuid(), getgid(), geteuid(), getegid());
-#endif
-
- /* Note: we require setresuid for now since I don't want to think
- to deeply about whether this works on systems that don't have
- setresuid. It's already hard enough. */
-
-#if HAVE_SETRESUID
-
- /* Setuid Nix operation works as follows:
-
- - The Nix binaries are owned by a Nix user and group, e.g.,
- nix.nix, and must setuid and setgid, e.g.,
-
- rwsrwsr-x nix.nix
-
- - Users (say alice.users) are only allowed to run (most) Nix
- operations if they are in the Nix group. If they aren't,
- some read-only operations (like nix-env -qa) may still work.
-
- - We run mostly under the Nix user/group, but we switch back to
- the calling user/group for some work, like reading Nix
- expressions.
-
- */
-
-
- /* Don't do anything if this is not a setuid binary. */
- if (getuid() == geteuid() && getgid() == getegid()) return;
-
- /* Here we set the uid and gid to the Nix user and group,
- respectively, IF the current (real) user is a member of the Nix
- group. (The Nix group is the group of the current executable,
- i.e., the current effective gid.) Otherwise we just drop all
- privileges. */
-
- nixGid = geteuid();
-
- /* Get the supplementary group IDs for the current user. */
- int maxGids = 512, nrGids;
- gid_t gids[maxGids];
- if ((nrGids = getgroups(maxGids, gids)) == -1) {
- std::cerr << format("unable to query gids\n");
- exit(1);
- }
-
- /* !!! Apparently it is unspecified whether getgroups() includes
- the effective gid. In that case the following test is always
- true *if* the program is installed setgid (which we do when we
- have setresuid()). On Linux this doesn't appear to be the
- case, but we should switch to the real gid before doing this
- test, and then switch back to the saved gid. */
-
- /* Check that the current user is a member of the Nix group. */
- bool found = false;
- for (int i = 0; i < nrGids; ++i)
- if (gids[i] == nixGid) {
- found = true;
- break;
- }
-
- if (!found) {
- /* Not in the Nix group - drop all root/Nix privileges. */
- _setgid(getgid());
- _setuid(getuid());
- return;
- }
-
- /* Save the uid/gid of the caller so the we can switch back to
- that uid/gid for temporary work, like accessing files, in
- SwitchToOriginaluser. */
- savedUid = getuid();
- savedGid = getgid();
-
- /* Set the real and effective gids to nixGid. Also make very sure
- that this succeeded. We switch the gid first because we cannot
- do it after we have dropped root uid. */
- if (_setgid(nixGid) != 0 || getgid() != nixGid || getegid() != nixGid) {
- std::cerr << format("unable to set gid to `%1%'\n") % nixGid;
- exit(1);
- }
-
- /* The Nix uid is the effective uid of the owner of the current
- executable, i.e., the current effective uid. */
- nixUid = geteuid();
-
- /* This will drop all root privileges, setting the real, effective
- and saved uids to pw->pw_uid. Also make very sure that this
- succeeded.*/
- if (_setuid(nixUid) != 0 || getuid() != nixUid || geteuid() != nixUid) {
- std::cerr << format("unable to set uid to `%1%'\n") % nixUid;
- exit(1);
- }
-
- /* !!! for setuid operation, we should: 1) wipe the environment;
- 2) verify file descriptors 0, 1, 2; 3) etc.
- See: http://www.daemon-systems.org/man/setuid.7.html
- */
-
- haveSwitched = true;
-#endif
-}
-
-
}
diff --git a/src/libutil/util.hh b/src/libutil/util.hh
index d1fb5b6e2..d49067dfe 100644
--- a/src/libutil/util.hh
+++ b/src/libutil/util.hh
@@ -249,10 +249,6 @@ string int2String(int n);
bool string2Int(const string & s, int & n);
-/* Setuid support. */
-void switchToNixUser();
-
-
}