forked from lix-project/lix
* Move setuid stuff to libutil.
* Install libexpr header files.
This commit is contained in:
parent
e5a6c09b12
commit
bafc1690fc
|
@ -1,11 +1,12 @@
|
||||||
pkglib_LTLIBRARIES = libexpr.la
|
pkglib_LTLIBRARIES = libexpr.la
|
||||||
|
|
||||||
libexpr_la_SOURCES = nixexpr.cc nixexpr.hh \
|
libexpr_la_SOURCES = \
|
||||||
eval.cc eval.hh primops.cc \
|
nixexpr.cc eval.cc primops.cc lexer-tab.cc parser-tab.cc \
|
||||||
lexer-tab.cc lexer-tab.hh parser-tab.cc parser-tab.hh \
|
get-drvs.cc attr-path.cc expr-to-xml.cc
|
||||||
get-drvs.cc get-drvs.hh \
|
|
||||||
attr-path.cc attr-path.hh \
|
pkginclude_HEADERS = \
|
||||||
expr-to-xml.cc expr-to-xml.hh
|
nixexpr.hh eval.hh parser.hh lexer-tab.hh parser-tab.hh \
|
||||||
|
get-drvs.hh attr-path.hh expr-to-xml.hh
|
||||||
|
|
||||||
libexpr_la_LIBADD = ../libutil/libutil.la ../libstore/libstore.la \
|
libexpr_la_LIBADD = ../libutil/libutil.la ../libstore/libstore.la \
|
||||||
../boost/format/libformat.la
|
../boost/format/libformat.la
|
||||||
|
|
|
@ -207,139 +207,6 @@ static void initAndRun(int argc, char * * argv)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
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
|
|
||||||
|
|
||||||
|
|
||||||
SwitchToOriginalUser::SwitchToOriginalUser()
|
|
||||||
{
|
|
||||||
#if SETUID_HACK && HAVE_SETRESUID
|
|
||||||
/* Temporarily switch the effective uid/gid back to the saved
|
|
||||||
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
|
|
||||||
the Nix user in switchToNixUser()). */
|
|
||||||
if (haveSwitched) {
|
|
||||||
if (setuid(savedUid) == -1)
|
|
||||||
throw SysError(format("temporarily restoring uid to `%1%'") % savedUid);
|
|
||||||
if (setgid(savedGid) == -1)
|
|
||||||
throw SysError(format("temporarily restoring gid to `%1%'") % savedGid);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
SwitchToOriginalUser::~SwitchToOriginalUser()
|
|
||||||
{
|
|
||||||
#if SETUID_HACK && HAVE_SETRESUID
|
|
||||||
/* Switch the effective uid/gid back to the Nix user. */
|
|
||||||
if (haveSwitched) {
|
|
||||||
if (setuid(nixUid) == -1)
|
|
||||||
throw SysError(format("restoring uid to `%1%'") % nixUid);
|
|
||||||
if (setgid(nixGid) == -1)
|
|
||||||
throw SysError(format("restoring gid to `%1%'") % nixGid);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void switchToNixUser()
|
|
||||||
{
|
|
||||||
#if SETUID_HACK
|
|
||||||
|
|
||||||
/* 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. Otherwise we just drop all privileges. */
|
|
||||||
|
|
||||||
/* Lookup the Nix gid. */
|
|
||||||
struct group * gr = getgrnam(NIX_GROUP);
|
|
||||||
if (!gr) {
|
|
||||||
cerr << format("missing group `%1%'\n") % NIX_GROUP;
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Get the supplementary group IDs for the current user. */
|
|
||||||
int maxGids = 512, nrGids;
|
|
||||||
gid_t gids[maxGids];
|
|
||||||
if ((nrGids = getgroups(maxGids, gids)) == -1) {
|
|
||||||
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] == gr->gr_gid) {
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!found) {
|
|
||||||
/* Not in the Nix group - drop all root/Nix privileges. */
|
|
||||||
_setgid(getgid());
|
|
||||||
_setuid(getuid());
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
savedUid = getuid();
|
|
||||||
savedGid = getgid();
|
|
||||||
|
|
||||||
/* Set the real, effective and saved gids to gr->gr_gid. Also
|
|
||||||
make very sure that this succeeded. We switch the gid first
|
|
||||||
because we cannot do it after we have dropped root uid. */
|
|
||||||
nixGid = gr->gr_gid;
|
|
||||||
if (_setgid(nixGid) != 0 || getgid() != nixGid || getegid() != nixGid) {
|
|
||||||
cerr << format("unable to set gid to `%1%'\n") % NIX_GROUP;
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Lookup the Nix uid. */
|
|
||||||
struct passwd * pw = getpwnam(NIX_USER);
|
|
||||||
if (!pw) {
|
|
||||||
cerr << format("missing user `%1%'\n") % NIX_USER;
|
|
||||||
exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* This will drop all root privileges, setting the real, effective
|
|
||||||
and saved uids to pw->pw_uid. Also make very sure that this
|
|
||||||
succeeded.*/
|
|
||||||
nixUid = pw->pw_uid;
|
|
||||||
if (_setuid(nixUid) != 0 || getuid() != nixUid || geteuid() != nixUid) {
|
|
||||||
cerr << format("unable to set uid to `%1%'\n") % NIX_USER;
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -850,4 +850,140 @@ 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
|
||||||
|
|
||||||
|
|
||||||
|
SwitchToOriginalUser::SwitchToOriginalUser()
|
||||||
|
{
|
||||||
|
#if SETUID_HACK && HAVE_SETRESUID
|
||||||
|
/* Temporarily switch the effective uid/gid back to the saved
|
||||||
|
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
|
||||||
|
the Nix user in switchToNixUser()). */
|
||||||
|
if (haveSwitched) {
|
||||||
|
if (setuid(savedUid) == -1)
|
||||||
|
throw SysError(format("temporarily restoring uid to `%1%'") % savedUid);
|
||||||
|
if (setgid(savedGid) == -1)
|
||||||
|
throw SysError(format("temporarily restoring gid to `%1%'") % savedGid);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
SwitchToOriginalUser::~SwitchToOriginalUser()
|
||||||
|
{
|
||||||
|
#if SETUID_HACK && HAVE_SETRESUID
|
||||||
|
/* Switch the effective uid/gid back to the Nix user. */
|
||||||
|
if (haveSwitched) {
|
||||||
|
if (setuid(nixUid) == -1)
|
||||||
|
throw SysError(format("restoring uid to `%1%'") % nixUid);
|
||||||
|
if (setgid(nixGid) == -1)
|
||||||
|
throw SysError(format("restoring gid to `%1%'") % nixGid);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void switchToNixUser()
|
||||||
|
{
|
||||||
|
#if SETUID_HACK
|
||||||
|
|
||||||
|
/* 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. Otherwise we just drop all privileges. */
|
||||||
|
|
||||||
|
/* Lookup the Nix gid. */
|
||||||
|
struct group * gr = getgrnam(NIX_GROUP);
|
||||||
|
if (!gr) {
|
||||||
|
cerr << format("missing group `%1%'\n") % NIX_GROUP;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Get the supplementary group IDs for the current user. */
|
||||||
|
int maxGids = 512, nrGids;
|
||||||
|
gid_t gids[maxGids];
|
||||||
|
if ((nrGids = getgroups(maxGids, gids)) == -1) {
|
||||||
|
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] == gr->gr_gid) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!found) {
|
||||||
|
/* Not in the Nix group - drop all root/Nix privileges. */
|
||||||
|
_setgid(getgid());
|
||||||
|
_setuid(getuid());
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
savedUid = getuid();
|
||||||
|
savedGid = getgid();
|
||||||
|
|
||||||
|
/* Set the real, effective and saved gids to gr->gr_gid. Also
|
||||||
|
make very sure that this succeeded. We switch the gid first
|
||||||
|
because we cannot do it after we have dropped root uid. */
|
||||||
|
nixGid = gr->gr_gid;
|
||||||
|
if (_setgid(nixGid) != 0 || getgid() != nixGid || getegid() != nixGid) {
|
||||||
|
cerr << format("unable to set gid to `%1%'\n") % NIX_GROUP;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Lookup the Nix uid. */
|
||||||
|
struct passwd * pw = getpwnam(NIX_USER);
|
||||||
|
if (!pw) {
|
||||||
|
cerr << format("missing user `%1%'\n") % NIX_USER;
|
||||||
|
exit(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This will drop all root privileges, setting the real, effective
|
||||||
|
and saved uids to pw->pw_uid. Also make very sure that this
|
||||||
|
succeeded.*/
|
||||||
|
nixUid = pw->pw_uid;
|
||||||
|
if (_setuid(nixUid) != 0 || getuid() != nixUid || geteuid() != nixUid) {
|
||||||
|
cerr << format("unable to set uid to `%1%'\n") % NIX_USER;
|
||||||
|
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
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -246,15 +246,15 @@ string int2String(int n);
|
||||||
bool string2Int(const string & s, int & n);
|
bool string2Int(const string & s, int & n);
|
||||||
|
|
||||||
|
|
||||||
/* !!! HACK HACK HACK - this should be in shared.hh, but it's to
|
/* Setuid support. */
|
||||||
facilitate a quick hack - will remove this eventually (famous last
|
|
||||||
words). */
|
|
||||||
struct SwitchToOriginalUser
|
struct SwitchToOriginalUser
|
||||||
{
|
{
|
||||||
SwitchToOriginalUser();
|
SwitchToOriginalUser();
|
||||||
~SwitchToOriginalUser();
|
~SwitchToOriginalUser();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void switchToNixUser();
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue