[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [PATCH] id: add feature to accept multiple usernames
From: |
Pádraig Brady |
Subject: |
Re: [PATCH] id: add feature to accept multiple usernames |
Date: |
Sat, 14 Jul 2018 18:39:52 -0700 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:45.0) Gecko/20100101 Thunderbird/45.8.0 |
On 14/07/18 01:59, Achilles Gaikwad wrote:
> Adds a feature to id command to accept multiple usernames and/or uid
> as arguments.
>
> $ id root nobody
> uid=0(root) gid=0(root) groups=0(root)
> uid=99(nobody) gid=99(nobody) groups=99(nobody)
>
> * src/id.c (main): make varibles opt_zero, just_group_list,
> just_group, use_real, just_user global to be used in a new
> function.
> (print_stuff): new function that will print user and group information
> for the specified USER.
> Restructure the code in the file to have global variables followed by
> functions to make the file look pretty.
>
> Signed-off-by: Achilles Gaikwad <address@hidden>
> ---
> src/id.c | 155 +++++++++++++++++++++++++++++--------------------------
> 1 file changed, 82 insertions(+), 73 deletions(-)
>
> diff --git a/src/id.c b/src/id.c
> index be0758059..65117ec5c 100644
> --- a/src/id.c
> +++ b/src/id.c
> @@ -43,10 +43,18 @@
>
> /* If nonzero, output only the SELinux context. */
> static bool just_context = 0;
> -
> -static void print_user (uid_t uid);
> -static void print_full_info (const char *username);
> -
> +/* If true, delimit entries with NUL characters, not whitespace */
> +bool opt_zero = false;
> +/* If true, output the list of all group IDs. -G */
> +bool just_group_list = false;
> +/* If true, output only the group ID(s). -g */
> +bool just_group = false;
> +/* If true, output real UID/GID instead of default effective UID/GID. -r */
> +bool use_real = false;
> +/* If true, output only the user ID(s). -u */
> +bool just_user = false;
> +/* True unless errors have been encountered. */
> +static bool ok = true;
> /* If true, output user/group name instead of ID number. -n */
> static bool use_name = false;
>
> @@ -54,13 +62,14 @@ static bool use_name = false;
> static uid_t ruid, euid;
> 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 void print_user (uid_t uid);
> +static void print_full_info (const char *username);
> +static void print_stuff(const char *pw_name);
> +
> static struct option const longopts[] =
> {
> {"context", no_argument, NULL, 'Z'},
> @@ -116,18 +125,8 @@ 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;
> - /* If true, output only the group ID(s). -g */
> - bool just_group = false;
> - /* If true, output real UID/GID instead of default effective UID/GID. -r */
> - bool use_real = false;
> - /* If true, output only the user ID(s). -u */
> - bool just_user = false;
> -
> initialize_main (&argc, &argv);
> set_program_name (argv[0]);
> setlocale (LC_ALL, "");
> @@ -185,11 +184,6 @@ main (int argc, char **argv)
> }
>
> size_t n_ids = argc - optind;
> - if (1 < n_ids)
> - {
> - error (0, 0, _("extra operand %s"), quote (argv[optind + 1]));
> - usage (EXIT_FAILURE);
> - }
>
> if (n_ids && just_context)
> die (EXIT_FAILURE, 0,
> @@ -228,29 +222,43 @@ main (int argc, char **argv)
> die (EXIT_FAILURE, 0, _("can't get process context"));
> }
>
> - if (n_ids == 1)
> - {
> - 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)
> - die (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;
> - }
> + if (n_ids >= 1)
> + {
> + /* Changing the value of n_ids to the last index in the array where we
> + have the last possible user id. This helps us because we don't have
> + to declare a different variable to keep a track of where the last
> username
> + lies in argv[]. */
> + n_ids += optind;
> +
> + /* For each username/userid to get its pw_name field */
> + for (; optind < n_ids; 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 (0, errno, _("%s: no such user"), quote
> (argv[optind]));
> + ok &= false;
> + continue;
> + }
> + pw_name = xstrdup(pwd->pw_name);
> + ruid = euid = pwd->pw_uid;
> + rgid = egid = pwd->pw_gid;
> + print_stuff(pw_name);
> + IF_LINT (free (pw_name));
> + }
> + }
> else
> {
> /* POSIX says identification functions (getuid, getgid, and
> @@ -289,34 +297,10 @@ main (int argc, char **argv)
> if (rgid == NO_GID && errno)
> die (EXIT_FAILURE, errno, _("cannot get real GID"));
> }
> + print_stuff(pw_name);
> + IF_LINT (free (pw_name));
> }
>
> - if (just_user)
> - {
> - print_user (use_real ? ruid : euid);
> - }
> - else if (just_group)
> - {
> - if (!print_group (use_real ? rgid : egid, use_name))
> - ok = false;
> - }
> - else if (just_group_list)
> - {
> - if (!print_group_list (pw_name, ruid, rgid, egid, use_name,
> - opt_zero ? '\0' : ' '))
> - ok = false;
> - }
> - else if (just_context)
> - {
> - fputs (context, stdout);
> - }
> - else
> - {
> - print_full_info (pw_name);
> - }
> - putchar (opt_zero ? '\0' : '\n');
> -
> - IF_LINT (free (pw_name));
> return ok ? EXIT_SUCCESS : EXIT_FAILURE;
> }
>
> @@ -356,7 +340,7 @@ print_user (uid_t uid)
> {
> error (0, 0, _("cannot find name for user ID %s"),
> uidtostr (uid));
> - ok = false;
> + ok &= false;
> }
> }
>
> @@ -415,7 +399,7 @@ print_full_info (const char *username)
> quote (username));
> else
> error (0, errno, _("failed to get groups for the current
> process"));
> - ok = false;
> + ok &= false;
> return;
> }
>
> @@ -438,3 +422,28 @@ print_full_info (const char *username)
> if (context)
> printf (_(" context=%s"), context);
> }
> +
> +/* Print information about the user based on the arguments passed. */
> +
> +static void
> +print_stuff(const char *pw_name)
> +{
> + if (just_user)
> + print_user (use_real ? ruid : euid);
> +
> + /* print_group and print_group_lists functions return true on successful
> + execution but false if something goes wrong. We then AND this value with
> + the current value of 'ok' because we want to know if one of the previous
> + users faced a problem in these functions. This value of 'ok' is later
> used
> + to understand what status program should exit with. */
> + else if (just_group)
> + ok &= print_group (use_real ? rgid : egid, use_name);
> + else if (just_group_list)
> + ok &= print_group_list (pw_name, ruid, rgid, egid,
> + use_name, opt_zero ? '\0' : ' ');
> + else if (just_context)
> + fputs (context, stdout);
> + else
> + print_full_info (pw_name);
> + putchar (opt_zero ? '\0' : '\n');
> +}
This makes sense I think.
I see groups(1) already supports multiple users:
$ groups $USER nobody
padraig : padraig wheel
nobody : nobody
While id(1) currently supports only:
$ id -Gn $USER
padraig wheel
I've not reviewed it yet, but things to consider.
- Add tests/docs
- Ensure we process all arguments. I.E. don't die() early
- Do we need double \0\0 with -z to delimit each record?
thanks for the patch,
Pádraig