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);