| /* vi: set sw=4 ts=4: */ |
| /* |
| * deluser/delgroup implementation for busybox |
| * |
| * Copyright (C) 1999 by Lineo, inc. and John Beppu |
| * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org> |
| * Copyright (C) 2007 by Tito Ragusa <farmatito@tiscali.it> |
| * |
| * Licensed under GPLv2, see file LICENSE in this source tree. |
| */ |
| //config:config DELUSER |
| //config: bool "deluser (9.1 kb)" |
| //config: default y |
| //config: help |
| //config: Utility for deleting a user account. |
| //config: |
| //config:config DELGROUP |
| //config: bool "delgroup (6.4 kb)" |
| //config: default y |
| //config: help |
| //config: Utility for deleting a group account. |
| //config: |
| //config:config FEATURE_DEL_USER_FROM_GROUP |
| //config: bool "Support removing users from groups" |
| //config: default y |
| //config: depends on DELGROUP |
| //config: help |
| //config: If called with two non-option arguments, deluser |
| //config: or delgroup will remove an user from a specified group. |
| |
| // APPLET_NOEXEC:name main location suid_type help |
| //applet:IF_DELUSER( APPLET_NOEXEC(deluser, deluser, BB_DIR_USR_SBIN, BB_SUID_DROP, deluser)) |
| //applet:IF_DELGROUP(APPLET_NOEXEC(delgroup, deluser, BB_DIR_USR_SBIN, BB_SUID_DROP, delgroup)) |
| |
| //kbuild:lib-$(CONFIG_DELUSER) += deluser.o |
| //kbuild:lib-$(CONFIG_DELGROUP) += deluser.o |
| |
| //usage:#define deluser_trivial_usage |
| //usage: IF_LONG_OPTS("[--remove-home] ") "USER" |
| //usage:#define deluser_full_usage "\n\n" |
| //usage: "Delete USER from the system" |
| // --remove-home is self-explanatory enough to put it in --help |
| |
| //usage:#define delgroup_trivial_usage |
| //usage: IF_FEATURE_DEL_USER_FROM_GROUP("[USER] ")"GROUP" |
| //usage:#define delgroup_full_usage "\n\n" |
| //usage: "Delete group GROUP from the system" |
| //usage: IF_FEATURE_DEL_USER_FROM_GROUP(" or user USER from group GROUP") |
| |
| #include "libbb.h" |
| |
| int deluser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
| int deluser_main(int argc, char **argv) |
| { |
| /* User or group name */ |
| char *name; |
| /* Username (non-NULL only in "delgroup USER GROUP" case) */ |
| char *member; |
| /* Name of passwd or group file */ |
| const char *pfile; |
| /* Name of shadow or gshadow file */ |
| const char *sfile; |
| /* Are we deluser or delgroup? */ |
| int do_deluser = (ENABLE_DELUSER && (!ENABLE_DELGROUP || applet_name[3] == 'u')); |
| |
| #if !ENABLE_LONG_OPTS |
| const int opt_delhome = 0; |
| #else |
| int opt_delhome = 0; |
| if (do_deluser) { |
| opt_delhome = getopt32long(argv, "", |
| "remove-home\0" No_argument "\xff"); |
| argv += opt_delhome; |
| argc -= opt_delhome; |
| } |
| #endif |
| |
| if (geteuid() != 0) |
| bb_simple_error_msg_and_die(bb_msg_perm_denied_are_you_root); |
| |
| name = argv[1]; |
| member = NULL; |
| |
| switch (argc) { |
| case 3: |
| if (!ENABLE_FEATURE_DEL_USER_FROM_GROUP || do_deluser) |
| break; |
| /* It's "delgroup USER GROUP" */ |
| member = name; |
| name = argv[2]; |
| /* Fallthrough */ |
| |
| case 2: |
| if (do_deluser) { |
| /* "deluser USER" */ |
| struct passwd *pw; |
| |
| pw = xgetpwnam(name); /* bail out if USER is wrong */ |
| pfile = bb_path_passwd_file; |
| if (ENABLE_FEATURE_SHADOWPASSWDS) |
| sfile = bb_path_shadow_file; |
| if (opt_delhome) { |
| struct stat st; |
| |
| /* Make sure home is an actual directory before |
| * removing it (e.g. users with /dev/null as home) */ |
| if (stat(pw->pw_dir, &st) == 0 && S_ISDIR(st.st_mode)) |
| remove_file(pw->pw_dir, FILEUTILS_RECUR); |
| } |
| } else { |
| struct group *gr; |
| do_delgroup: |
| /* "delgroup GROUP" or "delgroup USER GROUP" */ |
| if (do_deluser < 0) { /* delgroup after deluser? */ |
| gr = getgrnam(name); |
| if (!gr) |
| return EXIT_SUCCESS; |
| } else { |
| gr = xgetgrnam(name); /* bail out if GROUP is wrong */ |
| } |
| if (!member) { |
| /* "delgroup GROUP" */ |
| struct passwd *pw; |
| /* Check if the group is in use */ |
| while ((pw = getpwent()) != NULL) { |
| if (pw->pw_gid == gr->gr_gid) |
| bb_error_msg_and_die("'%s' still has '%s' as their primary group!", |
| pw->pw_name, name); |
| } |
| //endpwent(); |
| } |
| pfile = bb_path_group_file; |
| if (ENABLE_FEATURE_SHADOWPASSWDS) |
| sfile = bb_path_gshadow_file; |
| } |
| |
| /* Modify pfile, then sfile */ |
| do { |
| if (update_passwd(pfile, name, NULL, member) == -1) |
| return EXIT_FAILURE; |
| if (ENABLE_FEATURE_SHADOWPASSWDS) { |
| pfile = sfile; |
| sfile = NULL; |
| } |
| } while (ENABLE_FEATURE_SHADOWPASSWDS && pfile); |
| |
| if (do_deluser > 0) { |
| /* Delete user from all groups */ |
| if (update_passwd(bb_path_group_file, NULL, NULL, name) == -1) |
| return EXIT_FAILURE; |
| |
| if (ENABLE_DELGROUP) { |
| /* "deluser USER" also should try to delete |
| * same-named group. IOW: do "delgroup USER" |
| */ |
| // On debian deluser is a perl script that calls userdel. |
| // From man userdel: |
| // If USERGROUPS_ENAB is defined to yes in /etc/login.defs, userdel will |
| // delete the group with the same name as the user. |
| do_deluser = -1; |
| goto do_delgroup; |
| } |
| } |
| return EXIT_SUCCESS; |
| } |
| /* Reached only if number of command line args is wrong */ |
| bb_show_usage(); |
| } |