]> git.ipfire.org Git - thirdparty/shadow.git/commitdiff
add -U option to groupadd and groupmod 271/head
authorSerge Hallyn <shallyn@cisco.com>
Sun, 9 Aug 2020 21:44:30 +0000 (16:44 -0500)
committerSerge Hallyn <shallyn@cisco.com>
Mon, 10 Aug 2020 03:11:33 +0000 (22:11 -0500)
Add a -U option which adds new usernames as members.  For groupmod,
also add -a (append), without which existing members are removed.

Closes #265

lib/groupmem.c
lib/prototypes.h
man/groupadd.8.xml
man/groupmod.8.xml
src/groupadd.c
src/groupmod.c

index 1fd1c135c2f0ffdf68ba35dfafd9b64135d74cb4..2060d03bac32cd937537955eaf13e211bed436b9 100644 (file)
        return gr;
 }
 
-void gr_free (/*@out@*/ /*@only@*/struct group *grent)
+void gr_free_members (struct group *grent)
 {
-       free (grent->gr_name);
-       if (NULL != grent->gr_passwd) {
-               memzero (grent->gr_passwd, strlen (grent->gr_passwd));
-               free (grent->gr_passwd);
-       }
        if (NULL != grent->gr_mem) {
                size_t i;
                for (i = 0; NULL != grent->gr_mem[i]; i++) {
                        free (grent->gr_mem[i]);
                }
                free (grent->gr_mem);
+               grent->gr_mem = NULL;
        }
+}
+
+void gr_free (/*@out@*/ /*@only@*/struct group *grent)
+{
+       free (grent->gr_name);
+       if (NULL != grent->gr_passwd) {
+               memzero (grent->gr_passwd, strlen (grent->gr_passwd));
+               free (grent->gr_passwd);
+       }
+       gr_free_members(grent);
        free (grent);
 }
 
+bool gr_append_member(struct group *grp, char *member)
+{
+       int i;
+
+       if (NULL == grp->gr_mem || grp->gr_mem[0] == NULL) {
+               grp->gr_mem = (char **)malloc(2 * sizeof(char *));
+               if (!grp->gr_mem) {
+                       return false;
+               }
+               grp->gr_mem[0] = strdup(member);
+               if (!grp->gr_mem[0]) {
+                       return false;
+               }
+               grp->gr_mem[1] = NULL;
+               return true;
+       }
+
+       for (i = 0; grp->gr_mem[i]; i++) ;
+       grp->gr_mem = realloc(grp->gr_mem, (i + 2) * sizeof(char *));
+       if (NULL == grp->gr_mem) {
+               return false;
+       }
+       grp->gr_mem[i] = strdup(member);
+       if (NULL == grp->gr_mem[i]) {
+               return false;
+       }
+       grp->gr_mem[i + 1] = NULL;
+       return true;
+}
index 90651fb915ea5f702521cf3c4c4b02d68e5adf22..53d991fea6aacabfd6148796becc97ef5bee5a2a 100644 (file)
@@ -206,7 +206,9 @@ extern void __gr_set_changed (void);
 
 /* groupmem.c */
 extern /*@null@*/ /*@only@*/struct group *__gr_dup (const struct group *grent);
+extern void gr_free_members (struct group *grent);
 extern void gr_free (/*@out@*/ /*@only@*/struct group *grent);
+extern bool gr_append_member (struct group *grp, char *member);
 
 /* hushed.c */
 extern bool hushed (const char *username);
index 1e58f093cab3027aef47a960945fb10654be253b..f838c91e65767f8de86009644f64a8baa8781516 100644 (file)
          </para>
        </listitem>
       </varlistentry>
+      <varlistentry>
+       <term>
+         <option>-U</option>, <option>--users</option>
+       </term>
+       <listitem>
+         <para>
+           A list of usernames to add as members of the group.
+         </para>
+         <para>
+           The default behavior (if the <option>-g</option>,
+           <option>-N</option>, and <option>-U</option> options are not
+           specified) is defined by the <option>USERGROUPS_ENAB</option>
+           variable in <filename>/etc/login.defs</filename>.
+         </para>
+       </listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 
index b381c33a79d799c2d3a1a6d931c506d9ad9fde65..792332735c3837ee4017b60b0b3efa07f8282c5c 100644 (file)
     </para>
     <variablelist remap='IP'>
       <varlistentry>
