blob: 73fc1b864d2ab2ae499acd9d74903d86d5750f84
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 | //config:config DELUSER |
12 | //config: bool "deluser" |
13 | //config: default y |
14 | //config: help |
15 | //config: Utility for deleting a user account. |
16 | //config: |
17 | //config:config DELGROUP |
18 | //config: bool "delgroup" |
19 | //config: default y |
20 | //config: help |
21 | //config: Utility for deleting a group account. |
22 | //config: |
23 | //config:config FEATURE_DEL_USER_FROM_GROUP |
24 | //config: bool "Support for removing users from groups" |
25 | //config: default y |
26 | //config: depends on DELGROUP |
27 | //config: help |
28 | //config: If called with two non-option arguments, deluser |
29 | //config: or delgroup will remove an user from a specified group. |
30 | |
31 | //applet:IF_DELUSER(APPLET(deluser, BB_DIR_USR_SBIN, BB_SUID_DROP)) |
32 | //applet:IF_DELGROUP(APPLET_ODDNAME(delgroup, deluser, BB_DIR_USR_SBIN, BB_SUID_DROP, delgroup)) |
33 | |
34 | //kbuild:lib-$(CONFIG_DELUSER) += deluser.o |
35 | //kbuild:lib-$(CONFIG_DELGROUP) += deluser.o |
36 | |
37 | //usage:#define deluser_trivial_usage |
38 | //usage: IF_LONG_OPTS("[--remove-home] ") "USER" |
39 | //usage:#define deluser_full_usage "\n\n" |
40 | //usage: "Delete USER from the system" |
41 | // --remove-home is self-explanatory enough to put it in --help |
42 | |
43 | //usage:#define delgroup_trivial_usage |
44 | //usage: IF_FEATURE_DEL_USER_FROM_GROUP("[USER] ")"GROUP" |
45 | //usage:#define delgroup_full_usage "\n\n" |
46 | //usage: "Delete group GROUP from the system" |
47 | //usage: IF_FEATURE_DEL_USER_FROM_GROUP(" or user USER from group GROUP") |
48 | |
49 | #include "libbb.h" |
50 | |
51 | int deluser_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
52 | int deluser_main(int argc, char **argv) |
53 | { |
54 | /* User or group name */ |
55 | char *name; |
56 | /* Username (non-NULL only in "delgroup USER GROUP" case) */ |
57 | char *member; |
58 | /* Name of passwd or group file */ |
59 | const char *pfile; |
60 | /* Name of shadow or gshadow file */ |
61 | const char *sfile; |
62 | /* Are we deluser or delgroup? */ |
63 | int do_deluser = (ENABLE_DELUSER && (!ENABLE_DELGROUP || applet_name[3] == 'u')); |
64 | |
65 | #if !ENABLE_LONG_OPTS |
66 | const int opt_delhome = 0; |
67 | #else |
68 | int opt_delhome = 0; |
69 | if (do_deluser) { |
70 | applet_long_options = |
71 | "remove-home\0" No_argument "\xff"; |
72 | opt_delhome = getopt32(argv, ""); |
73 | argv += opt_delhome; |
74 | argc -= opt_delhome; |
75 | } |
76 | #endif |
77 | |
78 | if (geteuid() != 0) |
79 | bb_error_msg_and_die("%s", bb_msg_perm_denied_are_you_root); |
80 | |
81 | name = argv[1]; |
82 | member = NULL; |
83 | |
84 | switch (argc) { |
85 | case 3: |
86 | if (!ENABLE_FEATURE_DEL_USER_FROM_GROUP || do_deluser) |
87 | break; |
88 | /* It's "delgroup USER GROUP" */ |
89 | member = name; |
90 | name = argv[2]; |
91 | /* Fallthrough */ |
92 | |
93 | case 2: |
94 | if (do_deluser) { |
95 | /* "deluser USER" */ |
96 | struct passwd *pw; |
97 | |
98 | pw = xgetpwnam(name); /* bail out if USER is wrong */ |
99 | pfile = bb_path_passwd_file; |
100 | if (ENABLE_FEATURE_SHADOWPASSWDS) |
101 | sfile = bb_path_shadow_file; |
102 | if (opt_delhome) |
103 | remove_file(pw->pw_dir, FILEUTILS_RECUR); |
104 | } else { |
105 | struct group *gr; |
106 | do_delgroup: |
107 | /* "delgroup GROUP" or "delgroup USER GROUP" */ |
108 | if (do_deluser < 0) { /* delgroup after deluser? */ |
109 | gr = getgrnam(name); |
110 | if (!gr) |
111 | return EXIT_SUCCESS; |
112 | } else { |
113 | gr = xgetgrnam(name); /* bail out if GROUP is wrong */ |
114 | } |
115 | if (!member) { |
116 | /* "delgroup GROUP" */ |
117 | struct passwd *pw; |
118 | /* Check if the group is in use */ |
119 | while ((pw = getpwent()) != NULL) { |
120 | if (pw->pw_gid == gr->gr_gid) |
121 | bb_error_msg_and_die("'%s' still has '%s' as their primary group!", |
122 | pw->pw_name, name); |
123 | } |
124 | //endpwent(); |
125 | } |
126 | pfile = bb_path_group_file; |
127 | if (ENABLE_FEATURE_SHADOWPASSWDS) |
128 | sfile = bb_path_gshadow_file; |
129 | } |
130 | |
131 | /* Modify pfile, then sfile */ |
132 | do { |
133 | if (update_passwd(pfile, name, NULL, member) == -1) |
134 | return EXIT_FAILURE; |
135 | if (ENABLE_FEATURE_SHADOWPASSWDS) { |
136 | pfile = sfile; |
137 | sfile = NULL; |
138 | } |
139 | } while (ENABLE_FEATURE_SHADOWPASSWDS && pfile); |
140 | |
141 | if (do_deluser > 0) { |
142 | /* Delete user from all groups */ |
143 | if (update_passwd(bb_path_group_file, NULL, NULL, name) == -1) |
144 | return EXIT_FAILURE; |
145 | |
146 | if (ENABLE_DELGROUP) { |
147 | /* "deluser USER" also should try to delete |
148 | * same-named group. IOW: do "delgroup USER" |
149 | */ |
150 | // On debian deluser is a perl script that calls userdel. |
151 | // From man userdel: |
152 | // If USERGROUPS_ENAB is defined to yes in /etc/login.defs, userdel will |
153 | // delete the group with the same name as the user. |
154 | do_deluser = -1; |
155 | goto do_delgroup; |
156 | } |
157 | } |
158 | return EXIT_SUCCESS; |
159 | } |
160 | /* Reached only if number of command line args is wrong */ |
161 | bb_show_usage(); |
162 | } |
163 |