From bafc1690fc4a2a2c3ff81ff1c1a677f208d3b1b7 Mon Sep 17 00:00:00 2001 From: Eelco Dolstra Date: Mon, 4 Sep 2006 22:55:28 +0000 Subject: [PATCH] * Move setuid stuff to libutil. * Install libexpr header files. --- src/libexpr/Makefile.am | 13 ++-- src/libmain/shared.cc | 133 --------------------------------------- src/libutil/util.cc | 136 ++++++++++++++++++++++++++++++++++++++++ src/libutil/util.hh | 6 +- 4 files changed, 146 insertions(+), 142 deletions(-) diff --git a/src/libexpr/Makefile.am b/src/libexpr/Makefile.am index 01a2a2f12..3d255d6bb 100644 --- a/src/libexpr/Makefile.am +++ b/src/libexpr/Makefile.am @@ -1,11 +1,12 @@ pkglib_LTLIBRARIES = libexpr.la -libexpr_la_SOURCES = nixexpr.cc nixexpr.hh \ - eval.cc eval.hh primops.cc \ - lexer-tab.cc lexer-tab.hh parser-tab.cc parser-tab.hh \ - get-drvs.cc get-drvs.hh \ - attr-path.cc attr-path.hh \ - expr-to-xml.cc expr-to-xml.hh +libexpr_la_SOURCES = \ + nixexpr.cc eval.cc primops.cc lexer-tab.cc parser-tab.cc \ + get-drvs.cc attr-path.cc expr-to-xml.cc + +pkginclude_HEADERS = \ + 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 \ ../boost/format/libformat.la diff --git a/src/libmain/shared.cc b/src/libmain/shared.cc index c153a6faf..3064299c8 100644 --- a/src/libmain/shared.cc +++ b/src/libmain/shared.cc @@ -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 -} - - } diff --git a/src/libutil/util.cc b/src/libutil/util.cc index 44b39f8c6..eac124edb 100644 --- a/src/libutil/util.cc +++ b/src/libutil/util.cc @@ -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 +} + + } diff --git a/src/libutil/util.hh b/src/libutil/util.hh index b4a61ae04..52ef2c6eb 100644 --- a/src/libutil/util.hh +++ b/src/libutil/util.hh @@ -246,15 +246,15 @@ string int2String(int n); bool string2Int(const string & s, int & n); -/* !!! HACK HACK HACK - this should be in shared.hh, but it's to - facilitate a quick hack - will remove this eventually (famous last - words). */ +/* Setuid support. */ struct SwitchToOriginalUser { SwitchToOriginalUser(); ~SwitchToOriginalUser(); }; +void switchToNixUser(); + }