From 34d372d2c31d1b1decb2528446a075287067336b Mon Sep 17 00:00:00 2001 From: Jan Steemann Date: Thu, 13 Aug 2015 14:25:33 +0200 Subject: [PATCH] lower privileges earlier on startup --- CHANGELOG | 17 ++ lib/ApplicationServer/ApplicationServer.cpp | 249 +++++++------------- lib/ApplicationServer/ApplicationServer.h | 46 +--- 3 files changed, 104 insertions(+), 208 deletions(-) diff --git a/CHANGELOG b/CHANGELOG index 7abacc47cd..d32554e61b 100644 --- a/CHANGELOG +++ b/CHANGELOG @@ -1,6 +1,23 @@ v2.7.0 (XXXX-XX-XX) ------------------- +* IMPORTANT CHANGE: when starting arangod, the server will drop the process + privileges to the specified values in options `--server.uid` and `--server.gid` + instantly after parsing the startup options. + + That means when either `--server.uid` or `--server.gid` are set, the privilege + change may happen earlier at startup. This may prevent binding the server to + and endpoint with a port number lower than 1024, if the user has no privileges + for that. Previous versions of ArangoDB changed the privileges later, so some + startup actions were still carried out under the invoking user (i.e. likely + *root* when started via init.d or system scripts) and especially binding to + low ports was still possible there. + + The default privileges for user *arangodb* will not be sufficient for binding + to port numbers lower than 1024. To have an ArangoDB 2.7 bind to a port number + lower than 1024, it needs to be started with either a different privileged user, + or the privileges of the *arangodb* user have to raised manually beforehand. + * added AQL optimizer rule `patch-update-statements` * Linux startup scripts and systemd configuration for arangod now try to diff --git a/lib/ApplicationServer/ApplicationServer.cpp b/lib/ApplicationServer/ApplicationServer.cpp index b210a4ea41..9d55a1e82b 100644 --- a/lib/ApplicationServer/ApplicationServer.cpp +++ b/lib/ApplicationServer/ApplicationServer.cpp @@ -100,11 +100,9 @@ ApplicationServer::ApplicationServer (std::string const& name, std::string const _userConfigFile(), _systemConfigFile(), _uid(), - _realUid(0), - _effectiveUid(0), + _numericUid(0), _gid(), - _realGid(0), - _effectiveGid(0), + _numericGid(0), _logApplicationName("arangod"), _logFacility(""), _logLevel("info"), @@ -123,9 +121,6 @@ ApplicationServer::ApplicationServer (std::string const& name, std::string const _randomGenerator(3), #endif _finishedCondition() { -#ifndef _WIN32 - storeRealPrivileges(); -#endif } //////////////////////////////////////////////////////////////////////////////// @@ -422,7 +417,7 @@ bool ApplicationServer::parse (int argc, // ............................................................................. extractPrivileges(); - dropPrivileges(); + dropPrivilegesPermanently(); // ............................................................................. // setup logging @@ -538,8 +533,6 @@ void ApplicationServer::start () { pthread_sigmask(SIG_SETMASK, &all, 0); #endif - raisePrivileges(); - // start all startable features for (vector::iterator i = _features.begin(); i != _features.end(); ++i) { ApplicationFeature* feature = *i; @@ -567,8 +560,6 @@ void ApplicationServer::start () { LOG_TRACE("opened server feature '%s'", feature->getName().c_str()); } - - dropPrivilegesPermanently(); } //////////////////////////////////////////////////////////////////////////////// @@ -630,66 +621,85 @@ void ApplicationServer::stop () { } //////////////////////////////////////////////////////////////////////////////// -/// @brief raise the privileges +/// @brief extract the privileges to use //////////////////////////////////////////////////////////////////////////////// -void ApplicationServer::raisePrivileges () { +void ApplicationServer::extractPrivileges() { - // first UID -#ifdef TRI_HAVE_SETUID - - if (_effectiveUid != _realUid) { - int res = seteuid(_realUid); - - if (res != 0) { - LOG_FATAL_AND_EXIT("cannot set uid '%s': %s", _uid.c_str(), strerror(errno)); - } - } - -#endif - - // then GID (because we are raising) #ifdef TRI_HAVE_SETGID - if (_effectiveGid != _realGid) { - int res = setegid(_realGid); - - if (res != 0) { - LOG_FATAL_AND_EXIT("cannot set gid %d: %s", (int) _effectiveGid, strerror(errno)); - } + if (_gid.empty()) { + _numericGid = getgid(); } + else { + int gidNumber = TRI_Int32String(_gid.c_str()); + if (TRI_errno() == TRI_ERROR_NO_ERROR && gidNumber >= 0) { + +#ifdef TRI_HAVE_GETGRGID + group* g = getgrgid(gidNumber); + + if (g == 0) { + LOG_FATAL_AND_EXIT("unknown numeric gid '%s'", _gid.c_str()); + } #endif -} - -//////////////////////////////////////////////////////////////////////////////// -/// @brief drops the privileges -//////////////////////////////////////////////////////////////////////////////// - -void ApplicationServer::dropPrivileges () { - - // first GID -#ifdef TRI_HAVE_SETGID - - if (_effectiveGid != _realGid) { - int res = setegid(_effectiveGid); - - if (res != 0) { - LOG_FATAL_AND_EXIT("cannot set gid %d: %s", (int) _effectiveGid, strerror(errno)); } + else { +#ifdef TRI_HAVE_GETGRNAM + string name = _gid; + group* g = getgrnam(name.c_str()); + + if (g != 0) { + gidNumber = g->gr_gid; + } + else { + LOG_FATAL_AND_EXIT("cannot convert groupname '%s' to numeric gid", _gid.c_str()); + } +#else + LOG_FATAL_AND_EXIT("cannot convert groupname '%s' to numeric gid", _gid.c_str()); +#endif + } + + _numericGid = gidNumber; } #endif - // then UID (because we are dropping) #ifdef TRI_HAVE_SETUID - if (_effectiveUid != _realUid) { - int res = seteuid(_effectiveUid); + if (_uid.empty()) { + _numericUid = getuid(); + } + else { + int uidNumber = TRI_Int32String(_uid.c_str()); - if (res != 0) { - LOG_FATAL_AND_EXIT("cannot set uid %s: %s", _uid.c_str(), strerror(errno)); + if (TRI_errno() == TRI_ERROR_NO_ERROR) { + +#ifdef TRI_HAVE_GETPWUID + passwd* p = getpwuid(uidNumber); + + if (p == 0) { + LOG_FATAL_AND_EXIT("unknown numeric uid '%s'", _uid.c_str()); + } +#endif } + else { +#ifdef TRI_HAVE_GETPWNAM + string name = _uid; + passwd* p = getpwnam(name.c_str()); + + if (p != 0) { + uidNumber = p->pw_uid; + } + else { + LOG_FATAL_AND_EXIT("cannot convert username '%s' to numeric uid", _uid.c_str()); + } +#else + LOG_FATAL_AND_EXIT("cannot convert username '%s' to numeric uid", _uid.c_str()); +#endif + } + + _numericUid = uidNumber; } #endif @@ -700,32 +710,32 @@ void ApplicationServer::dropPrivileges () { //////////////////////////////////////////////////////////////////////////////// void ApplicationServer::dropPrivilegesPermanently () { - raisePrivileges(); - + // clear all supplementary groups #if defined(TRI_HAVE_INITGROUPS) && defined(TRI_HAVE_SETGID) && defined(TRI_HAVE_SETUID) - struct passwd* pwent = getpwuid(_effectiveUid); + if (! _gid.empty() && ! _uid.empty()) { + struct passwd* pwent = getpwuid(_numericUid); - if (pwent != nullptr) { - initgroups(pwent->pw_name, _effectiveGid); + if (pwent != nullptr) { + initgroups(pwent->pw_name, _numericGid); + } } #endif + // first GID #ifdef TRI_HAVE_SETGID - if (_effectiveGid != _realGid) { - LOG_INFO("permanently changing the gid to %d", (int) _effectiveGid); + if (! _gid.empty()) { + LOG_INFO("permanently changing the gid to %d", (int) _numericGid); - int res = setgid(_effectiveGid); + int res = setgid(_numericGid); if (res != 0) { - LOG_FATAL_AND_EXIT("cannot set gid %d: %s", (int) _effectiveGid, strerror(errno)); + LOG_FATAL_AND_EXIT("cannot set gid %d: %s", (int) _numericGid, strerror(errno)); } - - _realGid = _effectiveGid; } #endif @@ -733,35 +743,19 @@ void ApplicationServer::dropPrivilegesPermanently () { // then UID (because we are dropping) #ifdef TRI_HAVE_SETUID - if (_effectiveUid != _realUid) { - LOG_INFO("permanently changing the uid to %d", (int) _effectiveUid); + if (! _uid.empty()) { + LOG_INFO("permanently changing the uid to %d", (int) _numericUid); - int res = setuid(_effectiveUid); + int res = setuid(_numericUid); if (res != 0) { LOG_FATAL_AND_EXIT("cannot set uid '%s': %s", _uid.c_str(), strerror(errno)); } - - _realUid = _effectiveUid; } #endif } -//////////////////////////////////////////////////////////////////////////////// -/// @brief saves the logging privileges -//////////////////////////////////////////////////////////////////////////////// - -void ApplicationServer::storeRealPrivileges () { -#ifdef TRI_HAVE_SETGID - _realGid = getgid(); -#endif - -#ifdef TRI_HAVE_SETUID - _realUid = getuid(); -#endif -} - // ----------------------------------------------------------------------------- // --SECTION-- protected methods // ----------------------------------------------------------------------------- @@ -1023,91 +1017,6 @@ bool ApplicationServer::readConfigurationFile () { return true; } -//////////////////////////////////////////////////////////////////////////////// -/// @brief extract the privileges to use -//////////////////////////////////////////////////////////////////////////////// - -void ApplicationServer::extractPrivileges() { - -#ifdef TRI_HAVE_SETGID - - if (_gid.empty()) { - _effectiveGid = getgid(); - } - else { - int gidNumber = TRI_Int32String(_gid.c_str()); - - if (TRI_errno() == TRI_ERROR_NO_ERROR && gidNumber >= 0) { - -#ifdef TRI_HAVE_GETGRGID - group* g = getgrgid(gidNumber); - - if (g == 0) { - LOG_FATAL_AND_EXIT("unknown numeric gid '%s'", _gid.c_str()); - } -#endif - } - else { -#ifdef TRI_HAVE_GETGRNAM - string name = _gid; - group* g = getgrnam(name.c_str()); - - if (g != 0) { - gidNumber = g->gr_gid; - } - else { - LOG_FATAL_AND_EXIT("cannot convert groupname '%s' to numeric gid", _gid.c_str()); - } -#else - LOG_FATAL_AND_EXIT("cannot convert groupname '%s' to numeric gid", _gid.c_str()); -#endif - } - - _effectiveGid = gidNumber; - } - -#endif - -#ifdef TRI_HAVE_SETUID - - if (_uid.empty()) { - _effectiveUid = getuid(); - } - else { - int uidNumber = TRI_Int32String(_uid.c_str()); - - if (TRI_errno() == TRI_ERROR_NO_ERROR) { - -#ifdef TRI_HAVE_GETPWUID - passwd* p = getpwuid(uidNumber); - - if (p == 0) { - LOG_FATAL_AND_EXIT("unknown numeric uid '%s'", _uid.c_str()); - } -#endif - } - else { -#ifdef TRI_HAVE_GETPWNAM - string name = _uid; - passwd* p = getpwnam(name.c_str()); - - if (p != 0) { - uidNumber = p->pw_uid; - } - else { - LOG_FATAL_AND_EXIT("cannot convert username '%s' to numeric uid", _uid.c_str()); - } -#else - LOG_FATAL_AND_EXIT("cannot convert username '%s' to numeric uid", _uid.c_str()); -#endif - } - - _effectiveUid = uidNumber; - } - -#endif -} - // ----------------------------------------------------------------------------- // --SECTION-- END-OF-FILE // ----------------------------------------------------------------------------- diff --git a/lib/ApplicationServer/ApplicationServer.h b/lib/ApplicationServer/ApplicationServer.h index 8e14ff633f..782f1b5b38 100644 --- a/lib/ApplicationServer/ApplicationServer.h +++ b/lib/ApplicationServer/ApplicationServer.h @@ -174,16 +174,10 @@ namespace triagens { void stop (); //////////////////////////////////////////////////////////////////////////////// -/// @brief raises the privileges +/// @brief extracts the privileges from the command-line //////////////////////////////////////////////////////////////////////////////// - void raisePrivileges (); - -//////////////////////////////////////////////////////////////////////////////// -/// @brief drops the privileges -//////////////////////////////////////////////////////////////////////////////// - - void dropPrivileges (); + void extractPrivileges (); //////////////////////////////////////////////////////////////////////////////// /// @brief drops the privileges permanently @@ -221,18 +215,6 @@ namespace triagens { bool readConfigurationFile (); -//////////////////////////////////////////////////////////////////////////////// -/// @brief extracts the real privileges -//////////////////////////////////////////////////////////////////////////////// - - void storeRealPrivileges (); - -//////////////////////////////////////////////////////////////////////////////// -/// @brief extracts the privileges from the command-line -//////////////////////////////////////////////////////////////////////////////// - - void extractPrivileges (); - // ----------------------------------------------------------------------------- // --SECTION-- private variables // ----------------------------------------------------------------------------- @@ -432,16 +414,10 @@ namespace triagens { std::string _uid; //////////////////////////////////////////////////////////////////////////////// -/// @brief real uid +/// @brief numeric uid //////////////////////////////////////////////////////////////////////////////// - TRI_uid_t _realUid; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief effective uid -//////////////////////////////////////////////////////////////////////////////// - - TRI_uid_t _effectiveUid; + TRI_uid_t _numericUid; //////////////////////////////////////////////////////////////////////////////// /// @brief the group id to use for the process @@ -461,18 +437,12 @@ namespace triagens { //////////////////////////////////////////////////////////////////////////////// std::string _gid; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief real gid + +///////////////////////////////////////////////////////////////////////////////// +/// @brief numeric gid //////////////////////////////////////////////////////////////////////////////// - TRI_gid_t _realGid; - -//////////////////////////////////////////////////////////////////////////////// -/// @brief effective gid -//////////////////////////////////////////////////////////////////////////////// - - TRI_gid_t _effectiveGid; + TRI_gid_t _numericGid; //////////////////////////////////////////////////////////////////////////////// /// @brief log application name