* Remove --enable-setuid, --with-nix-user and --with-nix-group.

Rather, setuid support is now always compiled in (at least on
  platforms that have the setresuid system call, e.g., Linux and
  FreeBSD), but it must enabled by chowning/chmodding the Nix
  binaries.
This commit is contained in:
Eelco Dolstra 2006-11-29 21:06:58 +00:00
parent c6a97e3b74
commit 71e867c5f5
4 changed files with 52 additions and 60 deletions

View file

@ -20,10 +20,11 @@ install-data-local: init-state
fi fi
if INIT_STATE if INIT_STATE
if SETUID_HACK
INIT_FLAGS = -g @NIX_GROUP@ -o @NIX_USER@ # For setuid operation, you can enable the following:
GROUP_WRITABLE = -m 775 # INIT_FLAGS = -g @NIX_GROUP@ -o @NIX_USER@
endif # GROUP_WRITABLE = -m 775
init-state: init-state:
$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix $(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix
$(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix/db $(INSTALL) $(INIT_FLAGS) -d $(DESTDIR)$(localstatedir)/nix/db
@ -40,6 +41,7 @@ init-state:
$(INSTALL) $(INIT_FLAGS) -m 1777 -d $(DESTDIR)$(prefix)/store $(INSTALL) $(INIT_FLAGS) -m 1777 -d $(DESTDIR)$(prefix)/store
$(INSTALL) $(INIT_FLAGS) $(GROUP_WRITABLE) -d $(DESTDIR)$(localstatedir)/nix/manifests $(INSTALL) $(INIT_FLAGS) $(GROUP_WRITABLE) -d $(DESTDIR)$(localstatedir)/nix/manifests
# $(bindir)/nix-store --init # $(bindir)/nix-store --init
else else
init-state: init-state:
endif endif

View file

@ -237,32 +237,12 @@ AM_CONDITIONAL(INIT_STATE, test "$init_state" = "yes")
# Setuid installations. # Setuid installations.
AC_ARG_ENABLE(setuid, AC_HELP_STRING([--enable-setuid],
[install Nix setuid]),
setuid_hack=$enableval, setuid_hack=no)
AM_CONDITIONAL(SETUID_HACK, test "$setuid_hack" = "yes")
if test "$setuid_hack" = "yes"; then
AC_DEFINE(SETUID_HACK, 1, [whether to install Nix setuid])
fi
AC_CHECK_FUNC(setresuid, [HAVE_SETRESUID=1], [HAVE_SETRESUID=]) AC_CHECK_FUNC(setresuid, [HAVE_SETRESUID=1], [HAVE_SETRESUID=])
AM_CONDITIONAL(HAVE_SETRESUID, test "$HAVE_SETRESUID" = "1") AM_CONDITIONAL(HAVE_SETRESUID, test "$HAVE_SETRESUID" = "1")
if test "$HAVE_SETRESUID" = "1"; then if test "$HAVE_SETRESUID" = "1"; then
AC_DEFINE(HAVE_SETRESUID, 1, [whether we have setresuid()]) AC_DEFINE(HAVE_SETRESUID, 1, [whether we have setresuid()])
fi fi
AC_ARG_WITH(nix-user, AC_HELP_STRING([--with-nix-user=USER],
[user for Nix setuid binaries]),
NIX_USER=$withval, NIX_USER=nix)
AC_SUBST(NIX_USER)
AC_DEFINE_UNQUOTED(NIX_USER, ["$NIX_USER"], [Nix user])
AC_ARG_WITH(nix-group, AC_HELP_STRING([--with-nix-group=USER],
[group for Nix setuid binaries]),
NIX_GROUP=$withval, NIX_GROUP=nix)
AC_SUBST(NIX_GROUP)
AC_DEFINE_UNQUOTED(NIX_GROUP, ["$NIX_GROUP"], [Nix group])
# This is needed if ATerm, Berkeley DB or bzip2 are static libraries, # This is needed if ATerm, Berkeley DB or bzip2 are static libraries,
# and the Nix libraries are dynamic. # and the Nix libraries are dynamic.

View file

@ -3,13 +3,4 @@ SUBDIRS = bin2c boost libutil libstore libmain nix-store nix-hash \
EXTRA_DIST = aterm-helper.pl EXTRA_DIST = aterm-helper.pl
SETUID_PROGS = nix-store nix-instantiate nix-env #SETUID_PROGS = nix-store nix-instantiate nix-env
install-exec-hook:
if SETUID_HACK
if HAVE_SETRESUID
cd $(DESTDIR)$(bindir) && chown @NIX_USER@ $(SETUID_PROGS) \
&& chgrp @NIX_GROUP@ $(SETUID_PROGS) && chmod ug+s $(SETUID_PROGS)
else
cd $(DESTDIR)$(bindir) && chown root $(SETUID_PROGS) && chmod u+s $(SETUID_PROGS)
endif
endif

View file

@ -911,7 +911,7 @@ static gid_t savedGid, nixGid;
SwitchToOriginalUser::SwitchToOriginalUser() SwitchToOriginalUser::SwitchToOriginalUser()
{ {
#if SETUID_HACK && HAVE_SETRESUID #if HAVE_SETRESUID
/* Temporarily switch the effective uid/gid back to the saved /* Temporarily switch the effective uid/gid back to the saved
uid/gid (which is the uid/gid of the user that executed the Nix uid/gid (which is the uid/gid of the user that executed the Nix
program; it's *not* the real uid/gid, since we changed that to program; it's *not* the real uid/gid, since we changed that to
@ -928,7 +928,7 @@ SwitchToOriginalUser::SwitchToOriginalUser()
SwitchToOriginalUser::~SwitchToOriginalUser() SwitchToOriginalUser::~SwitchToOriginalUser()
{ {
#if SETUID_HACK && HAVE_SETRESUID #if HAVE_SETRESUID
/* Switch the effective uid/gid back to the Nix user. */ /* Switch the effective uid/gid back to the Nix user. */
if (haveSwitched) { if (haveSwitched) {
if (setuid(nixUid) == -1) if (setuid(nixUid) == -1)
@ -942,21 +942,43 @@ SwitchToOriginalUser::~SwitchToOriginalUser()
void switchToNixUser() void switchToNixUser()
{ {
#if SETUID_HACK fprintf(stderr, "real = %d/%d, effective = %d/%d\n",
getuid(), geteuid(), getgid(), getegid());
/* 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. */ /* Don't do anything if this is not a setuid binary. */
if (getuid() == geteuid() && getgid() == getegid()) return; if (getuid() == geteuid() && getgid() == getegid()) return;
/* Here we set the uid and gid to the Nix user and group, /* 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 respectively, IF the current (real) user is a member of the Nix
group. Otherwise we just drop all privileges. */ group. (The Nix group is the group of the current executable,
i.e., the current effective gid.) Otherwise we just drop all
privileges. */
/* Lookup the Nix gid. */ nixGid = geteuid();
struct group * gr = getgrnam(NIX_GROUP);
if (!gr) {
std::cerr << format("missing group `%1%'\n") % NIX_GROUP;
exit(1);
}
/* Get the supplementary group IDs for the current user. */ /* Get the supplementary group IDs for the current user. */
int maxGids = 512, nrGids; int maxGids = 512, nrGids;
@ -976,7 +998,7 @@ void switchToNixUser()
/* Check that the current user is a member of the Nix group. */ /* Check that the current user is a member of the Nix group. */
bool found = false; bool found = false;
for (int i = 0; i < nrGids; ++i) for (int i = 0; i < nrGids; ++i)
if (gids[i] == gr->gr_gid) { if (gids[i] == nixGid) {
found = true; found = true;
break; break;
} }
@ -988,31 +1010,29 @@ void switchToNixUser()
return; 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(); savedUid = getuid();
savedGid = getgid(); savedGid = getgid();
/* Set the real, effective and saved gids to gr->gr_gid. Also /* Set the real and effective gids to nixGid. Also make very sure
make very sure that this succeeded. We switch the gid first that this succeeded. We switch the gid first because we cannot
because we cannot do it after we have dropped root uid. */ do it after we have dropped root uid. */
nixGid = gr->gr_gid;
if (_setgid(nixGid) != 0 || getgid() != nixGid || getegid() != nixGid) { if (_setgid(nixGid) != 0 || getgid() != nixGid || getegid() != nixGid) {
std::cerr << format("unable to set gid to `%1%'\n") % NIX_GROUP; std::cerr << format("unable to set gid to `%1%'\n") % nixGid;
exit(1); exit(1);
} }
/* Lookup the Nix uid. */ /* The Nix uid is the effective uid of the owner of the current
struct passwd * pw = getpwnam(NIX_USER); executable, i.e., the current effective uid. */
if (!pw) { nixUid = geteuid();
std::cerr << format("missing user `%1%'\n") % NIX_USER;
exit(1);
}
/* This will drop all root privileges, setting the real, effective /* This will drop all root privileges, setting the real, effective
and saved uids to pw->pw_uid. Also make very sure that this and saved uids to pw->pw_uid. Also make very sure that this
succeeded.*/ succeeded.*/
nixUid = pw->pw_uid;
if (_setuid(nixUid) != 0 || getuid() != nixUid || geteuid() != nixUid) { if (_setuid(nixUid) != 0 || getuid() != nixUid || geteuid() != nixUid) {
std::cerr << format("unable to set uid to `%1%'\n") % NIX_USER; std::cerr << format("unable to set uid to `%1%'\n") % nixUid;
exit(1); exit(1);
} }
@ -1022,7 +1042,6 @@ void switchToNixUser()
*/ */
haveSwitched = true; haveSwitched = true;
#endif #endif
} }