summaryrefslogtreecommitdiff
path: root/src/id.c
diff options
context:
space:
mode:
authorLorry Tar Creator <lorry-tar-importer@lorry>2016-01-20 10:55:18 +0000
committerLorry Tar Creator <lorry-tar-importer@lorry>2016-01-20 10:55:18 +0000
commit70e9163c9c18e995515598085cb824e554eb7ae7 (patch)
treea42dc8b2a6c031354bf31472de888bfc8a060132 /src/id.c
parentcbf5993c43f49281173f185863577d86bfac6eae (diff)
downloadcoreutils-tarball-master.tar.gz
Diffstat (limited to 'src/id.c')
-rw-r--r--src/id.c470
1 files changed, 260 insertions, 210 deletions
diff --git a/src/id.c b/src/id.c
index 7abb3e5..38844af 100644
--- a/src/id.c
+++ b/src/id.c
@@ -1,10 +1,10 @@
/* id -- print real and effective UIDs and GIDs
- Copyright (C) 1989-2005 Free Software Foundation, Inc.
+ Copyright (C) 1989-2016 Free Software Foundation, Inc.
- This program is free software; you can redistribute it and/or modify
+ 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
- the Free Software Foundation; either version 2, or (at your option)
- any later version.
+ the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
@@ -12,39 +12,40 @@
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., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
/* Written by Arnold Robbins.
Major rewrite by David MacKenzie, djm@gnu.ai.mit.edu. */
#include <config.h>
#include <stdio.h>
-#include <getopt.h>
#include <sys/types.h>
#include <pwd.h>
#include <grp.h>
#include <getopt.h>
+#include <selinux/selinux.h>
#include "system.h"
#include "error.h"
+#include "mgetgroups.h"
#include "quote.h"
+#include "group-list.h"
+#include "smack.h"
+#include "userspec.h"
-/* The official name of this program (e.g., no `g' prefix). */
+/* The official name of this program (e.g., no 'g' prefix). */
#define PROGRAM_NAME "id"
-#define AUTHORS "Arnold Robbins", "David MacKenzie"
+#define AUTHORS \
+ proper_name ("Arnold Robbins"), \
+ proper_name ("David MacKenzie")
-int getugroups ();
+/* If nonzero, output only the SELinux context. */
+static bool just_context = 0;
static void print_user (uid_t uid);
-static void print_group (gid_t gid);
-static void print_group_list (const char *username);
static void print_full_info (const char *username);
-/* The name this program was run with. */
-char *program_name;
-
/* If true, output user/group name instead of ID number. -n */
static bool use_name = false;
@@ -55,13 +56,19 @@ static gid_t rgid, egid;
/* True unless errors have been encountered. */
static bool ok = true;
+/* The SELinux context. Start with a known invalid value so print_full_info
+ knows when 'context' has not been set to a meaningful value. */
+static char *context = NULL;
+
static struct option const longopts[] =
{
+ {"context", no_argument, NULL, 'Z'},
{"group", no_argument, NULL, 'g'},
{"groups", no_argument, NULL, 'G'},
{"name", no_argument, NULL, 'n'},
{"real", no_argument, NULL, 'r'},
{"user", no_argument, NULL, 'u'},
+ {"zero", no_argument, NULL, 'z'},
{GETOPT_HELP_OPTION_DECL},
{GETOPT_VERSION_OPTION_DECL},
{NULL, 0, NULL, 0}
@@ -71,20 +78,25 @@ void
usage (int status)
{
if (status != EXIT_SUCCESS)
- fprintf (stderr, _("Try `%s --help' for more information.\n"),
- program_name);
+ emit_try_help ();
else
{
- printf (_("Usage: %s [OPTION]... [USERNAME]\n"), program_name);
+ printf (_("Usage: %s [OPTION]... [USER]\n"), program_name);
fputs (_("\
-Print information for USERNAME, or the current user.\n\
-\n\
- -a ignore, for compatibility with other versions\n\
- -g, --group print only the effective group ID\n\
- -G, --groups print all group IDs\n\
- -n, --name print a name instead of a number, for -ugG\n\
- -r, --real print the real ID instead of the effective ID, with -ugG\n\
- -u, --user print only the effective user ID\n\
+Print user and group information for the specified USER,\n\
+or (when USER omitted) for the current user.\n\
+\n"),
+ stdout);
+ fputs (_("\
+ -a ignore, for compatibility with other versions\n\
+ -Z, --context print only the security context of the process\n\
+ -g, --group print only the effective group ID\n\
+ -G, --groups print all group IDs\n\
+ -n, --name print a name instead of a number, for -ugG\n\
+ -r, --real print the real ID instead of the effective ID, with -ugG\n\
+ -u, --user print only the effective user ID\n\
+ -z, --zero delimit entries with NUL characters, not whitespace;\n\
+ not permitted in default format\n\
"), stdout);
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
@@ -92,7 +104,7 @@ Print information for USERNAME, or the current user.\n\
\n\
Without any OPTION, print some useful set of identified information.\n\
"), stdout);
- printf (_("\nReport bugs to <%s>.\n"), PACKAGE_BUGREPORT);
+ emit_ancillary_info (PROGRAM_NAME);
}
exit (status);
}
@@ -101,6 +113,10 @@ int
main (int argc, char **argv)
{
int optc;
+ int selinux_enabled = (is_selinux_enabled () > 0);
+ bool smack_enabled = is_smack_enabled ();
+ bool opt_zero = false;
+ char *pw_name = NULL;
/* If true, output the list of all group IDs. -G */
bool just_group_list = false;
@@ -112,216 +128,237 @@ main (int argc, char **argv)
bool just_user = false;
initialize_main (&argc, &argv);
- program_name = argv[0];
+ set_program_name (argv[0]);
setlocale (LC_ALL, "");
bindtextdomain (PACKAGE, LOCALEDIR);
textdomain (PACKAGE);
atexit (close_stdout);
- while ((optc = getopt_long (argc, argv, "agnruG", longopts, NULL)) != -1)
+ while ((optc = getopt_long (argc, argv, "agnruzGZ", longopts, NULL)) != -1)
{
switch (optc)
- {
- case 'a':
- /* Ignore -a, for compatibility with SVR4. */
- break;
- case 'g':
- just_group = true;
- break;
- case 'n':
- use_name = true;
- break;
- case 'r':
- use_real = true;
- break;
- case 'u':
- just_user = true;
- break;
- case 'G':
- just_group_list = true;
- break;
- case_GETOPT_HELP_CHAR;
- case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
- default:
- usage (EXIT_FAILURE);
- }
+ {
+ case 'a':
+ /* Ignore -a, for compatibility with SVR4. */
+ break;
+
+ case 'Z':
+ /* politely decline if we're not on a SELinux/SMACK-enabled kernel. */
+#ifdef HAVE_SMACK
+ if (!selinux_enabled && !smack_enabled)
+ error (EXIT_FAILURE, 0,
+ _("--context (-Z) works only on "
+ "an SELinux/SMACK-enabled kernel"));
+#else
+ if (!selinux_enabled)
+ error (EXIT_FAILURE, 0,
+ _("--context (-Z) works only on an SELinux-enabled kernel"));
+#endif
+ just_context = true;
+ break;
+
+ case 'g':
+ just_group = true;
+ break;
+ case 'n':
+ use_name = true;
+ break;
+ case 'r':
+ use_real = true;
+ break;
+ case 'u':
+ just_user = true;
+ break;
+ case 'z':
+ opt_zero = true;
+ break;
+ case 'G':
+ just_group_list = true;
+ break;
+ case_GETOPT_HELP_CHAR;
+ case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
+ default:
+ usage (EXIT_FAILURE);
+ }
}
- if (just_user + just_group + just_group_list > 1)
- error (EXIT_FAILURE, 0, _("cannot print only user and only group"));
+ size_t n_ids = argc - optind;
+ if (1 < n_ids)
+ {
+ error (0, 0, _("extra operand %s"), quote (argv[optind + 1]));
+ usage (EXIT_FAILURE);
+ }
- if (just_user + just_group + just_group_list == 0 && (use_real | use_name))
+ if (n_ids && just_context)
error (EXIT_FAILURE, 0,
- _("cannot print only names or real IDs in default format"));
+ _("cannot print security context when user specified"));
+
+ if (just_user + just_group + just_group_list + just_context > 1)
+ error (EXIT_FAILURE, 0, _("cannot print \"only\" of more than one choice"));
+
+ bool default_format = (just_user + just_group + just_group_list
+ + just_context == 0);
- if (argc - optind > 1)
+ if (default_format && (use_real || use_name))
+ error (EXIT_FAILURE, 0,
+ _("cannot print only names or real IDs in default format"));
+
+ if (default_format && opt_zero)
+ error (EXIT_FAILURE, 0,
+ _("option --zero not permitted in default format"));
+
+ /* If we are on a SELinux/SMACK-enabled kernel, no user is specified, and
+ either --context is specified or none of (-u,-g,-G) is specified,
+ and we're not in POSIXLY_CORRECT mode, get our context. Otherwise,
+ leave the context variable alone - it has been initialized to an
+ invalid value that will be not displayed in print_full_info(). */
+ if (n_ids == 0
+ && (just_context
+ || (default_format && ! getenv ("POSIXLY_CORRECT"))))
{
- error (0, 0, _("extra operand %s"), quote (argv[optind + 1]));
- usage (EXIT_FAILURE);
+ /* Report failure only if --context (-Z) was explicitly requested. */
+ if ((selinux_enabled && getcon (&context) && just_context)
+ || (smack_enabled
+ && smack_new_label_from_self (&context) < 0
+ && just_context))
+ error (EXIT_FAILURE, 0, _("can't get process context"));
}
- if (argc - optind == 1)
+ 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"), quote (spec));
+ pw_name = xstrdup (pwd->pw_name);
ruid = euid = pwd->pw_uid;
rgid = egid = pwd->pw_gid;
}
else
{
- euid = geteuid ();
- ruid = getuid ();
- egid = getegid ();
- rgid = getgid ();
+ /* POSIX says identification functions (getuid, getgid, and
+ others) cannot fail, but they can fail under GNU/Hurd and a
+ few other systems. Test for failure by checking errno. */
+ uid_t NO_UID = -1;
+ gid_t NO_GID = -1;
+
+ if (just_user ? !use_real
+ : !just_group && !just_group_list && !just_context)
+ {
+ errno = 0;
+ euid = geteuid ();
+ if (euid == NO_UID && errno)
+ error (EXIT_FAILURE, errno, _("cannot get effective UID"));
+ }
+
+ if (just_user ? use_real
+ : !just_group && (just_group_list || !just_context))
+ {
+ errno = 0;
+ ruid = getuid ();
+ if (ruid == NO_UID && errno)
+ error (EXIT_FAILURE, errno, _("cannot get real UID"));
+ }
+
+ if (!just_user && (just_group || just_group_list || !just_context))
+ {
+ errno = 0;
+ egid = getegid ();
+ if (egid == NO_GID && errno)
+ error (EXIT_FAILURE, errno, _("cannot get effective GID"));
+
+ errno = 0;
+ rgid = getgid ();
+ if (rgid == NO_GID && errno)
+ error (EXIT_FAILURE, errno, _("cannot get real GID"));
+ }
}
if (just_user)
- print_user (use_real ? ruid : euid);
- else if (just_group)
- print_group (use_real ? rgid : egid);
- else if (just_group_list)
- print_group_list (argv[optind]);
- else
- print_full_info (argv[optind]);
- putchar ('\n');
-
- exit (ok ? EXIT_SUCCESS : EXIT_FAILURE);
-}
-
-/* Print the name or value of user ID UID. */
-
-static void
-print_user (uid_t uid)
-{
- struct passwd *pwd = NULL;
-
- if (use_name)
{
- pwd = getpwuid (uid);
- if (pwd == NULL)
- {
- error (0, 0, _("cannot find name for user ID %lu"),
- (unsigned long int) uid);
- ok = false;
- }
+ print_user (use_real ? ruid : euid);
}
-
- if (pwd == NULL)
- printf ("%lu", (unsigned long int) uid);
- else
- printf ("%s", pwd->pw_name);
-}
-
-/* Print the name or value of group ID GID. */
-
-static void
-print_group (gid_t gid)
-{
- struct group *grp = NULL;
-
- if (use_name)
+ else if (just_group)
{
- grp = getgrgid (gid);
- if (grp == NULL)
- {
- error (0, 0, _("cannot find name for group ID %lu"),
- (unsigned long int) gid);
- ok = false;
- }
+ if (!print_group (use_real ? rgid : egid, use_name))
+ ok = false;
}
-
- if (grp == NULL)
- printf ("%lu", (unsigned long int) gid);
- else
- printf ("%s", grp->gr_name);
-}
-
-#if HAVE_GETGROUPS
-
-/* FIXME: document */
-
-static bool
-xgetgroups (const char *username, gid_t gid, int *n_groups,
- GETGROUPS_T **groups)
-{
- int max_n_groups;
- int ng;
- GETGROUPS_T *g = NULL;
-
- if (!username)
- max_n_groups = getgroups (0, NULL);
- else
- max_n_groups = getugroups (0, NULL, username, gid);
-
- if (max_n_groups < 0)
- ng = -1;
- else
+ else if (just_group_list)
{
- g = xnmalloc (max_n_groups, sizeof *g);
- if (!username)
- ng = getgroups (max_n_groups, g);
- else
- ng = getugroups (max_n_groups, g, username, gid);
+ if (!print_group_list (pw_name, ruid, rgid, egid, use_name,
+ opt_zero ? '\0' : ' '))
+ ok = false;
}
-
- if (ng < 0)
+ else if (just_context)
{
- error (0, errno, _("cannot get supplemental group list"));
- free (g);
- return false;
+ fputs (context, stdout);
}
else
{
- *n_groups = ng;
- *groups = g;
- return true;
+ print_full_info (pw_name);
}
+ putchar (opt_zero ? '\0' : '\n');
+
+ IF_LINT (free (pw_name));
+ return ok ? EXIT_SUCCESS : EXIT_FAILURE;
+}
+
+/* Convert a gid_t to string. Do not use this function directly.
+ Instead, use it via the gidtostr macro.
+ Beware that it returns a pointer to static storage. */
+static char *
+gidtostr_ptr (gid_t const *gid)
+{
+ static char buf[INT_BUFSIZE_BOUND (uintmax_t)];
+ return umaxtostr (*gid, buf);
}
+#define gidtostr(g) gidtostr_ptr (&(g))
-#endif /* HAVE_GETGROUPS */
+/* Convert a uid_t to string. Do not use this function directly.
+ Instead, use it via the uidtostr macro.
+ Beware that it returns a pointer to static storage. */
+static char *
+uidtostr_ptr (uid_t const *uid)
+{
+ static char buf[INT_BUFSIZE_BOUND (uintmax_t)];
+ return umaxtostr (*uid, buf);
+}
+#define uidtostr(u) uidtostr_ptr (&(u))
-/* Print all of the distinct groups the user is in. */
+/* Print the name or value of user ID UID. */
static void
-print_group_list (const char *username)
+print_user (uid_t uid)
{
- struct passwd *pwd;
-
- pwd = getpwuid (ruid);
- if (pwd == NULL)
- ok = false;
+ struct passwd *pwd = NULL;
- print_group (rgid);
- if (egid != rgid)
+ if (use_name)
{
- putchar (' ');
- print_group (egid);
+ pwd = getpwuid (uid);
+ if (pwd == NULL)
+ {
+ error (0, 0, _("cannot find name for user ID %s"),
+ uidtostr (uid));
+ ok = false;
+ }
}
-#if HAVE_GETGROUPS
- {
- int n_groups;
- GETGROUPS_T *groups;
- int i;
-
- if (! xgetgroups (username, (pwd ? pwd->pw_gid : (gid_t) -1),
- &n_groups, &groups))
- {
- ok = false;
- return;
- }
-
- for (i = 0; i < n_groups; i++)
- if (groups[i] != rgid && groups[i] != egid)
- {
- putchar (' ');
- print_group (groups[i]);
- }
- free (groups);
- }
-#endif /* HAVE_GETGROUPS */
+ char *s = pwd ? pwd->pw_name : uidtostr (uid);
+ fputs (s, stdout);
}
/* Print all of the info about the user's user and group IDs. */
@@ -332,57 +369,70 @@ print_full_info (const char *username)
struct passwd *pwd;
struct group *grp;
- printf ("uid=%lu", (unsigned long int) ruid);
+ printf (_("uid=%s"), uidtostr (ruid));
pwd = getpwuid (ruid);
if (pwd)
printf ("(%s)", pwd->pw_name);
- printf (" gid=%lu", (unsigned long int) rgid);
+ printf (_(" gid=%s"), gidtostr (rgid));
grp = getgrgid (rgid);
if (grp)
printf ("(%s)", grp->gr_name);
if (euid != ruid)
{
- printf (" euid=%lu", (unsigned long int) euid);
+ printf (_(" euid=%s"), uidtostr (euid));
pwd = getpwuid (euid);
if (pwd)
- printf ("(%s)", pwd->pw_name);
+ printf ("(%s)", pwd->pw_name);
}
if (egid != rgid)
{
- printf (" egid=%lu", (unsigned long int) egid);
+ printf (_(" egid=%s"), gidtostr (egid));
grp = getgrgid (egid);
if (grp)
- printf ("(%s)", grp->gr_name);
+ printf ("(%s)", grp->gr_name);
}
-#if HAVE_GETGROUPS
{
- int n_groups;
- GETGROUPS_T *groups;
+ gid_t *groups;
int i;
- if (! xgetgroups (username, (pwd ? pwd->pw_gid : (gid_t) -1),
- &n_groups, &groups))
+ gid_t primary_group;
+ if (username)
+ primary_group = pwd ? pwd->pw_gid : -1;
+ else
+ primary_group = egid;
+
+ int n_groups = xgetgroups (username, primary_group, &groups);
+ if (n_groups < 0)
{
- ok = false;
- return;
+ if (username)
+ error (0, errno, _("failed to get groups for user %s"),
+ quote (username));
+ else
+ error (0, errno, _("failed to get groups for the current process"));
+ ok = false;
+ return;
}
if (n_groups > 0)
fputs (_(" groups="), stdout);
for (i = 0; i < n_groups; i++)
{
- if (i > 0)
- putchar (',');
- printf ("%lu", (unsigned long int) groups[i]);
- grp = getgrgid (groups[i]);
- if (grp)
- printf ("(%s)", grp->gr_name);
+ if (i > 0)
+ putchar (',');
+ fputs (gidtostr (groups[i]), stdout);
+ grp = getgrgid (groups[i]);
+ if (grp)
+ printf ("(%s)", grp->gr_name);
}
free (groups);
}
-#endif /* HAVE_GETGROUPS */
+
+ /* POSIX mandates the precise output format, and that it not include
+ any context=... part, so skip that if POSIXLY_CORRECT is set. */
+ if (context)
+ printf (_(" context=%s"), context);
}