diff options
author | Roger Leigh <rleigh@debian.org> | 2009-09-27 22:52:44 +0100 |
---|---|---|
committer | Roger Leigh <rleigh@debian.org> | 2009-09-27 22:54:57 +0100 |
commit | 11ea9932e8d90e4e0681f3062f26b494842e675d (patch) | |
tree | 6802941901a37d93cce059b2e5256b5ad001ba22 | |
parent | 6fe0df0c4cb22e81e3850384fd3b208b8848bbe7 (diff) | |
download | schroot-11ea9932e8d90e4e0681f3062f26b494842e675d.tar.gz |
sbuild: Add reentrant passwd and group wrappers
In order to make the library thread-safe, use the reentrant
getpw*_r and getgr*_r functions in place of the older unsafe
functions which use static buffers. The passwd and group
structures are inherited by C++ classes of the same name which
allow handling of dynamic memory allocation while at the same
time allowing use of RAII and passing to C functions.
-rw-r--r-- | TODO | 4 | ||||
-rw-r--r-- | sbuild/sbuild-auth.cc | 25 | ||||
-rw-r--r-- | sbuild/sbuild-session.cc | 14 | ||||
-rw-r--r-- | sbuild/sbuild-util.cc | 221 | ||||
-rw-r--r-- | sbuild/sbuild-util.h | 75 |
5 files changed, 316 insertions, 23 deletions
@@ -28,10 +28,6 @@ and test for particular permissions. POTENTIAL --------- -* Use of passwd/group databases should be thread-safe - - - Use the _r variants of getpw*, getgr*. - * Add tests for ** Auth diff --git a/sbuild/sbuild-auth.cc b/sbuild/sbuild-auth.cc index 165a8349..346cc717 100644 --- a/sbuild/sbuild-auth.cc +++ b/sbuild/sbuild-auth.cc @@ -19,6 +19,7 @@ #include <config.h> #include "sbuild-auth.h" +#include "sbuild-util.h" #include <cassert> #include <cerrno> @@ -84,25 +85,25 @@ auth::auth (std::string const& service_name): { this->ruid = getuid(); this->rgid = getgid(); - struct passwd *pwent = getpwuid(this->ruid); - if (pwent == 0) + passwd pwent(this->ruid); + if (!pwent) { if (errno) throw error(this->ruid, USER, strerror(errno)); else throw error(this->ruid, USER); } - this->ruser = pwent->pw_name; + this->ruser = pwent.pw_name; - struct group *grent = getgrgid(this->rgid); - if (grent == 0) + group grent(this->rgid); + if (!grent) { if (errno) throw error(this->ruid, GROUP, strerror(errno)); else throw error(this->ruid, GROUP); } - this->rgroup = grent->gr_name; + this->rgroup = grent.gr_name; /* By default, the auth user is the same as the remote user. */ set_user(this->ruser); @@ -155,18 +156,18 @@ auth::set_user (std::string const& user) this->user = user; - struct passwd *pwent = getpwnam(this->user.c_str()); - if (pwent == 0) + passwd pwent(this->user); + if (!pwent) { if (errno) throw error(user, USER, strerror(errno)); else throw error(user, USER); } - this->uid = pwent->pw_uid; - this->gid = pwent->pw_gid; - this->home = pwent->pw_dir; - this->shell = pwent->pw_shell; + this->uid = pwent.pw_uid; + this->gid = pwent.pw_gid; + this->home = pwent.pw_dir; + this->shell = pwent.pw_shell; log_debug(DEBUG_INFO) << format("auth uid = %1%, gid = %2%") % this->uid % this->gid << endl; diff --git a/sbuild/sbuild-session.cc b/sbuild/sbuild-session.cc index 44e2b6b6..e4e0c4d1 100644 --- a/sbuild/sbuild-session.cc +++ b/sbuild/sbuild-session.cc @@ -125,27 +125,27 @@ namespace * @returns true if the user is a member of group, otherwise false. */ bool - is_group_member (std::string const& group) + is_group_member (std::string const& groupname) { errno = 0; - struct group *groupbuf = getgrnam(group.c_str()); - if (groupbuf == 0) + sbuild::group grp(groupname); + if (!grp) { if (errno == 0) { - session::error e(group, session::GROUP_UNKNOWN); + session::error e(groupname, session::GROUP_UNKNOWN); log_exception_warning(e); } else { - session::error e(group, session::GROUP_UNKNOWN, strerror(errno)); + session::error e(groupname, session::GROUP_UNKNOWN, strerror(errno)); log_exception_warning(e); } return false; } bool group_member = false; - if (groupbuf->gr_gid == getgid()) + if (grp.gr_gid == getgid()) { group_member = true; } @@ -167,7 +167,7 @@ namespace for (int i = 0; i < supp_group_count; ++i) { - if (groupbuf->gr_gid == supp_groups[i]) + if (grp.gr_gid == supp_groups[i]) group_member = true; } delete[] supp_groups; diff --git a/sbuild/sbuild-util.cc b/sbuild/sbuild-util.cc index f380e8b5..dc5cb21e 100644 --- a/sbuild/sbuild-util.cc +++ b/sbuild/sbuild-util.cc @@ -516,3 +516,224 @@ sbuild::stat::stat (int fd): sbuild::stat::~stat () { } + +sbuild::passwd::passwd (): + ::passwd(), + buffer(), + valid(false) +{ + clear(); +} + +sbuild::passwd::passwd (uid_t uid): + ::passwd(), + buffer(), + valid(false) +{ + clear(); + + query_uid(uid); +} + +sbuild::passwd::passwd (const char *name): + ::passwd(), + buffer(), + valid(false) +{ + clear(); + + query_name(name); +} + +sbuild::passwd::passwd (std::string const& name): + ::passwd(), + buffer(), + valid(false) +{ + clear(); + + query_name(name); +} + +void +sbuild::passwd::clear () +{ + valid = false; + + buffer.clear(); + + ::passwd::pw_name = 0; + ::passwd::pw_passwd = 0; + ::passwd::pw_uid = 0; + ::passwd::pw_gid = 0; + ::passwd::pw_gecos = 0; + ::passwd::pw_dir = 0; + ::passwd::pw_shell = 0; +} + +void +sbuild::passwd::query_uid (uid_t uid) +{ + buffer_type::size_type size = 1 << 7; + buffer.reserve(size); + int error; + + ::passwd *pwd_result; + + while ((error = getpwuid_r(uid, this, + &buffer[0], buffer.capacity(), + &pwd_result))) + { + size <<= 1; + buffer.reserve(size); + } + + if (pwd_result) + valid = true; + else + errno = error; +} + +void +sbuild::passwd::query_name (const char *name) +{ + buffer_type::size_type size = 1 << 8; + buffer.reserve(size); + int error; + + ::passwd *pwd_result; + + while ((error = getpwnam_r(name, this, + &buffer[0], buffer.capacity(), + &pwd_result))) + { + size <<= 1; + buffer.reserve(size); + } + + if (pwd_result) + valid = true; + else + errno = error; +} + +void +sbuild::passwd::query_name (std::string const& name) +{ + query_name(name.c_str()); +} + +bool +sbuild::passwd::operator ! () const +{ + return !valid; +} + +sbuild::group::group (): + ::group(), + buffer(), + valid(false) +{ + clear(); +} + +sbuild::group::group (gid_t gid): + ::group(), + buffer(), + valid(false) +{ + clear(); + + query_gid(gid); +} + +sbuild::group::group (const char *name): + ::group(), + buffer(), + valid(false) +{ + clear(); + + query_name(name); +} + +sbuild::group::group (std::string const& name): + ::group(), + buffer(), + valid(false) +{ + clear(); + + query_name(name); +} + +void +sbuild::group::clear () +{ + valid = false; + + buffer.clear(); + + ::group::gr_name = 0; + ::group::gr_passwd = 0; + ::group::gr_gid = 0; + ::group::gr_mem = 0; +} + +void +sbuild::group::query_gid (gid_t gid) +{ + buffer_type::size_type size = 1 << 7; + buffer.reserve(size); + int error; + + ::group *grp_result; + + while ((error = getgrgid_r(gid, this, + &buffer[0], buffer.capacity(), + &grp_result))) + { + size <<= 1; + buffer.reserve(size); + } + + if (grp_result) + valid = true; + else + errno = error; +} + +void +sbuild::group::query_name (const char *name) +{ + buffer_type::size_type size = 1 << 8; + buffer.reserve(size); + int error; + + ::group *grp_result; + + while ((error = getgrnam_r(name, this, + &buffer[0], buffer.capacity(), + &grp_result))) + { + size <<= 1; + buffer.reserve(size); + } + + if (grp_result) + valid = true; + else + errno = error; +} + +void +sbuild::group::query_name (std::string const& name) +{ + query_name(name.c_str()); +} + +bool +sbuild::group::operator ! () const +{ + return !valid; +} diff --git a/sbuild/sbuild-util.h b/sbuild/sbuild-util.h index b05c9f6f..c18da049 100644 --- a/sbuild/sbuild-util.h +++ b/sbuild/sbuild-util.h @@ -25,9 +25,12 @@ #include <sbuild/sbuild-types.h> #include <string> +#include <cerrno> #include <sys/types.h> #include <sys/stat.h> +#include <pwd.h> +#include <grp.h> #include <unistd.h> namespace sbuild @@ -672,6 +675,78 @@ namespace sbuild return (static_cast<stat::mode_bits>(status.st_mode) & mask) == mask; } + /** + * System passwd database entry + */ + class passwd : public ::passwd + { + public: + typedef std::vector<char> buffer_type; + + passwd (); + + passwd (uid_t uid); + + passwd (const char *name); + + passwd (std::string const& name); + + void + clear (); + + void + query_uid (uid_t uid); + + void + query_name (const char *name); + + void + query_name (std::string const& name); + + bool + operator ! () const; + + private: + buffer_type buffer; + bool valid; + }; + + /** + * System group database entry + */ + class group : public ::group + { + public: + typedef std::vector<char> buffer_type; + + group (); + + group (gid_t gid); + + group (const char *name); + + group (std::string const& name); + + void + clear (); + + void + query_gid (gid_t gid); + + void + query_name (const char *name); + + void + query_name (std::string const& name); + + bool + operator ! () const; + + private: + buffer_type buffer; + bool valid; + }; + } #endif /* SBUILD_UTIL_H */ |