On 09/19/2013 08:24 PM, Pádraig Brady wrote:
> On 09/19/2013 08:13 PM, Eric Blake wrote:
>> I just created a local user named "0" (don't ask), and noticed that
>> although we can do things like "chown +0:+0 file" to FORCE a file to be
>> owned by uid 0 (rather than the uid of my unfortunate "0" username),
>> it's a bit harder to learn details about a uid hidden by a poor username.
>>
>> $ id 0
>> uid=14987(0) gid=14987(0) groups=14987(0)
>> $ id +0
>> id: +0: no such user
>>
>> Of course, everyone "knows" that uid 0 is named "root", but this
>> question applies to any other unfortunate uid/name collision.
>> Therefore, I propose that we support 'id +0' as the way to say 'give me
>> the details about uid 0, no matter if username 0 also happens to exist'.
> 
> Yep that makes sense.
> I see also that FreeBSD does this too.

The attached should address this, in combination with:
http://lists.gnu.org/archive/html/bug-gnulib/2013-09/msg00043.html

thanks,
Pádraig.
>From ae7adc97280eade6793b3349df9448863b20fe86 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?P=C3=A1draig=20Brady?= <[email protected]>
Date: Fri, 20 Sep 2013 12:38:00 +0100
Subject: [PATCH] id: support specifying the user by user ID

* src/id.c (usage): Remove 'name' from the synopsis,
implying that one can also specify by user ID.
(main): Like chown(1), call parse_user_spec() to implement
user name or ID lookup with appropriate precedence.
* doc/coreutils.texi (id invocation): Mention that
a user ID is supported and how '+' affects lookup order.
* tests/misc/id-groups.sh: Remove test now subsumed into...
* tests/misc/id-uid.sh: New test covering new interface.
* tests/local.mk: Rename the test.
* NEWS: Mention the new feature.
Addresses http://bugs.gnu.org/15421
---
 NEWS                                   |    2 ++
 doc/coreutils.texi                     |    5 ++++-
 src/id.c                               |   31 ++++++++++++++++++++++++-------
 tests/local.mk                         |    2 +-
 tests/misc/{id-groups.sh => id-uid.sh} |   20 +++++++++++++++++---
 5 files changed, 49 insertions(+), 13 deletions(-)
 rename tests/misc/{id-groups.sh => id-uid.sh} (58%)

diff --git a/NEWS b/NEWS
index d26722d..cc47c7c 100644
--- a/NEWS
+++ b/NEWS
@@ -47,6 +47,8 @@ GNU coreutils NEWS                                    -*- outline -*-
   id and ls with -Z report the SMACK security context where available.
   mkdir, mkfifo and mknod with -Z set the SMACK context where available.
 
+  id can now lookup by user ID, in addition to the existing name lookup.
+
   join accepts a new option: --zero-terminated (-z). As with the sort,uniq
   option of the same name, this makes join consume and produce NUL-terminated
   lines rather than newline-terminated lines.
diff --git a/doc/coreutils.texi b/doc/coreutils.texi
index 21216b4..aa99aef 100644
--- a/doc/coreutils.texi
+++ b/doc/coreutils.texi
@@ -14456,9 +14456,12 @@ logins, groups, and so forth.
 running it if no user is specified.  Synopsis:
 
 @example
-id [@var{option}]@dots{} [@var{username}]
+id [@var{option}]@dots{} [@var{user}]
 @end example
 
+@var{user} can be either a user ID or a name, with name lookup
+taking precedence unless the ID is specified with a leading @samp{+}.
+
 @vindex POSIXLY_CORRECT
 By default, it prints the real user ID, real group ID, effective user ID
 if different from the real user ID, effective group ID if different from
diff --git a/src/id.c b/src/id.c
index 3e7016f..c35dee4 100644
--- a/src/id.c
+++ b/src/id.c
@@ -31,6 +31,7 @@
 #include "quote.h"
 #include "group-list.h"
 #include "smack.h"
+#include "userspec.h"
 
 /* The official name of this program (e.g., no 'g' prefix).  */
 #define PROGRAM_NAME "id"
@@ -79,10 +80,10 @@ usage (int status)
     emit_try_help ();
   else
     {
-      printf (_("Usage: %s [OPTION]... [USERNAME]\n"), program_name);
+      printf (_("Usage: %s [OPTION]... [USER]\n"), program_name);
       fputs (_("\
-Print user and group information for the specified USERNAME,\n\
-or (when USERNAME omitted) for the current user.\n\
+Print user and group information for the specified USER,\n\
+or (when USER omitted) for the current user.\n\
 \n\
   -a              ignore, for compatibility with other versions\n\
   -Z, --context   print only the security context of the current user\n\
@@ -109,6 +110,7 @@ main (int argc, char **argv)
   int optc;
   int selinux_enabled = (is_selinux_enabled () > 0);
   bool smack_enabled = is_smack_enabled ();
+  const char *pw_name = NULL;
 
   /* If true, output the list of all group IDs. -G */
   bool just_group_list = false;
@@ -212,9 +214,24 @@ main (int argc, char **argv)
 
   if (n_ids == 1)
     {
-      struct passwd *pwd = getpwnam (argv[optind]);
+      struct passwd *pwd = NULL;
+      const char *spec = argv[optind];
+      /* Disallow an empty spec here as parse_user_spec() doesn't
+         give an error for that as it seems it's a valid way to
+         specify a noop or "reset special bits" depending on the system.  */
+      if (*spec)
+        {
+          if (parse_user_spec (spec, &euid, NULL, NULL, NULL) == NULL)
+            {
+              /* parse_user_spec will only extract a numeric spec,
+                 so we lookup that here to verify and also retrieve
+                 the PW_NAME used subsequently in group lookup.  */
+              pwd = getpwuid (euid);
+            }
+        }
       if (pwd == NULL)
-        error (EXIT_FAILURE, 0, _("%s: no such user"), argv[optind]);
+        error (EXIT_FAILURE, 0, _("%s: no such user"), spec);
+      pw_name = xstrdup (pwd->pw_name);
       ruid = euid = pwd->pw_uid;
       rgid = egid = pwd->pw_gid;
     }
@@ -269,7 +286,7 @@ main (int argc, char **argv)
     }
   else if (just_group_list)
     {
-      if (!print_group_list (argv[optind], ruid, rgid, egid, use_name))
+      if (!print_group_list (pw_name, ruid, rgid, egid, use_name))
         ok = false;
     }
   else if (just_context)
@@ -278,7 +295,7 @@ main (int argc, char **argv)
     }
   else
     {
-      print_full_info (argv[optind]);
+      print_full_info (pw_name);
     }
   putchar ('\n');
 
diff --git a/tests/local.mk b/tests/local.mk
index b00ff59..e5e3f74 100644
--- a/tests/local.mk
+++ b/tests/local.mk
@@ -275,7 +275,7 @@ all_tests =					\
   tests/misc/head-c.sh				\
   tests/misc/head-pos.sh			\
   tests/misc/id-context.sh			\
-  tests/misc/id-groups.sh			\
+  tests/misc/id-uid.sh				\
   tests/misc/id-setgid.sh			\
   tests/misc/md5sum.pl				\
   tests/misc/md5sum-bsd.sh			\
diff --git a/tests/misc/id-groups.sh b/tests/misc/id-uid.sh
similarity index 58%
rename from tests/misc/id-groups.sh
rename to tests/misc/id-uid.sh
index ff3dc59..13f5663 100755
--- a/tests/misc/id-groups.sh
+++ b/tests/misc/id-uid.sh
@@ -1,6 +1,6 @@
 #!/bin/sh
-# Ensure that "id" outputs groups for a user
-# Copyright (C) 2009-2013 Free Software Foundation, Inc.
+# Ensure that "id" works with numeric user ids
+# Copyright (C) 2013 Free Software Foundation, Inc.
 
 # This program is free software: you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -18,6 +18,20 @@
 . "${srcdir=.}/tests/init.sh"; path_prepend_ ./src
 print_ver_ id
 
-id -G $(id -nu) || fail=1
+uid=$(id -u) || fail=1
+user=$(id -nu) || fail=1
+
+# Ensure the empty user spec is discarded
+id '' && fail=1
+
+for mode in '' '-G' '-g'; do
+  id $mode $user > user_out || fail=1 # lookup name for comparison
+
+  id $mode $uid > uid_out || fail=1   # lookup name "$uid" before id "$uid"
+  compare user_out uid_out || fail=1
+
+  id $mode +$uid > uid_out || fail=1  # lookup only id "$uid"
+  compare user_out uid_out || fail=1
+done
 
 Exit $fail
-- 
1.7.7.6

Reply via email to