+       <term>
+         <option>-a</option>, <option>--append</option>&nbsp;<replaceable>GID</replaceable>
+       </term>
+       <listitem>
+      <para>If group members are specified with -U, append them to the existing
+            member list, rather than replacing it.</para>
+    </listitem>
+    </varlistentry>
+    <varlistentry>
        <term>
          <option>-g</option>, <option>--gid</option>&nbsp;<replaceable>GID</replaceable>
        </term>
          </para>
        </listitem>
       </varlistentry>
+      <varlistentry>
+       <term>
+         <option>-U</option>, <option>--users</option>
+       </term>
+       <listitem>
+         <para>
+           A list of usernames to add as members of the group.
+         </para>
+         <para>
+           The default behavior (if the <option>-g</option>,
+           <option>-N</option>, and <option>-U</option> options are not
+           specified) is defined by the <option>USERGROUPS_ENAB</option>
+           variable in <filename>/etc/login.defs</filename>.
+         </para>
+       </listitem>
+      </varlistentry>
     </variablelist>
   </refsect1>
 
index 2dd8eec9e4eff8c204e8c9ccf79a10de393d0ba6..fa75c7f71ff90b5b4884550a700fc49b212c308f 100644 (file)
@@ -79,6 +79,7 @@ static /*@null@*/char *group_passwd;
 static /*@null@*/char *empty_list = NULL;
 
 static const char *prefix = "";
+static char *user_list;
 
 static bool oflg = false;      /* permit non-unique group ID to be specified with -g */
 static bool gflg = false;      /* ID value for the new group */
@@ -126,7 +127,8 @@ static /*@noreturn@*/void usage (int status)
        (void) fputs (_("  -p, --password PASSWORD       use this encrypted password for the new group\n"), usageout);
        (void) fputs (_("  -r, --system                  create a system account\n"), usageout);
        (void) fputs (_("  -R, --root CHROOT_DIR         directory to chroot into\n"), usageout);
-       (void) fputs (_("  -P, --prefix PREFIX_DIR       directory prefix\n"), usageout);
+       (void) fputs (_("  -P, --prefix PREFIX_DI        directory prefix\n"), usageout);
+       (void) fputs (_("  -U, --users USERS             list of user members of this group\n"), usageout);
        (void) fputs ("\n", usageout);
        exit (status);
 }
@@ -207,6 +209,19 @@ static void grp_update (void)
        }
 #endif                         /* SHADOWGRP */
 
+       if (user_list) {
+               char *token;
+               token = strtok(user_list, ",");
+               while (token) {
+                       if (prefix_getpwnam (token) == NULL) {
+                               fprintf (stderr, _("Invalid member username %s\n"), token);
+                               exit (E_GRP_UPDATE);
+                       }
+                       grp.gr_mem = add_list(grp.gr_mem, token);
+                       token = strtok(NULL, ",");
+               }
+       }
+
        /*
         * Write out the new group file entry.
         */
@@ -391,10 +406,11 @@ static void process_flags (int argc, char **argv)
                {"system",     no_argument,       NULL, 'r'},
                {"root",       required_argument, NULL, 'R'},
                {"prefix",     required_argument, NULL, 'P'},
+               {"users",      required_argument, NULL, 'U'},
                {NULL, 0, NULL, '\0'}
        };
 
