forked from lix-project/lix
* Remove most of the old setuid code.
* Much simpler setuid code for the worker in slave mode.
This commit is contained in:
parent
9c9cdb06d0
commit
536595b072
|
@ -15,6 +15,9 @@
|
||||||
#include <aterm2.h>
|
#include <aterm2.h>
|
||||||
|
|
||||||
|
|
||||||
|
extern char * * environ;
|
||||||
|
|
||||||
|
|
||||||
namespace nix {
|
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)
|
int main(int argc, char * * argv)
|
||||||
{
|
{
|
||||||
using namespace nix;
|
using namespace nix;
|
||||||
|
|
||||||
/* If we are setuid root, we have to get rid of the excess
|
/* If we're setuid, then we need to take some security precautions
|
||||||
privileges ASAP. */
|
right away. */
|
||||||
switchToNixUser();
|
if (argc == 0) abort();
|
||||||
|
setuidInit();
|
||||||
|
|
||||||
/* ATerm setup. */
|
/* ATerm setup. */
|
||||||
ATerm bottomOfStack;
|
ATerm bottomOfStack;
|
||||||
|
|
|
@ -11,11 +11,8 @@
|
||||||
|
|
||||||
#include <sys/stat.h>
|
#include <sys/stat.h>
|
||||||
#include <sys/wait.h>
|
#include <sys/wait.h>
|
||||||
#include <fcntl.h>
|
|
||||||
|
|
||||||
#include <sys/types.h>
|
#include <sys/types.h>
|
||||||
#include <pwd.h>
|
#include <fcntl.h>
|
||||||
#include <grp.h>
|
|
||||||
|
|
||||||
#include "util.hh"
|
#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
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -249,10 +249,6 @@ string int2String(int n);
|
||||||
bool string2Int(const string & s, int & n);
|
bool string2Int(const string & s, int & n);
|
||||||
|
|
||||||
|
|
||||||
/* Setuid support. */
|
|
||||||
void switchToNixUser();
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue