summaryrefslogtreecommitdiffstats
path: root/src/tools
diff options
context:
space:
mode:
authorJakub Hrozek <jhrozek@redhat.com>2010-03-30 15:26:58 +0200
committerStephen Gallagher <sgallagh@redhat.com>2010-04-08 08:53:35 -0400
commit9c124af8868a7d3908c03ec369e28daef17d5f12 (patch)
tree2efdddd72acb1d48941c2ee9749c6ad7cadb8697 /src/tools
parent81020661d35772b5499525b76a19c9a3794c953e (diff)
downloadsssd-9c124af8868a7d3908c03ec369e28daef17d5f12.tar.gz
sssd-9c124af8868a7d3908c03ec369e28daef17d5f12.tar.xz
sssd-9c124af8868a7d3908c03ec369e28daef17d5f12.zip
SELinux login management
Adds a new option -Z to sss_useradd and sss_usermod. This option allows user to specify the SELinux login context for the user. On deleting the user with sss_userdel, the login mapping is deleted, so subsequent adding of the same user would result in the default login context unless -Z is specified again. MLS security is not supported as of this patch.
Diffstat (limited to 'src/tools')
-rw-r--r--src/tools/selinux.c338
-rw-r--r--src/tools/sss_useradd.c11
-rw-r--r--src/tools/sss_userdel.c9
-rw-r--r--src/tools/sss_usermod.c11
-rw-r--r--src/tools/tools_util.h2
5 files changed, 371 insertions, 0 deletions
diff --git a/src/tools/selinux.c b/src/tools/selinux.c
index 9fa660c62..23951289a 100644
--- a/src/tools/selinux.c
+++ b/src/tools/selinux.c
@@ -21,12 +21,23 @@
#include "config.h"
+#define _GNU_SOURCE
+#include <stdio.h>
+
#ifdef HAVE_SELINUX
#include <selinux/selinux.h>
#endif
+#ifdef HAVE_SEMANAGE
+#include <semanage/semanage.h>
+#endif
+
#include "util/util.h"
+#ifndef DEFAULT_SERANGE
+#define DEFAULT_SERANGE "s0"
+#endif
+
#ifdef HAVE_SELINUX
/*
* selinux_file_context - Set the security context before any file or
@@ -79,3 +90,330 @@ int reset_selinux_file_context(void)
return EOK;
}
#endif /* HAVE_SELINUX */
+
+#ifdef HAVE_SEMANAGE
+/* turn libselinux messages into SSSD DEBUG() calls */
+static void sss_semanage_error_callback(void *varg,
+ semanage_handle_t *handle,
+ const char *fmt, ...)
+{
+ int level = -1;
+ int ret;
+ char * message = NULL;
+ va_list ap;
+
+ switch (semanage_msg_get_level(handle)) {
+ case SEMANAGE_MSG_ERR:
+ level = 1;
+ break;
+ case SEMANAGE_MSG_WARN:
+ level = 4;
+ break;
+ case SEMANAGE_MSG_INFO:
+ level = 6;
+ break;
+ }
+
+ va_start(ap, fmt);
+ ret = vasprintf(&message, fmt, ap);
+ if (ret < 0) {
+ /* ENOMEM */
+ return;
+ }
+ va_end(ap);
+
+ if (level <= debug_level) {
+ if (debug_timestamps) {
+ time_t rightnow = time(NULL);
+ char stamp[25];
+ memcpy(stamp, ctime(&rightnow), 24);
+ stamp[24] = '\0';
+ debug_fn("(%s) [%s] [libsemanage] (%d): %s\n",
+ stamp, debug_prg_name, level, message);
+ } else {
+ debug_fn("[%s] [libsemanage] (%d): %s\n",
+ debug_prg_name, level, message);
+ }
+ }
+ free(message);
+}
+
+static semanage_handle_t *sss_semanage_init(void)
+{
+ int ret;
+ semanage_handle_t *handle = NULL;
+
+ handle = semanage_handle_create();
+ if (!handle) {
+ DEBUG(1, ("Cannot create SELinux management handle\n"));
+ return NULL;
+ }
+
+ semanage_msg_set_callback(handle,
+ sss_semanage_error_callback,
+ NULL);
+
+ ret = semanage_is_managed(handle);
+ if (ret != 1) {
+ DEBUG(1, ("SELinux policy not managed\n"));
+ goto fail;
+ }
+
+ ret = semanage_access_check(handle);
+ if (ret < SEMANAGE_CAN_READ) {
+ DEBUG(1, ("Cannot read SELinux policy store\n"));
+ goto fail;
+ }
+
+ ret = semanage_connect(handle);
+ if (ret != 0) {
+ DEBUG(1, ("Cannot estabilish SELinux management connection\n"));
+ goto fail;
+ }
+
+ ret = semanage_begin_transaction(handle);
+ if (ret != 0) {
+ DEBUG(1, ("Cannot begin SELinux transaction\n"));
+ goto fail;
+ }
+
+ return handle;
+fail:
+ semanage_handle_destroy(handle);
+ return NULL;
+}
+
+static int sss_semanage_user_add(semanage_handle_t *handle,
+ semanage_seuser_key_t *key,
+ const char *login_name,
+ const char *seuser_name)
+{
+ int ret;
+ semanage_seuser_t *seuser = NULL;
+
+ ret = semanage_seuser_create(handle, &seuser);
+ if (ret != 0) {
+ DEBUG(1, ("Cannot create SELinux login mapping for %s\n", login_name));
+ ret = EIO;
+ goto done;
+ }
+
+ ret = semanage_seuser_set_name(handle, seuser, login_name);
+ if (ret != 0) {
+ DEBUG(1, ("Could not set name for %s\n", login_name));
+ ret = EIO;
+ goto done;
+ }
+
+ ret = semanage_seuser_set_mlsrange(handle, seuser, DEFAULT_SERANGE);
+ if (ret != 0) {
+ DEBUG(1, ("Could not set serange for %s\n", login_name));
+ ret = EIO;
+ goto done;
+ }
+
+ ret = semanage_seuser_set_sename(handle, seuser, seuser_name);
+ if (ret != 0) {
+ DEBUG(1, ("Could not set SELinux user for %s\n", login_name));
+ ret = EIO;
+ goto done;
+ }
+
+ ret = semanage_seuser_modify_local(handle, key, seuser);
+ if (ret != 0) {
+ DEBUG(1, ("Could not add login mapping for %s\n", login_name));
+ ret = EIO;
+ goto done;
+ }
+
+ ret = EOK;
+done:
+ semanage_seuser_free(seuser);
+ return ret;
+}
+
+static int sss_semanage_user_mod(semanage_handle_t *handle,
+ semanage_seuser_key_t *key,
+ const char *login_name,
+ const char *seuser_name)
+{
+ int ret;
+ semanage_seuser_t *seuser = NULL;
+
+ semanage_seuser_query(handle, key, &seuser);
+ if (seuser == NULL) {
+ DEBUG(1, ("Could not query seuser for %s\n", login_name));
+ ret = EIO;
+ goto done;
+ }
+
+ ret = semanage_seuser_set_mlsrange(handle, seuser, DEFAULT_SERANGE);
+ if (ret != 0) {
+ DEBUG(1, ("Could not set serange for %s\n", login_name));
+ ret = EIO;
+ goto done;
+ }
+
+ ret = semanage_seuser_set_sename(handle, seuser, seuser_name);
+ if (ret != 0) {
+ DEBUG(1, ("Could not set sename for %s\n", login_name));
+ ret = EIO;
+ goto done;
+ }
+
+ ret = semanage_seuser_modify_local(handle, key, seuser);
+ if (ret != 0) {
+ DEBUG(1, (("Could not modify login mapping for %s\n"), login_name));
+ ret = EIO;
+ goto done;
+ }
+
+ ret = EOK;
+done:
+ semanage_seuser_free(seuser);
+ return ret;
+}
+
+int set_seuser(const char *login_name, const char *seuser_name)
+{
+ semanage_handle_t *handle = NULL;
+ semanage_seuser_key_t *key = NULL;
+ int ret;
+ int seuser_exists = 0;
+
+ if (seuser_name == NULL) {
+ /* don't care, just let system pick the defaults */
+ return EOK;
+ }
+
+ handle = sss_semanage_init();
+ if (!handle) {
+ DEBUG(1, ("Cannot init SELinux management\n"));
+ ret = EIO;
+ goto done;
+ }
+
+ ret = semanage_seuser_key_create(handle, login_name, &key);
+ if (ret != 0) {
+ DEBUG(1, ("Cannot create SELinux user key\n"));
+ ret = EIO;
+ goto done;
+ }
+
+ ret = semanage_seuser_exists(handle, key, &seuser_exists);
+ if (ret < 0) {
+ DEBUG(1, ("Cannot verify the SELinux user\n"));
+ ret = EIO;
+ goto done;
+ }
+
+ if (seuser_exists) {
+ ret = sss_semanage_user_mod(handle, key, login_name, seuser_name);
+ if (ret != 0) {
+ DEBUG(1, ("Cannot modify SELinux user mapping\n"));
+ ret = EIO;
+ goto done;
+ }
+ } else {
+ ret = sss_semanage_user_add(handle, key, login_name, seuser_name);
+ if (ret != 0) {
+ DEBUG(1, ("Cannot add SELinux user mapping\n"));
+ ret = EIO;
+ goto done;
+ }
+ }
+
+ ret = semanage_commit(handle);
+ if (ret != 0) {
+ DEBUG(1, ("Cannot commit SELinux transaction\n"));
+ ret = EIO;
+ goto done;
+ }
+
+ ret = EOK;
+done:
+ semanage_seuser_key_free(key);
+ semanage_handle_destroy(handle);
+ return ret;
+}
+
+int del_seuser(const char *login_name)
+{
+ semanage_handle_t *handle = NULL;
+ semanage_seuser_key_t *key = NULL;
+ int ret;
+ int exists = 0;
+
+ handle = sss_semanage_init();
+ if (!handle) {
+ DEBUG(1, ("Cannot init SELinux management\n"));
+ ret = EIO;
+ goto done;
+ }
+
+ ret = semanage_seuser_key_create(handle, login_name, &key);
+ if (ret != 0) {
+ DEBUG(1, ("Cannot create SELinux user key\n"));
+ ret = EIO;
+ goto done;
+ }
+
+ ret = semanage_seuser_exists(handle, key, &exists);
+ if (ret < 0) {
+ DEBUG(1, ("Cannot verify the SELinux user\n"));
+ ret = EIO;
+ goto done;
+ }
+
+ if (!exists) {
+ DEBUG(5, ("Login mapping for %s is not defined, OK if default mapping "
+ "was used\n", login_name));
+ ret = EOK; /* probably default mapping */
+ goto done;
+ }
+
+ ret = semanage_seuser_exists_local(handle, key, &exists);
+ if (ret < 0) {
+ DEBUG(1, ("Cannot verify the SELinux user\n"));
+ ret = EIO;
+ goto done;
+ }
+
+ if (!exists) {
+ DEBUG(1, ("Login mapping for %s is defined in policy, "
+ "cannot be deleted", login_name));
+ ret = ENOENT;
+ goto done;
+ }
+
+ ret = semanage_seuser_del_local(handle, key);
+ if (ret != 0) {
+ DEBUG(1, ("Could not delete login mapping for %s", login_name));
+ ret = EIO;
+ goto done;
+ }
+
+ ret = semanage_commit(handle);
+ if (ret != 0) {
+ DEBUG(1, ("Cannot commit SELinux transaction\n"));
+ ret = EIO;
+ goto done;
+ }
+
+ ret = EOK;
+done:
+ semanage_handle_destroy(handle);
+ return ret;
+}
+
+#else /* HAVE_SEMANAGE */
+int set_seuser(const char *login_name, const char *seuser_name)
+{
+ return EOK;
+}
+
+int del_seuser(const char *login_name)
+{
+ return EOK;
+}
+#endif /* HAVE_SEMANAGE */
diff --git a/src/tools/sss_useradd.c b/src/tools/sss_useradd.c
index 2d88e75e4..6c6b5851f 100644
--- a/src/tools/sss_useradd.c
+++ b/src/tools/sss_useradd.c
@@ -109,6 +109,7 @@ int main(int argc, const char **argv)
int pc_create_home = 0;
const char *pc_username = NULL;
const char *pc_skeldir = NULL;
+ const char *pc_selinux_user = 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 },
@@ -121,6 +122,7 @@ int main(int argc, const char **argv)
{ "create-home", 'm', POPT_ARG_NONE, NULL, 'm', _("Create user's directory if it does not exist"), NULL },
{ "no-create-home", 'M', POPT_ARG_NONE, NULL, 'M', _("Never create user's directory, overrides config"), NULL },
{ "skel", 'k', POPT_ARG_STRING, &pc_skeldir, 0, _("Specify an alternative skeleton directory"), NULL },
+ { "selinux-user", 'Z', POPT_ARG_STRING, &pc_selinux_user, 0, _("The SELinux user for user's login"), NULL },
POPT_TABLEEND
};
poptContext pc = NULL;
@@ -270,6 +272,15 @@ int main(int argc, const char **argv)
end_transaction(tctx);
+ /* Set SELinux login context - must be done after transaction is done
+ * b/c libselinux calls getpwnam */
+ ret = set_seuser(tctx->octx->name, pc_selinux_user);
+ if (ret != EOK) {
+ ERROR("Cannot set SELinux login context\n");
+ ret = EXIT_FAILURE;
+ goto fini;
+ }
+
/* Create user's home directory and/or mail spool */
if (tctx->octx->create_homedir) {
/* We need to know the UID and GID of the user, if
diff --git a/src/tools/sss_userdel.c b/src/tools/sss_userdel.c
index e74424d80..464c22e74 100644
--- a/src/tools/sss_userdel.c
+++ b/src/tools/sss_userdel.c
@@ -278,6 +278,15 @@ int main(int argc, const char **argv)
end_transaction(tctx);
+ /* Set SELinux login context - must be done after transaction is done
+ * b/c libselinux calls getpwnam */
+ ret = del_seuser(tctx->octx->name);
+ if (ret != EOK) {
+ ERROR("Cannot reset SELinux login context\n");
+ ret = EXIT_FAILURE;
+ goto fini;
+ }
+
if (!pc_kick) {
ret = is_logged_in(tctx, tctx->octx->uid);
switch(ret) {
diff --git a/src/tools/sss_usermod.c b/src/tools/sss_usermod.c
index a272bc55e..65431fa56 100644
--- a/src/tools/sss_usermod.c
+++ b/src/tools/sss_usermod.c
@@ -41,6 +41,7 @@ int main(int argc, const char **argv)
char *pc_home = NULL;
char *pc_shell = NULL;
int pc_debug = 0;
+ const char *pc_selinux_user = 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 },
@@ -53,6 +54,7 @@ int main(int argc, const char **argv)
{ "remove-group", 'r', POPT_ARG_STRING, NULL, 'r', _("Groups to remove this user from"), NULL },
{ "lock", 'L', POPT_ARG_NONE, NULL, 'L', _("Lock the account"), NULL },
{ "unlock", 'U', POPT_ARG_NONE, NULL, 'U', _("Unlock the account"), NULL },
+ { "selinux-user", 'Z', POPT_ARG_STRING, &pc_selinux_user, 0, _("The SELinux user for user's login"), NULL },
POPT_TABLEEND
};
poptContext pc = NULL;
@@ -233,6 +235,15 @@ int main(int argc, const char **argv)
end_transaction(tctx);
+ /* Set SELinux login context - must be done after transaction is done
+ * b/c libselinux calls getpwnam */
+ ret = set_seuser(tctx->octx->name, pc_selinux_user);
+ if (ret != EOK) {
+ ERROR("Cannot set SELinux login context\n");
+ ret = EXIT_FAILURE;
+ goto fini;
+ }
+
done:
if (tctx->error) {
ret = tctx->error;
diff --git a/src/tools/tools_util.h b/src/tools/tools_util.h
index 2ac18535b..ac8828684 100644
--- a/src/tools/tools_util.h
+++ b/src/tools/tools_util.h
@@ -115,5 +115,7 @@ int flush_nscd_cache(TALLOC_CTX *mem_ctx, enum nscd_db flush_db);
/* from selinux.c */
int selinux_file_context(const char *dst_name);
int reset_selinux_file_context(void);
+int set_seuser(const char *login_name, const char *seuser_name);
+int del_seuser(const char *login_name);
#endif /* __TOOLS_UTIL_H__ */