One of the things that becomes a big issue for customers, especially when we move to automated build processes, is “how do you allow a user to add/remove users or groups, but NOT allow them to add ‘root-capable’ accounts, or elevate their own access?” As has been well discussed in other forums such as OWASP: https://cheatsheetseries.owasp.org/cheatsheets/Input_Validation_Cheat_Sheet.html - input validation is very difficult to do properly, especially if all you’re doing is checking “are these options included in the input?” A lot of customers will simply try to grep the options for dangerous flags or mis-uses, but as documented above, this is not safe - a re-implementation of the commandline parsing is typically required for security.
For a customer this month, we built a “pbuseradd” function that re-implements the “useradd” commandline validation, but adds protections such as “you cannot create a new backdoor root user”. One of the features we use to validate these backdoors is the Fedora/RedHat “/usr/share/doc/setup/uidgid” file which has all the pre-allocated UIDs and GIDs for those platforms (helping to ensure that users don’t add an account that conflicts with this file). For Ubuntu and non-Linux since the file doesn’t exist, there’s a simple “not less than uid/gid x” functionality that gets implemented instead.
You would use this by simply adding the following include to your PMUL policy, and then delegating users the ability to call “pbrun pbuseradd” instead of “pbrun useradd” (or whichever of the other 6 commands they need). After deciding that the user is allowed to do the pbuseradd, call the PBModUser() procedure just before your “accept;”
include pbusergroup.conf;
if ("canaddgroups" in groups || group == "canaddgroups") {
SetRunEnv("root", true);
PBModUser();
accept;
}