summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorBostjan Skufca <bostjan@a2o.si>2014-09-05 21:21:03 +0000
committerSerge Hallyn <serge.hallyn@ubuntu.com>2014-09-17 15:48:10 -0500
commita113b87c4549b3236d43e1e1c31790b5167d87db (patch)
tree7860e810685b083817e3076f287b472f4cce2c07
parentb999d48941e86111589b38c1909d38a44319d0f0 (diff)
newuidmap/newgidmap: added support for user matching by UID in /etc/sub[ug]id
Until now only exact username specification in /etc/sub[ug]id file allowed the mapping. This prevented normal use for those users who use multiple usernames with the same UID, as it rejected mapping even though it was allowed for another username with the same UID. This patch initially retains the old behaviour, for performance's sake. In the first pass, new[ug]idmap only searches for exact username match. If that yields no valid results, it continues into another loop, which does UID resolution and comparison. If either definition (numeric UID mapping specification or mapping specification for another username with the same UID as current username) is found, it is used. Signed-off-by: Serge Hallyn <serge.hallyn@ubuntu.com>
-rw-r--r--lib/subordinateio.c79
-rw-r--r--man/subgid.5.xml2
-rw-r--r--man/subuid.5.xml2
3 files changed, 81 insertions, 2 deletions
diff --git a/lib/subordinateio.c b/lib/subordinateio.c
index 0ba117b0..25353368 100644
--- a/lib/subordinateio.c
+++ b/lib/subordinateio.c
@@ -11,6 +11,8 @@
#include <stdio.h>
#include "commonio.h"
#include "subordinateio.h"
+#include <sys/types.h>
+#include <pwd.h>
struct subordinate_range {
const char *owner;
@@ -189,6 +191,15 @@ static const struct subordinate_range *find_range(struct commonio_db *db,
const char *owner, unsigned long val)
{
const struct subordinate_range *range;
+
+ /*
+ * Search for exact username/group specification
+ *
+ * This is the original method - go fast through the db, doing only
+ * exact username/group string comparison. Therefore we leave it as-is
+ * for the time being, in order to keep it equally fast as it was
+ * before.
+ */
commonio_rewind(db);
while ((range = commonio_next(db)) != NULL) {
unsigned long first = range->start;
@@ -200,6 +211,74 @@ static const struct subordinate_range *find_range(struct commonio_db *db,
if ((val >= first) && (val <= last))
return range;
}
+
+
+ /*
+ * We only do special handling for these two files
+ */
+ if ((0 != strcmp(db->filename, "/etc/subuid")) && (0 != strcmp(db->filename, "/etc/subgid")))
+ return NULL;
+
+ /*
+ * Search loop above did not produce any result. Let's rerun it,
+ * but this time try to matcha actual UIDs. The first entry that
+ * matches is considered a success.
+ * (It may be specified as literal UID or as another username which
+ * has the same UID as the username we are looking for.)
+ */
+ struct passwd *pwd;
+ uid_t owner_uid;
+ char owner_uid_string[33] = "";
+
+
+ /* Get UID of the username we are looking for */
+ pwd = getpwnam(owner);
+ if (NULL == pwd) {
+ /* Username not defined in /etc/passwd, or error occured during lookup */
+ return NULL;
+ }
+ owner_uid = pwd->pw_uid;
+ sprintf(owner_uid_string, "%lu", (unsigned long int)owner_uid);
+
+ commonio_rewind(db);
+ while ((range = commonio_next(db)) != NULL) {
+ unsigned long first = range->start;
+ unsigned long last = first + range->count - 1;
+
+ /*
+ * First check if range owner is specified as numeric UID
+ * and if it matches.
+ */
+ if (0 != strcmp(range->owner, owner_uid_string)) {
+ /*
+ * Ok, this range owner is not specified as numeric UID
+ * we are looking for. It may be specified as another
+ * UID or as a literal username.
+ *
+ * If specified as another UID, the call to getpwnam()
+ * will return NULL.
+ *
+ * If specified as literal username, we will get its
+ * UID and compare that to UID we are looking for.
+ */
+ const struct passwd *range_owner_pwd;
+
+ range_owner_pwd = getpwnam(range->owner);
+ if (NULL == range_owner_pwd) {
+ continue;
+ }
+
+ if (owner_uid != range_owner_pwd->pw_uid) {
+ continue;
+ }
+ }
+
+ /* Owner matches, now let us check this UID/GID range */
+ if ((val >= first) && (val <= last)) {
+ return range;
+ }
+ }
+
return NULL;
}
diff --git a/man/subgid.5.xml b/man/subgid.5.xml
index f7b4b50b..27799ba9 100644
--- a/man/subgid.5.xml
+++ b/man/subgid.5.xml
@@ -57,7 +57,7 @@
</para>
<itemizedlist mark='bullet'>
<listitem>
- <para>login name</para>
+ <para>login name or UID</para>
</listitem>
<listitem>
<para>numerical subordinate group ID</para>
diff --git a/man/subuid.5.xml b/man/subuid.5.xml
index a833f57f..939ea166 100644
--- a/man/subuid.5.xml
+++ b/man/subuid.5.xml
@@ -57,7 +57,7 @@
</para>
<itemizedlist mark='bullet'>
<listitem>
- <para>login name</para>
+ <para>login name or UID</para>
</listitem>
<listitem>
<para>numerical subordinate user ID</para>