diff --git a/lib/groupmem.c b/lib/groupmem.c
index 1fd1c135..2060d03b 100644
--- a/lib/groupmem.c
+++ b/lib/groupmem.c
@@ -87,6 +87,18 @@
return gr;
}
+void gr_free_members (struct group *grent)
+{
+ 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);
@@ -94,13 +106,36 @@ void gr_free (/*@out@*/ /*@only@*/struct group *grent)
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);
- }
+ 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;
+}
diff --git a/lib/prototypes.h b/lib/prototypes.h
index 90651fb9..53d991fe 100644
--- a/lib/prototypes.h
+++ b/lib/prototypes.h
@@ -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);
diff --git a/man/groupadd.8.xml b/man/groupadd.8.xml
index 1e58f093..f838c91e 100644
--- a/man/groupadd.8.xml
+++ b/man/groupadd.8.xml
@@ -229,6 +229,22 @@
+
+
+ ,
+
+
+
+ A list of usernames to add as members of the group.
+
+
+ The default behavior (if the ,
+ , and options are not
+ specified) is defined by the
+ variable in /etc/login.defs.
+
+
+
diff --git a/man/groupmod.8.xml b/man/groupmod.8.xml
index b381c33a..79233273 100644
--- a/man/groupmod.8.xml
+++ b/man/groupmod.8.xml
@@ -93,6 +93,15 @@
+
+ , GID
+
+
+ If group members are specified with -U, append them to the existing
+ member list, rather than replacing it.
+
+
+
, GID
@@ -203,6 +212,22 @@
+
+
+ ,
+
+
+
+ A list of usernames to add as members of the group.
+
+
+ The default behavior (if the ,
+ , and options are not
+ specified) is defined by the
+ variable in /etc/login.defs.
+
+
+
diff --git a/src/groupadd.c b/src/groupadd.c
index 2dd8eec9..fa75c7f7 100644
--- a/src/groupadd.c
+++ b/src/groupadd.c
@@ -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);
}
diff --git a/src/groupmod.c b/src/groupmod.c
index 1dca5fc9..e64ae3e5 100644
--- a/src/groupmod.c
+++ b/src/groupmod.c
@@ -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);
}