diff --git a/AUTHORS.md b/AUTHORS.md index 97c709b21..32baf05e7 100644 --- a/AUTHORS.md +++ b/AUTHORS.md @@ -15,6 +15,7 @@ Aleksa Sarai Alexander O. Yuriev Algis Rudys Andreas Jaeger +Andy Zaugg Aniello Del Sorbo Anton Gluck Arkadiusz Miskiewicz diff --git a/man/usermod.8.xml b/man/usermod.8.xml index 79f1a5b8e..f8d9a9225 100644 --- a/man/usermod.8.xml +++ b/man/usermod.8.xml @@ -326,6 +326,17 @@ + + + , + + + + Remove the user from named supplementary group(s). Use only with the + option. + + + ,  CHROOT_DIR diff --git a/src/usermod.c b/src/usermod.c index 1069be1e1..4e0e88cf2 100644 --- a/src/usermod.c +++ b/src/usermod.c @@ -147,6 +147,7 @@ static bool mflg = false, /* create user's home directory if it doesn't exist */ oflg = false, /* permit non-unique user ID to be specified with -u */ pflg = false, /* new encrypted password */ + rflg = false, /* remove a user from a single group */ sflg = false, /* new shell program */ #ifdef WITH_SELINUX Zflg = false, /* new selinux user */ @@ -424,6 +425,9 @@ static /*@noreturn@*/void usage (int status) (void) fputs (_(" -a, --append append the user to the supplemental GROUPS\n" " mentioned by the -G option without removing\n" " the user from other groups\n"), usageout); + (void) fputs (_(" -r, --remove remove the user from only the supplemental GROUPS\n" + " mentioned by the -G option without removing\n" + " the user from other groups\n"), usageout); (void) fputs (_(" -h, --help display this help message and exit\n"), usageout); (void) fputs (_(" -l, --login NEW_LOGIN new value of the login name\n"), usageout); (void) fputs (_(" -L, --lock lock the user account\n"), usageout); @@ -751,6 +755,14 @@ static void update_group (void) continue; } + /* + * If rflg+Gflg is passed in AKA -rG invert is_member flag, which removes + * mentioned groups while leaving the others. + */ + if (Gflg && rflg && was_member) { + is_member = !is_member; + } + ngrp = __gr_dup (grp); if (NULL == ngrp) { fprintf (stderr, @@ -866,6 +878,14 @@ static void update_gshadow (void) continue; } + /* + * If rflg+Gflg is passed in AKA -rG invert is_member, to remove targeted + * groups while leaving the user apart of groups not mentioned + */ + if (Gflg && rflg && was_member) { + is_member = !is_member; + } + nsgrp = __sgr_dup (sgrp); if (NULL == nsgrp) { fprintf (stderr, @@ -1014,6 +1034,7 @@ static void process_flags (int argc, char **argv) {"move-home", no_argument, NULL, 'm'}, {"non-unique", no_argument, NULL, 'o'}, {"password", required_argument, NULL, 'p'}, + {"remove", no_argument, NULL, 'r'}, {"root", required_argument, NULL, 'R'}, {"prefix", required_argument, NULL, 'P'}, {"shell", required_argument, NULL, 's'}, @@ -1031,7 +1052,7 @@ static void process_flags (int argc, char **argv) {NULL, 0, NULL, '\0'} }; while ((c = getopt_long (argc, argv, - "abc:d:e:f:g:G:hl:Lmop:R:s:u:UP:" + "abc:d:e:f:g:G:hl:Lmop:rR:s:u:UP:" #ifdef ENABLE_SUBIDS "v:w:V:W:" #endif /* ENABLE_SUBIDS */ @@ -1141,6 +1162,9 @@ static void process_flags (int argc, char **argv) user_pass = optarg; pflg = true; break; + case 'r': + rflg = true; + break; case 'R': /* no-op, handled in process_root_flag () */ break; case 'P': /* no-op, handled in process_prefix_flag () */ @@ -1342,6 +1366,20 @@ static void process_flags (int argc, char **argv) usage (E_USAGE); } + if (rflg && (!Gflg)) { + fprintf (stderr, + _("%s: %s flag is only allowed with the %s flag\n"), + Prog, "-r", "-G"); + usage (E_USAGE); + } + + if (rflg && aflg) { + fprintf (stderr, + _("%s: %s and %s are mutually exclusive flags\n"), + Prog, "-r", "-a"); + usage (E_USAGE); + } + if ((Lflg && (pflg || Uflg)) || (pflg && Uflg)) { fprintf (stderr, _("%s: the -L, -p, and -U flags are exclusive\n"),