add -U option to groupadd and groupmod
Add a -U option which adds new usernames as members. For groupmod, also add -a (append), without which existing members are removed. Closes #265
This commit is contained in:
parent
7ea342579e
commit
342c934a35
@ -87,6 +87,18 @@
|
|||||||
return gr;
|
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)
|
void gr_free (/*@out@*/ /*@only@*/struct group *grent)
|
||||||
{
|
{
|
||||||
free (grent->gr_name);
|
free (grent->gr_name);
|
||||||
@ -94,13 +106,36 @@ void gr_free (/*@out@*/ /*@only@*/struct group *grent)
|
|||||||
memzero (grent->gr_passwd, strlen (grent->gr_passwd));
|
memzero (grent->gr_passwd, strlen (grent->gr_passwd));
|
||||||
free (grent->gr_passwd);
|
free (grent->gr_passwd);
|
||||||
}
|
}
|
||||||
if (NULL != grent->gr_mem) {
|
gr_free_members(grent);
|
||||||
size_t i;
|
|
||||||
for (i = 0; NULL != grent->gr_mem[i]; i++) {
|
|
||||||
free (grent->gr_mem[i]);
|
|
||||||
}
|
|
||||||
free (grent->gr_mem);
|
|
||||||
}
|
|
||||||
free (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;
|
||||||
|
}
|
||||||
|
@ -206,7 +206,9 @@ extern void __gr_set_changed (void);
|
|||||||
|
|
||||||
/* groupmem.c */
|
/* groupmem.c */
|
||||||
extern /*@null@*/ /*@only@*/struct group *__gr_dup (const struct group *grent);
|
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 void gr_free (/*@out@*/ /*@only@*/struct group *grent);
|
||||||
|
extern bool gr_append_member (struct group *grp, char *member);
|
||||||
|
|
||||||
/* hushed.c */
|
/* hushed.c */
|
||||||
extern bool hushed (const char *username);
|
extern bool hushed (const char *username);
|
||||||
|
@ -229,6 +229,22 @@
|
|||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</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>
|
</variablelist>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
@ -92,6 +92,15 @@
|
|||||||
are:
|
are:
|
||||||
</para>
|
</para>
|
||||||
<variablelist remap='IP'>
|
<variablelist remap='IP'>
|
||||||
|
<varlistentry>
|
||||||
|
<term>
|
||||||
|
<option>-a</option>, <option>--append</option> <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>
|
<varlistentry>
|
||||||
<term>
|
<term>
|
||||||
<option>-g</option>, <option>--gid</option> <replaceable>GID</replaceable>
|
<option>-g</option>, <option>--gid</option> <replaceable>GID</replaceable>
|
||||||
@ -203,6 +212,22 @@
|
|||||||
</para>
|
</para>
|
||||||
</listitem>
|
</listitem>
|
||||||
</varlistentry>
|
</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>
|
</variablelist>
|
||||||
</refsect1>
|
</refsect1>
|
||||||
|
|
||||||
|
@ -79,6 +79,7 @@ static /*@null@*/char *group_passwd;
|
|||||||
static /*@null@*/char *empty_list = NULL;
|
static /*@null@*/char *empty_list = NULL;
|
||||||
|
|
||||||
static const char *prefix = "";
|
static const char *prefix = "";
|
||||||
|
static char *user_list;
|
||||||
|
|
||||||
static bool oflg = false; /* permit non-unique group ID to be specified with -g */
|
static bool oflg = false; /* permit non-unique group ID to be specified with -g */
|
||||||
static bool gflg = false; /* ID value for the new group */
|
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 (_(" -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, --system create a system account\n"), usageout);
|
||||||
(void) fputs (_(" -R, --root CHROOT_DIR directory to chroot into\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);
|
(void) fputs ("\n", usageout);
|
||||||
exit (status);
|
exit (status);
|
||||||
}
|
}
|
||||||
@ -207,6 +209,19 @@ static void grp_update (void)
|
|||||||
}
|
}
|
||||||
#endif /* SHADOWGRP */
|
#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.
|
* Write out the new group file entry.
|
||||||
*/
|
*/
|
||||||
@ -391,10 +406,11 @@ static void process_flags (int argc, char **argv)
|
|||||||
{"system", no_argument, NULL, 'r'},
|
{"system", no_argument, NULL, 'r'},
|
||||||
{"root", required_argument, NULL, 'R'},
|
{"root", required_argument, NULL, 'R'},
|
||||||
{"prefix", required_argument, NULL, 'P'},
|
{"prefix", required_argument, NULL, 'P'},
|
||||||
|
{"users", required_argument, NULL, 'U'},
|
||||||
{NULL, 0, NULL, '\0'}
|
{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) {
|
long_options, NULL)) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 'f':
|
case 'f':
|
||||||
@ -453,6 +469,9 @@ static void process_flags (int argc, char **argv)
|
|||||||
break;
|
break;
|
||||||
case 'P': /* no-op, handled in process_prefix_flag () */
|
case 'P': /* no-op, handled in process_prefix_flag () */
|
||||||
break;
|
break;
|
||||||
|
case 'U':
|
||||||
|
user_list = optarg;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage (E_USAGE);
|
usage (E_USAGE);
|
||||||
}
|
}
|
||||||
|
@ -87,6 +87,7 @@ static gid_t group_id;
|
|||||||
static gid_t group_newid;
|
static gid_t group_newid;
|
||||||
|
|
||||||
static const char* prefix = "";
|
static const char* prefix = "";
|
||||||
|
static char *user_list;
|
||||||
|
|
||||||
static struct cleanup_info_mod info_passwd;
|
static struct cleanup_info_mod info_passwd;
|
||||||
static struct cleanup_info_mod info_group;
|
static struct cleanup_info_mod info_group;
|
||||||
@ -95,6 +96,7 @@ static struct cleanup_info_mod info_gshadow;
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
|
aflg = false, /* append -U members rather than replace them */
|
||||||
oflg = false, /* permit non-unique group ID to be specified with -g */
|
oflg = false, /* permit non-unique group ID to be specified with -g */
|
||||||
gflg = false, /* new ID value for the group */
|
gflg = false, /* new ID value for the group */
|
||||||
nflg = false, /* a new name has been specified 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 close_files (void);
|
||||||
static void update_primary_groups (gid_t ogid, gid_t ngid);
|
static void update_primary_groups (gid_t ogid, gid_t ngid);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* usage - display usage message and exit
|
* usage - display usage message and exit
|
||||||
*/
|
*/
|
||||||
@ -129,6 +132,8 @@ static void usage (int status)
|
|||||||
"\n"
|
"\n"
|
||||||
"Options:\n"),
|
"Options:\n"),
|
||||||
Prog);
|
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 (_(" -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 (_(" -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);
|
(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);
|
" PASSWORD\n"), usageout);
|
||||||
(void) fputs (_(" -R, --root CHROOT_DIR directory to chroot into\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 (_(" -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);
|
(void) fputs ("\n", usageout);
|
||||||
exit (status);
|
exit (status);
|
||||||
}
|
}
|
||||||
@ -255,6 +261,32 @@ static void grp_update (void)
|
|||||||
update_primary_groups (ogrp->gr_gid, group_newid);
|
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.
|
* Write out the new group file entry.
|
||||||
*/
|
*/
|
||||||
@ -379,6 +411,7 @@ static void process_flags (int argc, char **argv)
|
|||||||
{
|
{
|
||||||
int c;
|
int c;
|
||||||
static struct option long_options[] = {
|
static struct option long_options[] = {
|
||||||
|
{"append", no_argument, NULL, 'a'},
|
||||||
{"gid", required_argument, NULL, 'g'},
|
{"gid", required_argument, NULL, 'g'},
|
||||||
{"help", no_argument, NULL, 'h'},
|
{"help", no_argument, NULL, 'h'},
|
||||||
{"new-name", required_argument, NULL, 'n'},
|
{"new-name", required_argument, NULL, 'n'},
|
||||||
@ -386,11 +419,15 @@ static void process_flags (int argc, char **argv)
|
|||||||
{"password", required_argument, NULL, 'p'},
|
{"password", required_argument, NULL, 'p'},
|
||||||
{"root", required_argument, NULL, 'R'},
|
{"root", required_argument, NULL, 'R'},
|
||||||
{"prefix", required_argument, NULL, 'P'},
|
{"prefix", required_argument, NULL, 'P'},
|
||||||
|
{"users", required_argument, NULL, 'U'},
|
||||||
{NULL, 0, NULL, '\0'}
|
{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) {
|
long_options, NULL)) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
|
case 'a':
|
||||||
|
aflg = true;
|
||||||
|
break;
|
||||||
case 'g':
|
case 'g':
|
||||||
gflg = true;
|
gflg = true;
|
||||||
if ( (get_gid (optarg, &group_newid) == 0)
|
if ( (get_gid (optarg, &group_newid) == 0)
|
||||||
@ -419,6 +456,9 @@ static void process_flags (int argc, char **argv)
|
|||||||
break;
|
break;
|
||||||
case 'P': /* no-op, handled in process_prefix_flag () */
|
case 'P': /* no-op, handled in process_prefix_flag () */
|
||||||
break;
|
break;
|
||||||
|
case 'U':
|
||||||
|
user_list = optarg;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
usage (E_USAGE);
|
usage (E_USAGE);
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user