deluser: also remove user from /etc/group
[oweals/busybox.git] / loginutils / deluser.c
1 /* vi: set sw=4 ts=4: */
2 /*
3  * deluser/delgroup implementation for busybox
4  *
5  * Copyright (C) 1999 by Lineo, inc. and John Beppu
6  * Copyright (C) 1999,2000,2001 by John Beppu <beppu@codepoet.org>
7  * Copyright (C) 2007 by Tito Ragusa <farmatito@tiscali.it>
8  *
9  * Licensed under GPLv2, see file LICENSE in this source tree.
10  *
11  */
12
13 //usage:#define deluser_trivial_usage
14 //usage:       IF_LONG_OPTS("[--remove-home] ") "USER"
15 //usage:#define deluser_full_usage "\n\n"
16 //usage:       "Delete USER from the system"
17 //      --remove-home is self-explanatory enough to put it in --help
18
19 //usage:#define delgroup_trivial_usage
20 //usage:        IF_FEATURE_DEL_USER_FROM_GROUP("[USER] ")"GROUP"
21 //usage:#define delgroup_full_usage "\n\n"
22 //usage:       "Delete group GROUP from the system"
23 //usage:        IF_FEATURE_DEL_USER_FROM_GROUP(" or user USER from group GROUP")
24
25 #include "libbb.h"
26
27 int deluser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
28 int deluser_main(int argc, char **argv)
29 {
30         /* User or group name */
31         char *name;
32         /* Username (non-NULL only in "delgroup USER GROUP" case) */
33         char *member;
34         /* Name of passwd or group file */
35         const char *pfile;
36         /* Name of shadow or gshadow file */
37         const char *sfile;
38         /* Are we deluser or delgroup? */
39         int do_deluser = (ENABLE_DELUSER && (!ENABLE_DELGROUP || applet_name[3] == 'u'));
40
41 #if !ENABLE_LONG_OPTS
42         const int opt_delhome = 0;
43 #else
44         int opt_delhome = 0;
45         if (do_deluser) {
46                 applet_long_options =
47                         "remove-home\0" No_argument "\xff";
48                 opt_delhome = getopt32(argv, "");
49                 argv += opt_delhome;
50                 argc -= opt_delhome;
51         }
52 #endif
53
54         if (geteuid() != 0)
55                 bb_error_msg_and_die(bb_msg_perm_denied_are_you_root);
56
57         name = argv[1];
58         member = NULL;
59
60         switch (argc) {
61         case 3:
62                 if (!ENABLE_FEATURE_DEL_USER_FROM_GROUP || do_deluser)
63                         break;
64                 /* It's "delgroup USER GROUP" */
65                 member = name;
66                 name = argv[2];
67                 /* Fallthrough */
68
69         case 2:
70                 if (do_deluser) {
71                         /* "deluser USER" */
72                         struct passwd *pw;
73
74                         pw = xgetpwnam(name); /* bail out if USER is wrong */
75                         pfile = bb_path_passwd_file;
76                         if (ENABLE_FEATURE_SHADOWPASSWDS)
77                                 sfile = bb_path_shadow_file;
78                         if (opt_delhome)
79                                 remove_file(pw->pw_dir, FILEUTILS_RECUR);
80                 } else {
81                         struct group *gr;
82  do_delgroup:
83                         /* "delgroup GROUP" or "delgroup USER GROUP" */
84                         if (do_deluser < 0) { /* delgroup after deluser? */
85                                 gr = getgrnam(name);
86                                 if (!gr)
87                                         return EXIT_SUCCESS;
88                         } else {
89                                 gr = xgetgrnam(name); /* bail out if GROUP is wrong */
90                         }
91                         if (!member) {
92                                 /* "delgroup GROUP" */
93                                 struct passwd *pw;
94                                 /* Check if the group is in use */
95                                 while ((pw = getpwent()) != NULL) {
96                                         if (pw->pw_gid == gr->gr_gid)
97                                                 bb_error_msg_and_die("'%s' still has '%s' as their primary group!",
98                                                         pw->pw_name, name);
99                                 }
100                                 //endpwent();
101                         }
102                         pfile = bb_path_group_file;
103                         if (ENABLE_FEATURE_SHADOWPASSWDS)
104                                 sfile = bb_path_gshadow_file;
105                 }
106
107                 /* Modify pfile, then sfile */
108                 do {
109                         if (update_passwd(pfile, name, NULL, member) == -1)
110                                 return EXIT_FAILURE;
111                         if (ENABLE_FEATURE_SHADOWPASSWDS) {
112                                 pfile = sfile;
113                                 sfile = NULL;
114                         }
115                 } while (ENABLE_FEATURE_SHADOWPASSWDS && pfile);
116
117                 if (do_deluser > 0) {
118                         /* Delete user from all groups */
119                         if (update_passwd(bb_path_group_file, NULL, NULL, name) == -1)
120                                 return EXIT_FAILURE;
121
122                         if (ENABLE_DELGROUP) {
123                                 /* "deluser USER" also should try to delete
124                                  * same-named group. IOW: do "delgroup USER"
125                                  */
126 // On debian deluser is a perl script that calls userdel.
127 // From man userdel:
128 //  If USERGROUPS_ENAB is defined to yes in /etc/login.defs, userdel will
129 //  delete the group with the same name as the user.
130                                 do_deluser = -1;
131                                 goto do_delgroup;
132                         }
133                 }
134                 return EXIT_SUCCESS;
135         }
136         /* Reached only if number of command line args is wrong */
137         bb_show_usage();
138 }