diff --git a/lib/addgrps.c b/lib/addgrps.c index 6ab34dcb31..b90828e1e2 100644 --- a/lib/addgrps.c +++ b/lib/addgrps.c @@ -24,6 +24,7 @@ #include "shadow/grp/agetgroups.h" #include "shadowlog.h" #include "string/strchr/strchrscnt.h" +#include "string/strcmp/streq.h" #include "string/strerrno.h" @@ -35,7 +36,7 @@ int add_groups(const char *list) { - char *g, *p, *dup; + char *dup; FILE *shadow_logfd = log_get_logfd(); gid_t *gids; size_t n; @@ -48,20 +49,25 @@ add_groups(const char *list) if (gids == NULL) return -1; - p = dup = strdup(list); + dup = strdup(list); if (dup == NULL) goto free_gids; - while (NULL != (g = strsep(&p, ",:"))) { - struct group *grp; + if (!streq(dup, "")) { + char *g, *p; - grp = getgrnam(g); /* local, no need for xgetgrnam */ - if (NULL == grp) { - fprintf(shadow_logfd, _("Warning: unknown group %s\n"), g); - continue; - } + p = dup; + while (NULL != (g = strsep(&p, ",:"))) { + struct group *grp; + + grp = getgrnam(g); /* local, no need for xgetgrnam */ + if (NULL == grp) { + fprintf(shadow_logfd, _("Warning: unknown group %s\n"), g); + continue; + } - LSEARCH(gid_t, &grp->gr_gid, gids, &n); + LSEARCH(gid_t, &grp->gr_gid, gids, &n); + } } free(dup); diff --git a/src/groupadd.c b/src/groupadd.c index 7bb946b3c1..fab8111b4a 100644 --- a/src/groupadd.c +++ b/src/groupadd.c @@ -40,6 +40,7 @@ #include "shadow/gshadow/sgrp.h" #include "shadowlog.h" #include "string/memset/memzero.h" +#include "string/strcmp/streq.h" #include "string/strerrno.h" #include "string/strtok/stpsep.h" @@ -217,7 +218,7 @@ grp_update(void) } #endif /* SHADOWGRP */ - if (user_list) { + if (user_list && !streq(user_list, "")) { char *u, *ul; ul = user_list; diff --git a/src/groupmod.c b/src/groupmod.c index 22d07fe69b..c29f905088 100644 --- a/src/groupmod.c +++ b/src/groupmod.c @@ -259,8 +259,6 @@ grp_update(void) } if (user_list) { - char *u, *ul; - if (!aflg) { // requested to replace the existing groups grp.gr_mem = xmalloc_T(1, char *); @@ -282,18 +280,22 @@ grp_update(void) } #endif /* SHADOWGRP */ - ul = user_list; - while (NULL != (u = strsep(&ul, ","))) { - if (prefix_getpwnam(u) == NULL) { - fprintf(stderr, _("Invalid member username %s\n"), u); - exit (E_GRP_UPDATE); - } + if (!streq(user_list, "")) { + char *u, *ul; - grp.gr_mem = add_list(grp.gr_mem, u); + ul = user_list; + while (NULL != (u = strsep(&ul, ","))) { + if (prefix_getpwnam(u) == NULL) { + fprintf(stderr, _("Invalid member username %s\n"), u); + exit(E_GRP_UPDATE); + } + + grp.gr_mem = add_list(grp.gr_mem, u); #ifdef SHADOWGRP - if (NULL != osgrp) - sgrp.sg_mem = add_list(sgrp.sg_mem, u); + if (NULL != osgrp) + sgrp.sg_mem = add_list(sgrp.sg_mem, u); #endif /* SHADOWGRP */ + } } } diff --git a/tests/system/tests/test_groupadd.py b/tests/system/tests/test_groupadd.py index a979919de4..b46621b6ec 100644 --- a/tests/system/tests/test_groupadd.py +++ b/tests/system/tests/test_groupadd.py @@ -36,3 +36,33 @@ def test_groupadd__add_group(shadow: Shadow): assert gshadow_entry is not None, "Group should be found" assert gshadow_entry.name == "tgroup", "Incorrect groupname" assert gshadow_entry.password == "!", "Incorrect password" + + +@pytest.mark.topology(KnownTopology.Shadow) +def test_groupadd__u_option_empty_string_clears_members(shadow: Shadow): + """ + :title: Test groupadd -U option with empty user list + :setup: + 1. None required + :steps: + 1. Run groupadd with -U option and empty string parameter + 2. Verify group exists after creation + 3. Confirm group has no members + :expectedresults: + 1. groupadd -U '' command completes successfully + 2. Group entry is created and accessible + 3. Group member list is empty (no users assigned to group) + :customerscenario: False + """ + shadow.groupadd("-U '' tgroup") + + group_entry = shadow.tools.getent.group("tgroup") + assert group_entry is not None, "Group should be found" + assert group_entry.name == "tgroup", "Incorrect groupname" + assert not group_entry.members, "Group should have no members" + + if shadow.host.features["gshadow"]: + gshadow_entry = shadow.tools.getent.gshadow("tgroup") + assert gshadow_entry is not None, "Group should be found" + assert gshadow_entry.name == "tgroup", "Incorrect groupname" + assert not gshadow_entry.members, "Group should have no members" diff --git a/tests/system/tests/test_groupmod.py b/tests/system/tests/test_groupmod.py index 999ddc0cbf..6617602f5b 100644 --- a/tests/system/tests/test_groupmod.py +++ b/tests/system/tests/test_groupmod.py @@ -38,3 +38,34 @@ def test_groupmod__change_gid(shadow: Shadow): assert gshadow_entry is not None, "Group should be found" assert gshadow_entry.name == "tgroup", "Incorrect groupname" assert gshadow_entry.password == "!", "Incorrect password" + + +@pytest.mark.topology(KnownTopology.Shadow) +def test_groupmod__u_option_empty_string_clears_members(shadow: Shadow): + """ + :title: Test groupmod -U option with empty user list + :setup: + 1. Create test group + :steps: + 1. Run groupmod with -U option and empty string parameter + 2. Verify group exists after operation + 3. Confirm group has no members + :expectedresults: + 1. groupmod -U '' command completes successfully + 2. Group entry remains valid and accessible + 3. Group member list is empty (no users assigned to group) + :customerscenario: False + """ + shadow.groupadd("tgroup") + shadow.groupmod("-U '' tgroup") + + group_entry = shadow.tools.getent.group("tgroup") + assert group_entry is not None, "Group should be found" + assert group_entry.name == "tgroup", "Incorrect groupname" + assert not group_entry.members, "Group should have no members" + + if shadow.host.features["gshadow"]: + gshadow_entry = shadow.tools.getent.gshadow("tgroup") + assert gshadow_entry is not None, "Group should be found" + assert gshadow_entry.name == "tgroup", "Incorrect groupname" + assert not gshadow_entry.members, "Group should have no members"