From 3bd250d73e7d77cf8ceb72133ce13059c52a70ed Mon Sep 17 00:00:00 2001 From: Jakub Hrozek Date: Wed, 17 Mar 2010 11:56:47 +0100 Subject: Make sss_userdel check for logged in users sss_userdel now warns if the deleted user was logged in at the time of deletion. Also adds a new parameter --kick to userdel that kills all user processes before actually deleting ther user. Fixes: #229 --- src/Makefile.am | 1 + src/man/sss_userdel.8.xml | 11 ++++ src/tools/sss_userdel.c | 145 +++++++++++++++++++++++++++++++++++++++++++++- 3 files changed, 154 insertions(+), 3 deletions(-) diff --git a/src/Makefile.am b/src/Makefile.am index 3a156cb5c..c3b1fe7be 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -411,6 +411,7 @@ sss_useradd_LDADD = \ sss_userdel_SOURCES = \ tools/sss_userdel.c \ + util/find_uid.c \ $(SSSD_UTIL_OBJ) \ $(SSSD_TOOLS_OBJ) sss_userdel_LDADD = \ diff --git a/src/man/sss_userdel.8.xml b/src/man/sss_userdel.8.xml index 0c495297c..b37718c6c 100644 --- a/src/man/sss_userdel.8.xml +++ b/src/man/sss_userdel.8.xml @@ -75,6 +75,17 @@ + + + , + + + + Before actually deleting the user, terminate all + his processes. + + + diff --git a/src/tools/sss_userdel.c b/src/tools/sss_userdel.c index 7f17b1fbc..e74424d80 100644 --- a/src/tools/sss_userdel.c +++ b/src/tools/sss_userdel.c @@ -23,12 +23,108 @@ #include #include #include +#include +#include #include "db/sysdb.h" #include "util/util.h" +#include "util/find_uid.h" #include "tools/tools_util.h" #include "tools/sss_sync_ops.h" +#ifndef KILL_CMD +#define KILL_CMD "killall" +#endif + +#ifndef KILL_CMD_USER_FLAG +#define KILL_CMD_USER_FLAG "-u" +#endif + +#ifndef KILL_CMD_SIGNAL_FLAG +#define KILL_CMD_SIGNAL_FLAG "-s" +#endif + +#ifndef KILL_CMD_SIGNAL +#define KILL_CMD_SIGNAL "SIGKILL" +#endif + +static int is_logged_in(TALLOC_CTX *mem_ctx, uid_t uid) +{ + int ret; + hash_key_t key; + hash_value_t value; + hash_table_t *uid_table; + + ret = get_uid_table(mem_ctx, &uid_table); + if (ret == ENOSYS) return ret; + if (ret != EOK) { + DEBUG(1, ("Cannot initialize hash table.\n")); + return ret; + } + + key.type = HASH_KEY_ULONG; + key.ul = (unsigned long) uid; + + ret = hash_lookup(uid_table, &key, &value); + talloc_zfree(uid_table); + return ret == HASH_SUCCESS ? EOK : ENOENT; +} + +static int kick_user(struct tools_ctx *tctx) +{ + int ret; + int status; + pid_t pid, child_pid; + + tctx->octx->lock = 1; + + start_transaction(tctx); + if (tctx->error != EOK) { + return tctx->error; + } + + ret = usermod(tctx, tctx->ev, tctx->sysdb, tctx->handle, tctx->octx); + if (ret != EOK) { + talloc_zfree(tctx->handle); + return ret; + } + + end_transaction(tctx); + if (tctx->error != EOK) { + return tctx->error; + } + + errno = 0; + pid = fork(); + if (pid == 0) { + /* child */ + execlp(KILL_CMD, KILL_CMD, + KILL_CMD_USER_FLAG, tctx->octx->name, + KILL_CMD_SIGNAL_FLAG, KILL_CMD_SIGNAL, + (char *) NULL); + exit(errno); + } else { + /* parent */ + if (pid == -1) { + DEBUG(1, ("fork failed [%d]: %s\n")); + return errno; + } + + while((child_pid = waitpid(pid, &status, 0)) > 0) { + if (child_pid == -1) { + DEBUG(1, ("waitpid failed\n")); + return errno; + } + + if (WIFEXITED(status)) { + break; + } + } + } + + return EOK; +} + int main(int argc, const char **argv) { int ret = EXIT_SUCCESS; @@ -38,14 +134,20 @@ int main(int argc, const char **argv) int pc_debug = 0; int pc_remove = 0; int pc_force = 0; + int pc_kick = 0; poptContext pc = NULL; struct poptOption long_options[] = { POPT_AUTOHELP { "debug", '\0', POPT_ARG_INT | POPT_ARGFLAG_DOC_HIDDEN, &pc_debug, 0, _("The debug level to run with"), NULL }, - { "remove", 'r', POPT_ARG_NONE, NULL, 'r', _("Remove home directory and mail spool"), NULL }, - { "no-remove", 'R', POPT_ARG_NONE, NULL, 'R', _("Do not remove home directory and mail spool"), NULL }, - { "force", 'f', POPT_ARG_NONE, NULL, 'f', _("Force removal of files not owned by the user"), NULL }, + { "remove", 'r', POPT_ARG_NONE, NULL, 'r', + _("Remove home directory and mail spool"), NULL }, + { "no-remove", 'R', POPT_ARG_NONE, NULL, 'R', + _("Do not remove home directory and mail spool"), NULL }, + { "force", 'f', POPT_ARG_NONE, NULL, 'f', + _("Force removal of files not owned by the user"), NULL }, + { "kick", 'k', POPT_ARG_NONE, NULL, 'k', + _("Kill users' processes before removing him"), NULL }, POPT_TABLEEND }; @@ -75,6 +177,10 @@ int main(int argc, const char **argv) case 'f': pc_force = DO_FORCE_REMOVAL; break; + + case 'k': + pc_kick = 1; + break; } } @@ -144,6 +250,17 @@ int main(int argc, const char **argv) goto fini; } + if (pc_kick) { + ret = kick_user(tctx); + if (ret != EOK) { + tctx->error = ret; + + /* cancel transaction */ + talloc_zfree(tctx->handle); + goto done; + } + } + start_transaction(tctx); if (tctx->error != EOK) { goto done; @@ -161,6 +278,28 @@ int main(int argc, const char **argv) end_transaction(tctx); + if (!pc_kick) { + ret = is_logged_in(tctx, tctx->octx->uid); + switch(ret) { + case ENOENT: + break; + + case EOK: + ERROR("WARNING: The user (uid %lu) was still logged in when " + "deleted.\n", (unsigned long) tctx->octx->uid); + break; + + case ENOSYS: + ERROR("Cannot determine if the user was logged in on this " + "platform"); + break; + + default: + ERROR("Error while checking if the user was logged in\n"); + break; + } + } + ret = run_userdel_cmd(tctx); if (ret != EOK) { ERROR("The post-delete command failed: %s\n", strerror(ret)); -- cgit