Line data Source code
1 : /*
2 : SSSD
3 :
4 : sss_userdel
5 :
6 : Copyright (C) Jakub Hrozek <jhrozek@redhat.com> 2009
7 :
8 : This program is free software; you can redistribute it and/or modify
9 : it under the terms of the GNU General Public License as published by
10 : the Free Software Foundation; either version 3 of the License, or
11 : (at your option) any later version.
12 :
13 : This program is distributed in the hope that it will be useful,
14 : but WITHOUT ANY WARRANTY; without even the implied warranty of
15 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 : GNU General Public License for more details.
17 :
18 : You should have received a copy of the GNU General Public License
19 : along with this program. If not, see <http://www.gnu.org/licenses/>.
20 : */
21 :
22 : #include <nss.h>
23 : #include <stdio.h>
24 : #include <stdlib.h>
25 : #include <talloc.h>
26 : #include <popt.h>
27 : #include <sys/types.h>
28 : #include <sys/wait.h>
29 :
30 : #include "db/sysdb.h"
31 : #include "util/util.h"
32 : #include "util/find_uid.h"
33 : #include "tools/tools_util.h"
34 : #include "tools/sss_sync_ops.h"
35 :
36 : #ifndef KILL_CMD
37 : #define KILL_CMD "killall"
38 : #endif
39 :
40 : #ifndef KILL_CMD_USER_FLAG
41 : #define KILL_CMD_USER_FLAG "-u"
42 : #endif
43 :
44 : #ifndef KILL_CMD_SIGNAL_FLAG
45 : #define KILL_CMD_SIGNAL_FLAG "-s"
46 : #endif
47 :
48 : #ifndef KILL_CMD_SIGNAL
49 : #define KILL_CMD_SIGNAL "SIGKILL"
50 : #endif
51 :
52 0 : static int is_logged_in(TALLOC_CTX *mem_ctx, uid_t uid)
53 : {
54 : int ret;
55 : hash_key_t key;
56 : hash_value_t value;
57 : hash_table_t *uid_table;
58 :
59 0 : ret = get_uid_table(mem_ctx, &uid_table);
60 0 : if (ret == ENOSYS) return ret;
61 0 : if (ret != EOK) {
62 0 : DEBUG(SSSDBG_CRIT_FAILURE, "Cannot initialize hash table.\n");
63 0 : return ret;
64 : }
65 :
66 0 : key.type = HASH_KEY_ULONG;
67 0 : key.ul = (unsigned long) uid;
68 :
69 0 : ret = hash_lookup(uid_table, &key, &value);
70 0 : talloc_zfree(uid_table);
71 0 : return ret == HASH_SUCCESS ? EOK : ENOENT;
72 : }
73 :
74 0 : static int kick_user(struct tools_ctx *tctx)
75 : {
76 : int ret;
77 : int status;
78 : pid_t pid, child_pid;
79 :
80 0 : tctx->octx->lock = 1;
81 :
82 0 : ret = usermod(tctx, tctx->octx);
83 0 : if (ret != EOK) {
84 0 : return ret;
85 : }
86 :
87 0 : errno = 0;
88 0 : pid = fork();
89 0 : if (pid == 0) {
90 : /* child */
91 0 : execlp(KILL_CMD, KILL_CMD,
92 0 : KILL_CMD_USER_FLAG, tctx->octx->name,
93 : KILL_CMD_SIGNAL_FLAG, KILL_CMD_SIGNAL,
94 : (char *) NULL);
95 0 : exit(errno);
96 : } else {
97 : /* parent */
98 0 : if (pid == -1) {
99 0 : ret = errno;
100 0 : DEBUG(SSSDBG_CRIT_FAILURE,
101 : "fork failed [%d]: %s\n", ret, strerror(ret));
102 0 : return ret;
103 : }
104 :
105 0 : while((child_pid = waitpid(pid, &status, 0)) > 0) {
106 :
107 0 : if (WIFEXITED(status)) {
108 0 : break;
109 : }
110 : }
111 0 : if (child_pid == -1) {
112 0 : DEBUG(SSSDBG_CRIT_FAILURE, "waitpid failed\n");
113 0 : return errno;
114 : }
115 : }
116 :
117 0 : return EOK;
118 : }
119 :
120 0 : int main(int argc, const char **argv)
121 : {
122 0 : int ret = EXIT_SUCCESS;
123 0 : struct tools_ctx *tctx = NULL;
124 0 : const char *pc_username = NULL;
125 :
126 0 : int pc_debug = SSSDBG_DEFAULT;
127 0 : int pc_remove = 0;
128 0 : int pc_force = 0;
129 0 : int pc_kick = 0;
130 0 : poptContext pc = NULL;
131 0 : struct poptOption long_options[] = {
132 : POPT_AUTOHELP
133 : { "debug", '\0', POPT_ARG_INT | POPT_ARGFLAG_DOC_HIDDEN, &pc_debug,
134 0 : 0, _("The debug level to run with"), NULL },
135 : { "remove", 'r', POPT_ARG_NONE, NULL, 'r',
136 0 : _("Remove home directory and mail spool"), NULL },
137 : { "no-remove", 'R', POPT_ARG_NONE, NULL, 'R',
138 0 : _("Do not remove home directory and mail spool"), NULL },
139 : { "force", 'f', POPT_ARG_NONE, NULL, 'f',
140 0 : _("Force removal of files not owned by the user"), NULL },
141 : { "kick", 'k', POPT_ARG_NONE, NULL, 'k',
142 0 : _("Kill users' processes before removing him"), NULL },
143 : POPT_TABLEEND
144 : };
145 :
146 0 : debug_prg_name = argv[0];
147 :
148 0 : ret = set_locale();
149 0 : if (ret != EOK) {
150 0 : DEBUG(SSSDBG_CRIT_FAILURE,
151 : "set_locale failed (%d): %s\n", ret, strerror(ret));
152 0 : ERROR("Error setting the locale\n");
153 0 : ret = EXIT_FAILURE;
154 0 : goto fini;
155 : }
156 :
157 : /* parse parameters */
158 0 : pc = poptGetContext(NULL, argc, argv, long_options, 0);
159 0 : poptSetOtherOptionHelp(pc, "USERNAME");
160 0 : while ((ret = poptGetNextOpt(pc)) > 0) {
161 0 : switch (ret) {
162 : case 'r':
163 0 : pc_remove = DO_REMOVE_HOME;
164 0 : break;
165 :
166 : case 'R':
167 0 : pc_remove = DO_NOT_REMOVE_HOME;
168 0 : break;
169 :
170 : case 'f':
171 0 : pc_force = DO_FORCE_REMOVAL;
172 0 : break;
173 :
174 : case 'k':
175 0 : pc_kick = 1;
176 0 : break;
177 : }
178 : }
179 :
180 0 : DEBUG_CLI_INIT(pc_debug);
181 :
182 0 : if (ret != -1) {
183 0 : BAD_POPT_PARAMS(pc, poptStrerror(ret), ret, fini);
184 : }
185 :
186 0 : pc_username = poptGetArg(pc);
187 0 : if (pc_username == NULL) {
188 0 : BAD_POPT_PARAMS(pc, _("Specify user to delete\n"), ret, fini);
189 : }
190 :
191 0 : CHECK_ROOT(ret, debug_prg_name);
192 :
193 0 : ret = init_sss_tools(&tctx);
194 0 : if (ret != EOK) {
195 0 : DEBUG(SSSDBG_CRIT_FAILURE,
196 : "init_sss_tools failed (%d): %s\n", ret, strerror(ret));
197 0 : if (ret == ENOENT) {
198 0 : ERROR("Error initializing the tools - no local domain\n");
199 : } else {
200 0 : ERROR("Error initializing the tools\n");
201 : }
202 0 : ret = EXIT_FAILURE;
203 0 : goto fini;
204 : }
205 :
206 : /* if the domain was not given as part of FQDN, default to local domain */
207 0 : ret = parse_name_domain(tctx, pc_username);
208 0 : if (ret != EOK) {
209 0 : ERROR("Invalid domain specified in FQDN\n");
210 0 : ret = EXIT_FAILURE;
211 0 : goto fini;
212 : }
213 :
214 : /*
215 : * Fills in defaults for ops_ctx user did not specify.
216 : */
217 0 : ret = userdel_defaults(tctx, tctx->confdb, tctx->octx, pc_remove);
218 0 : if (ret != EOK) {
219 0 : ERROR("Cannot set default values\n");
220 0 : ret = EXIT_FAILURE;
221 0 : goto fini;
222 : }
223 :
224 0 : ret = sysdb_getpwnam_sync(tctx,
225 0 : tctx->octx->name,
226 0 : tctx->octx);
227 0 : if (ret != EOK) {
228 : /* Error message will be printed in the switch */
229 0 : goto done;
230 : }
231 :
232 0 : if ((tctx->octx->uid < tctx->local->id_min) ||
233 0 : (tctx->local->id_max && tctx->octx->uid > tctx->local->id_max)) {
234 0 : ERROR("User %1$s is outside the defined ID range for domain\n",
235 : tctx->octx->name);
236 0 : ret = EXIT_FAILURE;
237 0 : goto fini;
238 : }
239 :
240 0 : if (pc_kick) {
241 0 : ret = kick_user(tctx);
242 0 : if (ret != EOK) {
243 0 : tctx->error = ret;
244 :
245 0 : goto done;
246 : }
247 : }
248 :
249 : /* userdel */
250 0 : ret = userdel(tctx, tctx->sysdb, tctx->octx);
251 0 : if (ret != EOK) {
252 0 : goto done;
253 : }
254 :
255 : /* Set SELinux login context - must be done after transaction is done
256 : * b/c libselinux calls getpwnam */
257 0 : ret = del_seuser(tctx->octx->name);
258 0 : if (ret != EOK) {
259 0 : ERROR("Cannot reset SELinux login context\n");
260 0 : ret = EXIT_FAILURE;
261 0 : goto fini;
262 : }
263 :
264 0 : if (!pc_kick) {
265 0 : ret = is_logged_in(tctx, tctx->octx->uid);
266 0 : switch(ret) {
267 : case ENOENT:
268 0 : break;
269 :
270 : case EOK:
271 0 : ERROR("WARNING: The user (uid %1$lu) was still logged in when "
272 : "deleted.\n", (unsigned long) tctx->octx->uid);
273 0 : break;
274 :
275 : case ENOSYS:
276 0 : ERROR("Cannot determine if the user was logged in on this "
277 : "platform");
278 0 : break;
279 :
280 : default:
281 0 : ERROR("Error while checking if the user was logged in\n");
282 0 : break;
283 : }
284 : }
285 :
286 0 : ret = run_userdel_cmd(tctx);
287 0 : if (ret != EOK) {
288 0 : ERROR("The post-delete command failed: %1$s\n", strerror(ret));
289 0 : goto fini;
290 : }
291 :
292 : /* Delete user from memory cache */
293 0 : ret = sss_mc_refresh_user(pc_username);
294 0 : if (ret != EOK) {
295 0 : ERROR("NSS request failed (%1$d). Entry might remain in memory "
296 : "cache.\n", ret);
297 : /* Nothing we can do about it */
298 : }
299 :
300 0 : if (tctx->octx->remove_homedir) {
301 0 : ret = remove_homedir(tctx,
302 0 : tctx->octx->home,
303 0 : tctx->octx->maildir,
304 0 : tctx->octx->name,
305 0 : tctx->octx->uid,
306 : pc_force);
307 0 : if (ret == EPERM) {
308 0 : ERROR("Not removing home dir - not owned by user\n");
309 0 : } else if (ret != EOK) {
310 0 : ERROR("Cannot remove homedir: %1$s\n", strerror(ret));
311 0 : ret = EXIT_FAILURE;
312 0 : goto fini;
313 : }
314 : }
315 :
316 0 : ret = EOK;
317 :
318 : done:
319 0 : if (ret) {
320 0 : DEBUG(SSSDBG_CRIT_FAILURE,
321 : "sysdb operation failed (%d)[%s]\n", ret, strerror(ret));
322 0 : switch (ret) {
323 : case ENOENT:
324 0 : ERROR("No such user in local domain. "
325 : "Removing users only allowed in local domain.\n");
326 0 : break;
327 :
328 : default:
329 0 : ERROR("Internal error. Could not remove user.\n");
330 0 : break;
331 : }
332 0 : ret = EXIT_FAILURE;
333 0 : goto fini;
334 : }
335 :
336 0 : ret = EXIT_SUCCESS;
337 :
338 : fini:
339 0 : talloc_free(tctx);
340 0 : poptFreeContext(pc);
341 0 : exit(ret);
342 : }
343 :
|