diff options
Diffstat (limited to 'paludis')
-rw-r--r-- | paludis/repositories/accounts/installed_accounts_id.cc | 40 | ||||
-rw-r--r-- | paludis/util/files.m4 | 1 | ||||
-rw-r--r-- | paludis/util/persona.cc | 127 | ||||
-rw-r--r-- | paludis/util/persona.hh | 43 | ||||
-rw-r--r-- | paludis/util/process.cc | 14 |
5 files changed, 190 insertions, 35 deletions
diff --git a/paludis/repositories/accounts/installed_accounts_id.cc b/paludis/repositories/accounts/installed_accounts_id.cc index a69b26add..ccc876cf4 100644 --- a/paludis/repositories/accounts/installed_accounts_id.cc +++ b/paludis/repositories/accounts/installed_accounts_id.cc @@ -22,6 +22,7 @@ #include <paludis/util/pimp-impl.hh> #include <paludis/util/config_file.hh> #include <paludis/util/options.hh> +#include <paludis/util/persona.hh> #include <paludis/util/stringify.hh> #include <paludis/util/hashes.hh> #include <paludis/util/visitor_cast.hh> @@ -117,44 +118,29 @@ InstalledAccountsID::need_keys_added() const /* depend upon our primary group */ { - int pwd_buf_sz(sysconf(_SC_GETPW_R_SIZE_MAX)); - if (-1 == pwd_buf_sz || pwd_buf_sz > 1024 * 128) - { - Log::get_instance()->message("accounts.getpw_r_size_max", ll_warning, lc_context) << - "Got dodgy value " << pwd_buf_sz << " from sysconf(_SC_GETPW_R_SIZE_MAX)"; - pwd_buf_sz = 1024 * 128; - } - std::vector<char> pwd_buf(pwd_buf_sz); - struct passwd pwd; - struct passwd * pwd_result; + struct passwd *result; + std::vector<char> buffer; - if (0 == getpwnam_r(stringify(name().package()).c_str(), &pwd, &pwd_buf[0], pwd_buf_sz, &pwd_result)) + if (0 == getpwnam_r_s(stringify(name().package()).c_str(), buffer, pwd, result) || result == nullptr) { - int grp_buf_sz(sysconf(_SC_GETGR_R_SIZE_MAX)); - if (-1 == grp_buf_sz || grp_buf_sz > 1024 * 128) - { - Log::get_instance()->message("accounts.getgr_r_size_max", ll_warning, lc_context) << - "Got dodgy value " << grp_buf_sz << " from sysconf(_SC_GETPW_R_SIZE_MAX)"; - grp_buf_sz = 1024 * 128; - } - std::vector<char> grp_buf(grp_buf_sz); - struct group grp; - struct group * grp_result; - if (0 == getgrgid_r(pwd.pw_gid, &grp, &grp_buf[0], grp_buf_sz, &grp_result) && nullptr != grp_result) + struct group *result; + std::vector<char> buffer; + + if (0 == getgrgid_r_s(pwd.pw_gid, buffer, grp, result) && nullptr != result) { - /* really we should only do this if the group in question is managed by accounts. users + /* really we should only do this if the group in question is managed by accounts. Users * might have accounts installed by hand with a group that's unmanaged. */ groups->insert(stringify(grp.gr_name)); } else - Log::get_instance()->message("accounts.getgrgid_r", ll_warning, lc_context) << - "getgrgid_r failed for " << name(); + Log::get_instance()->message("accounts.getgrgid_r", ll_warning, lc_context) + << "getgrgid_r failed for " << name(); } else - Log::get_instance()->message("accounts.getpwnam_r", ll_warning, lc_context) << - "getpwnam_r failed for " << name(); + Log::get_instance()->message("accounts.getpwnam_r", ll_warning, lc_context) + << "getpwnam_r failed for " << name(); } /* ...and our secondary groups */ diff --git a/paludis/util/files.m4 b/paludis/util/files.m4 index e2f304c52..dadcfcab3 100644 --- a/paludis/util/files.m4 +++ b/paludis/util/files.m4 @@ -55,6 +55,7 @@ add(`named_value', `hh', `cc', `fwd') add(`no_type', `hh') add(`operators', `hh') add(`options', `hh', `fwd', `cc', `gtest') +add(`persona', `hh', `cc') add(`pimp', `hh', `impl') add(`pipe', `hh', `cc') add(`pool', `hh', `cc', `impl', `gtest', `fwd') diff --git a/paludis/util/persona.cc b/paludis/util/persona.cc new file mode 100644 index 000000000..817ea960b --- /dev/null +++ b/paludis/util/persona.cc @@ -0,0 +1,127 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2016 Saleem Abdulrasool + * + * This file is part of the Paludis package manager. Paludis is free software; + * you can redistribute it and/or modify it under the terms of the GNU General + * Public License version 2, as published by the Free Software Foundation. + * + * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#include <paludis/util/persona.hh> + +#include <paludis/util/log.hh> + +#include <stdlib.h> +#include <unistd.h> + +#include <sys/types.h> + +namespace +{ + template <unsigned Name> + struct SystemConfigurationParameter; + + template <> + struct SystemConfigurationParameter<_SC_GETPW_R_SIZE_MAX> { + static constexpr const char * const Spelling = "_SC_GETPW_R_SIZE_MAX"; + }; + + template <> + struct SystemConfigurationParameter<_SC_GETGR_R_SIZE_MAX> { + static constexpr const char * const Spelling = "_SC_GETGR_R_SIZE_MAX"; + }; + + template <unsigned Name, size_t DefaultSize = 1024, long DodgyLimit = 1024 * 128> + size_t initial_buffer_size(const char *context) + { + using namespace paludis; + + long size; + + errno = 0; + size = ::sysconf(Name); + if (size == -1 && errno == 0) + return DefaultSize; + + if (size > DodgyLimit) + Log::get_instance()->message(context, ll_warning, lc_context) + << "Got dodgy value " << size << " from " + << "sysconf(" << SystemConfigurationParameter<Name>::Spelling << ")"; + + return std::min(size, DodgyLimit); + } +} + +namespace paludis +{ + int getpwnam_r_s(const char *name, std::vector<char> & buffer, + struct passwd & pwd, struct passwd * & result) + { + size_t length; + int rv; + + buffer.clear(); + + length = + initial_buffer_size<_SC_GETPW_R_SIZE_MAX>("accounts.getpw_r_size"); + + for (buffer.reserve(length); + (rv = ::getpwnam_r(name, &pwd, buffer.data(), buffer.capacity(), + &result)) == ERANGE; + buffer.reserve(length)) + length = length * 2; + + return rv; + } + + int getgrgid_r_s(gid_t gid, std::vector<char> & buffer, + struct group & grp, struct group * & result) + { + size_t length; + int rv; + + buffer.clear(); + + length = + initial_buffer_size<_SC_GETGR_R_SIZE_MAX>("accounts.getgr_r_size"); + + for (buffer.reserve(length); + (rv = ::getgrgid_r(gid, &grp, buffer.data(), buffer.capacity(), + &result)) == ERANGE; + buffer.reserve(length)) + length = length * 2; + + return rv; + } + + int getpwuid_r_s(uid_t uid, std::vector<char> & buffer, + struct passwd & pwd, struct passwd * & result) + { + size_t length; + int rv; + + buffer.clear(); + + length = + initial_buffer_size<_SC_GETPW_R_SIZE_MAX>("accounts.getpw_r_size"); + + for (buffer.reserve(length); + (rv = ::getpwuid_r(uid, &pwd, buffer.data(), buffer.capacity(), + &result)) == ERANGE; + buffer.reserve(length)) + length = length * 2; + + return rv; + } +} + diff --git a/paludis/util/persona.hh b/paludis/util/persona.hh new file mode 100644 index 000000000..de20216cd --- /dev/null +++ b/paludis/util/persona.hh @@ -0,0 +1,43 @@ +/* vim: set sw=4 sts=4 et foldmethod=syntax : */ + +/* + * Copyright (c) 2016 Saleem Abdulrasool + * + * This file is part of the Paludis package manager. Paludis is free software; + * you can redistribute it and/or modify it under the terms of the GNU General + * Public License version 2, as published by the Free Software Foundation. + * + * Paludis is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS + * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more + * details. + * + * You should have received a copy of the GNU General Public License along with + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple + * Place, Suite 330, Boston, MA 02111-1307 USA + */ + +#ifndef PALUDIS_GUARD_PALUDIS_UTIL_PERSONA_H +#define PALUDIS_GUARD_PALUDIS_UTIL_PERSONA_H + +#include <paludis/util/attributes.hh> + +#include <vector> + +#include <grp.h> +#include <pwd.h> + +namespace paludis +{ + int getpwnam_r_s(const char * name, std::vector<char> & buffer, + struct passwd & pwd, + struct passwd * & result) PALUDIS_VISIBLE; + + int getgrgid_r_s(gid_t gid, std::vector<char> & buffer, struct group & grp, + struct group * & result) PALUDIS_VISIBLE; + + int getpwuid_r_s(uid_t uid, std::vector<char> & buffer, struct passwd & pwd, + struct passwd * & result) PALUDIS_VISIBLE; +} + +#endif diff --git a/paludis/util/process.cc b/paludis/util/process.cc index b4b553db1..380d671d6 100644 --- a/paludis/util/process.cc +++ b/paludis/util/process.cc @@ -17,6 +17,7 @@ * Place, Suite 330, Boston, MA 02111-1307 USA */ +#include <paludis/util/persona.hh> #include <paludis/util/process.hh> #include <paludis/util/pimp-impl.hh> #include <paludis/util/pipe.hh> @@ -806,17 +807,14 @@ Process::run() if (0 != ::setgid(_imp->setgid)) throw ProcessError("setgid() failed"); - int buflen(::sysconf(_SC_GETPW_R_SIZE_MAX)); - if (-1 == buflen) - buflen = 1 << 16; + struct passwd pwd; + struct passwd *result; + std::vector<char> buffer; - std::unique_ptr<char []> buf(new char[buflen]); - struct passwd pw; - struct passwd * pw_result(nullptr); - if (0 != getpwuid_r(_imp->setuid, &pw, buf.get(), buflen, &pw_result) || nullptr == pw_result) + if (0 != getpwuid_r_s(_imp->setuid, buffer, pwd, result) || result == nullptr) throw ProcessError("getpwuid_r() failed"); - if (0 != ::initgroups(pw_result->pw_name, getgid())) + if (0 != ::initgroups(pwd.pw_name, getgid())) throw ProcessError("initgroups() failed"); if (0 != ::setuid(_imp->setuid)) |