If /etc/usermgmt.conf has a line like:
group =uid
where a new user's group ID in the passwd file is the same as their
user ID, remove that group when the user is removed. The group is
only removed if it matches the login name, has a gid that matches
the user's uid, and has no other members.
This makes our userdel(8) behave more like the version on other
systems.
Opinions? This is something that has always bothered me and can
result in uid/gid mismatches if you remove a user, then re-add them
without removing the login group first.
Thoughts or strong opinions?
- todd
Index: usr.sbin/user/user.c
===================================================================
RCS file: /cvs/src/usr.sbin/user/user.c,v
retrieving revision 1.131
diff -u -p -u -r1.131 user.c
--- usr.sbin/user/user.c 18 May 2023 18:29:28 -0000 1.131
+++ usr.sbin/user/user.c 19 May 2023 16:16:02 -0000
@@ -193,7 +193,7 @@ static int is_local(char *, const char *
static int modify_gid(char *, char *);
static int moduser(char *, char *, user_t *);
static int removehomedir(const char *, uid_t, const char *);
-static int rm_user_from_groups(char *);
+static int rm_user_from_groups(char *, int);
static int save_range(user_t *, char *);
static int scantime(time_t *, char *);
static int setdefaults(user_t *);
@@ -1308,9 +1308,9 @@ adduser(char *login_name, user_t *up)
return 1;
}
-/* remove a user from the groups file */
+/* remove a user from the groups file, optionally removing the login group */
static int
-rm_user_from_groups(char *login_name)
+rm_user_from_groups(char *login_name, int rm_login_group)
{
struct stat st;
size_t login_len;
@@ -1366,6 +1366,15 @@ rm_user_from_groups(char *login_name)
warnx("Malformed entry `%s'. Skipping", buf);
continue;
}
+ if (rm_login_group && strncmp(buf, login_name, login_len) == 0
+ && buf[login_len] == ':') {
+ /* remove login group if empty or user is only member */
+ if (*cp == '\n')
+ continue;
+ if (strncmp(cp, login_name, login_len) == 0 &&
+ cp [login_len] == '\n')
+ continue;
+ }
while ((cp = strstr(cp, login_name)) != NULL) {
if ((cp[-1] == ':' || cp[-1] == ',') &&
(cp[login_len] == ',' || cp[login_len] == '\n')) {
@@ -1745,7 +1754,7 @@ moduser(char *login_name, char *newlogin
up->u_groupv[i]);
}
}
- if (!rm_user_from_groups(newlogin)) {
+ if (!rm_user_from_groups(newlogin, 0)) {
close(ptmpfd);
pw_abort();
errx(EXIT_FAILURE,
@@ -2101,8 +2110,10 @@ int
userdel(int argc, char **argv)
{
struct passwd *pwp;
+ struct group *grp;
user_t u;
int defaultfield;
+ int rm_login_group;
int rmhome;
int bigD;
int c;
@@ -2164,7 +2175,15 @@ userdel(int argc, char **argv)
openlog("userdel", LOG_PID, LOG_USER);
return moduser(*argv, *argv, &u) ? EXIT_SUCCESS : EXIT_FAILURE;
}
- if (!rm_user_from_groups(*argv)) {
+ rm_login_group = 0;
+ if (strcmp(u.u_primgrp, "=uid") == 0 && pwp->pw_uid == pwp->pw_gid) {
+ /* remove primary group if it matches the username */
+ grp = getgrgid(pwp->pw_gid);
+ if (grp != NULL && strcmp(grp->gr_name, *argv) == 0) {
+ rm_login_group = 1;
+ }
+ }
+ if (!rm_user_from_groups(*argv, rm_login_group)) {
return 0;
}
openlog("userdel", LOG_PID, LOG_USER);