-       while ((c = getopt_long (argc, argv, "fg:hK:op:rR:P:",
+       while ((c = getopt_long (argc, argv, "fg:hK:op:rR:P:U:",
                                 long_options, NULL)) != -1) {
                switch (c) {
                case 'f':
@@ -453,6 +469,9 @@ static void process_flags (int argc, char **argv)
                        break;
                case 'P': /* no-op, handled in process_prefix_flag () */
                        break;
+               case 'U':
+                       user_list = optarg;
+                       break;
                default:
                        usage (E_USAGE);
                }
index 1dca5fc9c22bbddb57dd71c4b276947cb861d657..e64ae3e5ab7b9452c7204fd7944b34fe31f746f4 100644 (file)
@@ -87,6 +87,7 @@ static gid_t group_id;
 static gid_t group_newid;
 
 static const char* prefix = "";
+static char *user_list;
 
 static struct cleanup_info_mod info_passwd;
 static struct cleanup_info_mod info_group;
@@ -95,6 +96,7 @@ static struct cleanup_info_mod info_gshadow;
 #endif
 
 static bool
+    aflg = false,               /* append -U members rather than replace them */
     oflg = false,              /* permit non-unique group ID to be specified with -g */
     gflg = false,              /* new ID value for the group */
     nflg = false,              /* a new name has been specified for the group */
@@ -117,6 +119,7 @@ static void open_files (void);
 static void close_files (void);
 static void update_primary_groups (gid_t ogid, gid_t ngid);
 
+
 /*
  * usage - display usage message and exit
  */
@@ -129,6 +132,8 @@ static void usage (int status)
                          "\n"
                          "Options:\n"),
                        Prog);
+       (void) fputs (_("  -a, --append                  append the users mentioned by -U option to the group \n"
+                       "                                without removing existing user members\n"), usageout);
        (void) fputs (_("  -g, --gid GID                 change the group ID to GID\n"), usageout);
        (void) fputs (_("  -h, --help                    display this help message and exit\n"), usageout);
        (void) fputs (_("  -n, --new-name NEW_GROUP      change the name to NEW_GROUP\n"), usageout);
@@ -137,6 +142,7 @@ static void usage (int status)
                        "                                PASSWORD\n"), usageout);
        (void) fputs (_("  -R, --root CHROOT_DIR         directory to chroot into\n"), usageout);
        (void) fputs (_("  -P, --prefix PREFIX_DIR       prefix directory where are located the /etc/* files\n"), usageout);
+       (void) fputs (_("  -U, --users USERS             list of user members of this group\n"), usageout);
        (void) fputs ("\n", usageout);
        exit (status);
 }
@@ -255,6 +261,32 @@ static void grp_update (void)
                update_primary_groups (ogrp->gr_gid, group_newid);
        }
 
+       if (user_list) {
+               char *token;
+
+               if (!aflg) {
+                       // requested to replace the existing groups
+                       if (NULL != grp.gr_mem[0])
+                               gr_free_members(&grp);
+                       grp.gr_mem = (char **)xmalloc(sizeof(char *));
+                       grp.gr_mem[0] = (char *)0;
+               } else {
+                       // append to existing groups
+                       if (NULL != grp.gr_mem[0])
+                               grp.gr_mem = dup_list (grp.gr_mem);
+               }
+
+               token = strtok(user_list, ",");
+               while (token) {
+                       if (prefix_getpwnam (token) == NULL) {
+                               fprintf (stderr, _("Invalid member username %s\n"), token);
+                               exit (E_GRP_UPDATE);
+                       }
+                       grp.gr_mem = add_list(grp.gr_mem, token);
+                       token = strtok(NULL, ",");
+               }
+       }
+
        /*
         * Write out the new group file entry.
         */
@@ -379,6 +411,7 @@ static void process_flags (int argc, char **argv)
 {
        int c;
        static struct option long_options[] = {
+               {"append",     no_argument,       NULL, 'a'},
                {"gid",        required_argument, NULL, 'g'},
                {"help",       no_argument,       NULL, 'h'},
                {"new-name",   required_argument, NULL, 'n'},
@@ -386,11 +419,15 @@ static void process_flags (int argc, char **argv)
                {"password",   required_argument, NULL, 'p'},
                {"root",       required_argument, NULL, 'R'},
                {"prefix",     required_argument, NULL, 'P'},
+               {"users",      required_argument, NULL, 'U'},
                {NULL, 0, NULL, '\0'}
        };
-       while ((c = getopt_long (argc, argv, "g:hn:op:R:P:",
+       while ((c = getopt_long (argc, argv, "ag:hn:op:R:P:U:",
                                 long_options, NULL)) != -1) {
                switch (c) {
+               case 'a':
+                       aflg = true;
+                       break;
                case 'g':
                        gflg = true;
                        if (   (get_gid (optarg, &group_newid) == 0)
@@ -419,6 +456,9 @@ static void process_flags (int argc, char **argv)
                        break;
                case 'P': /* no-op, handled in process_prefix_flag () */
                        break;
+               case 'U':
+                       user_list = optarg;
+                       break;
                default:
                        usage (E_USAGE);
                }