summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRoger Leigh <rleigh@debian.org>2009-09-27 22:52:44 +0100
committerRoger Leigh <rleigh@debian.org>2009-09-27 22:54:57 +0100
commit11ea9932e8d90e4e0681f3062f26b494842e675d (patch)
tree6802941901a37d93cce059b2e5256b5ad001ba22
parent6fe0df0c4cb22e81e3850384fd3b208b8848bbe7 (diff)
downloadschroot-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--TODO4
-rw-r--r--sbuild/sbuild-auth.cc25
-rw-r--r--sbuild/sbuild-session.cc14
-rw-r--r--sbuild/sbuild-util.cc221
-rw-r--r--sbuild/sbuild-util.h75
5 files changed, 316 insertions, 23 deletions
diff --git a/TODO b/TODO
index 6cde7d0b..316a25e1 100644
--- a/TODO
+++ b/TODO
@@ -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 */