I've noticed that most major utilities that add and change users do so directly, often in different ways. The functions you can use to modify the passwd and shadow files are exposed in <pwd.h>
and in <sys/types.h>
, and they're part of glibc.
fgetpwent, getpwnam, getpw, getpwent_r, putpwent, setpwent
We can look into how busybox (via TinyLogin) does it, as an example. In busybox/loginutils/adduser.c
, they put a user in the passwd file by building the passwd structure and then call putpwent
. For adding the user's password in the shadow file, they simply call fprintf
and write the string directly.
For authenticating users the modern way, there's Linux-PAM. But as far as adding users, you can see in pam_unix_passwd.c that they call unix_update_db(), which calls various functions in libpwdb, which you'd have to add as a dependency to your project if you use it.
That being said, I'm guilty of having written a couple utilities to parse the passwd and shadow databases and modify them directly. It worked fine, but this was on an embedded system where I could tightly control everything. I didn't have to worry about things like race conditions with other programs modifying the passwd db.
If you need to add a group, same goes for the group database.