diff --git a/ChangeLog b/ChangeLog index 3883e777..c6828194 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,13 @@ +2011-11-16 Peter Vrabec + + * NEWS, src/userdel.c, man/userdel.8.xml: Add option -Z/--selinux-user. + * libmisc/system.c, lib/prototypes.h, libmisc/Makefile.am: Removed + safe_system(). + * lib/selinux.c, po/POTFILES.in, lib/prototypes.h, + lib/Makefile.am: Added helper functions for semanage. + * README, src/useradd.c, src/usermod.c, src/userdel.c, + configure.in: Use libsemanage instead of semanage. + 2011-11-16 Peter Vrabec * src/Makefile.am: useradd may need the LIBATTR library. diff --git a/NEWS b/NEWS index 7df574e8..dad38fa9 100644 --- a/NEWS +++ b/NEWS @@ -97,6 +97,7 @@ shadow-4.1.4.3 -> shadow-4.1.5 UNRELEASED * Do not remove a group with the same name as the user (usergroup) if this group isn't the user's primary group. * Add --root option. + * Add --selinux-user option. - usermod * Accept options in any order (username not necessarily at the end) * When the shadow file exists but there are no shadow entries, an entry diff --git a/README b/README index 0619ac75..e531de6c 100644 --- a/README +++ b/README @@ -37,7 +37,7 @@ S/Key support: Authors and contributors ======================== -Thanks to at least the following people for sending me patches, bug +Thanks to at least the following people for sending patches, bug reports and various comments. This list may be incomplete, I received a lot of mail... @@ -69,6 +69,7 @@ Greg Mortensen Guido van Rooij Guy Maor Hrvoje Dogan +Jakub Hrozek Janos Farkas Jay Soffian Jesse Thilo @@ -96,6 +97,7 @@ Mike Pakovic Nicolas François Nikos Mavroyanopoulos Pavel Machek +Peter Vrabec Phillip Street Rafał Maszkowski Rani Chouha diff --git a/configure.in b/configure.in index d2057c7b..1c5af5ac 100644 --- a/configure.in +++ b/configure.in @@ -422,22 +422,37 @@ if test "$with_libcrack" = "yes"; then fi AC_SUBST(LIBSELINUX) +AC_SUBST(LIBSEMANAGE) if test "$with_selinux" != "no"; then AC_CHECK_HEADERS(selinux/selinux.h, [selinux_header="yes"], [selinux_header="no"]) if test "$selinux_header$with_selinux" = "noyes" ; then AC_MSG_ERROR([selinux/selinux.h is missing]) - elif test "$selinux_header" = "yes" ; then - AC_CHECK_LIB(selinux, is_selinux_enabled, - [selinux_lib="yes"], [selinux_lib="no"]) + fi + + AC_CHECK_HEADERS(semanage/semanage.h, [semanage_header="yes"], [semanage_header="no"]) + if test "$semanage_header$with_selinux" = "noyes" ; then + AC_MSG_ERROR([semanage/semanage.h is missing]) + fi + + if test "$selinux_header$semanage_header" = "yesyes" ; then + AC_CHECK_LIB(selinux, is_selinux_enabled, [selinux_lib="yes"], [selinux_lib="no"]) if test "$selinux_lib$with_selinux" = "noyes" ; then AC_MSG_ERROR([libselinux not found]) - elif test "$selinux_lib" = "no" ; then - with_selinux="no" - else + fi + + AC_CHECK_LIB(semanage, semanage_connect, [semanage_lib="yes"], [semanage_lib="no"]) + if test "$semanage_lib$with_selinux" = "noyes" ; then + AC_MSG_ERROR([libsemanage not found]) + fi + + if test "$selinux_lib$semanage_lib" == "yesyes" ; then AC_DEFINE(WITH_SELINUX, 1, [Build shadow with SELinux support]) LIBSELINUX="-lselinux" + LIBSEMANAGE="-lsemanage" with_selinux="yes" + else + with_selinux="no" fi else with_selinux="no" diff --git a/lib/Makefile.am b/lib/Makefile.am index 05b3a943..4744d91f 100644 --- a/lib/Makefile.am +++ b/lib/Makefile.am @@ -39,6 +39,7 @@ libshadow_la_SOURCES = \ pwio.c \ pwio.h \ pwmem.c \ + selinux.c \ sgetgrent.c \ sgetpwent.c \ sgetspent.c \ diff --git a/lib/prototypes.h b/lib/prototypes.h index e2a0129b..42f0bba1 100644 --- a/lib/prototypes.h +++ b/lib/prototypes.h @@ -297,6 +297,10 @@ extern void process_root_flag (const char* short_opt, int argc, char **argv); /* salt.c */ extern /*@observer@*/const char *crypt_make_salt (/*@null@*//*@observer@*/const char *meth, /*@null@*/void *arg); +/* selinux.c */ +int set_seuser(const char *login_name, const char *seuser_name); +int del_seuser(const char *login_name); + /* setugid.c */ extern int setup_groups (const struct passwd *info); extern int change_uid (const struct passwd *info); @@ -345,12 +349,6 @@ extern int shell (const char *file, /*@null@*/const char *arg, char *const envp[ extern int run_command (const char *cmd, const char *argv[], /*@null@*/const char *envp[], /*@out@*/int *status); -/* system.c */ -extern int safe_system (const char *command, - const char *argv[], - /*@null@*/const char *env[], - bool ignore_stderr); - /* strtoday.c */ extern long strtoday (const char *); diff --git a/lib/selinux.c b/lib/selinux.c new file mode 100644 index 00000000..e8b0726f --- /dev/null +++ b/lib/selinux.c @@ -0,0 +1,374 @@ +/* + * Copyright (c) 2010 , Jakub Hrozek + * Copyright (c) 2011 , Peter Vrabec + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. The name of the copyright holders or contributors may not be used to + * endorse or promote products derived from this software without + * specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT + * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A + * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT + * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, + * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT + * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, + * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY + * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT + * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include + +#ifdef WITH_SELINUX + +#include "defines.h" + +#include +#include +#include +#include + + +#ifndef DEFAULT_SERANGE +#define DEFAULT_SERANGE "s0" +#endif + + +static void semanage_error_callback (void *varg, + semanage_handle_t *handle, + const char *fmt, ...) +{ + int ret; + char * message = NULL; + va_list ap; + + + va_start (ap, fmt); + ret = vasprintf (&message, fmt, ap); + va_end (ap); + if (ret < 0) { + /* ENOMEM */ + return; + } + + switch (semanage_msg_get_level (handle)) { + case SEMANAGE_MSG_ERR: + case SEMANAGE_MSG_WARN: + fprintf (stderr, _("[libsemanage]: %s\n"), message); + break; + case SEMANAGE_MSG_INFO: + /* nop */ + break; + } + + free (message); +} + + +static semanage_handle_t *semanage_init (void) +{ + int ret; + semanage_handle_t *handle = NULL; + + handle = semanage_handle_create (); + if (NULL == handle) { + fprintf (stderr, + _("Cannot create SELinux management handle\n")); + return NULL; + } + + semanage_msg_set_callback (handle, semanage_error_callback, NULL); + + ret = semanage_is_managed (handle); + if (ret != 1) { + fprintf (stderr, _("SELinux policy not managed\n")); + goto fail; + } + + ret = semanage_access_check (handle); + if (ret < SEMANAGE_CAN_READ) { + fprintf (stderr, _("Cannot read SELinux policy store\n")); + goto fail; + } + + ret = semanage_connect (handle); + if (ret != 0) { + fprintf (stderr, + _("Cannot establish SELinux management connection\n")); + goto fail; + } + + ret = semanage_begin_transaction (handle); + if (ret != 0) { + fprintf (stderr, _("Cannot begin SELinux transaction\n")); + goto fail; + } + + return handle; + +fail: + semanage_handle_destroy (handle); + return NULL; +} + + +static int 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 (NULL == seuser) { + fprintf (stderr, + _("Could not query seuser for %s\n"), login_name); + ret = 1; + goto done; + } + + ret = semanage_seuser_set_mlsrange (handle, seuser, DEFAULT_SERANGE); + if (ret != 0) { + fprintf (stderr, + _("Could not set serange for %s\n"), login_name); + ret = 1; + goto done; + } + + ret = semanage_seuser_set_sename (handle, seuser, seuser_name); + if (ret != 0) { + fprintf (stderr, + _("Could not set sename for %s\n"), + login_name); + ret = 1; + goto done; + } + + ret = semanage_seuser_modify_local (handle, key, seuser); + if (ret != 0) { + fprintf (stderr, + _("Could not modify login mapping for %s\n"), + login_name); + ret = 1; + goto done; + } + + ret = 0; +done: + semanage_seuser_free (seuser); + return ret; +} + + +static int 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) { + fprintf (stderr, + _("Cannot create SELinux login mapping for %s\n"), + login_name); + ret = 1; + goto done; + } + + ret = semanage_seuser_set_name (handle, seuser, login_name); + if (ret != 0) { + fprintf (stderr, _("Could not set name for %s\n"), login_name); + ret = 1; + goto done; + } + + ret = semanage_seuser_set_mlsrange (handle, seuser, DEFAULT_SERANGE); + if (ret != 0) { + fprintf (stderr, + _("Could not set serange for %s\n"), + login_name); + ret = 1; + goto done; + } + + ret = semanage_seuser_set_sename (handle, seuser, seuser_name); + if (ret != 0) { + fprintf (stderr, + _("Could not set SELinux user for %s\n"), + login_name); + ret = 1; + goto done; + } + + ret = semanage_seuser_modify_local (handle, key, seuser); + if (ret != 0) { + fprintf (stderr, + _("Could not add login mapping for %s\n"), + login_name); + ret = 1; + goto done; + } + + ret = 0; +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 (NULL == seuser_name) { + /* don't care, just let system pick the defaults */ + return 0; + } + + handle = semanage_init (); + if (NULL == handle) { + fprintf (stderr, _("Cannot init SELinux management\n")); + ret = 1; + goto done; + } + + ret = semanage_seuser_key_create (handle, login_name, &key); + if (ret != 0) { + fprintf (stderr, _("Cannot create SELinux user key\n")); + ret = 1; + goto done; + } + + ret = semanage_seuser_exists (handle, key, &seuser_exists); + if (ret < 0) { + fprintf (stderr, _("Cannot verify the SELinux user\n")); + ret = 1; + goto done; + } + + if (0 != seuser_exists) { + ret = semanage_user_mod (handle, key, login_name, seuser_name); + if (ret != 0) { + fprintf (stderr, + _("Cannot modify SELinux user mapping\n")); + ret = 1; + goto done; + } + } else { + ret = semanage_user_add (handle, key, login_name, seuser_name); + if (ret != 0) { + fprintf (stderr, + _("Cannot add SELinux user mapping\n")); + ret = 1; + goto done; + } + } + + ret = semanage_commit (handle); + if (ret < 0) { + fprintf (stderr, _("Cannot commit SELinux transaction\n")); + ret = 1; + goto done; + } + + ret = 0; + +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 = semanage_init (); + if (NULL == handle) { + fprintf (stderr, _("Cannot init SELinux management\n")); + ret = 1; + goto done; + } + + ret = semanage_seuser_key_create (handle, login_name, &key); + if (ret != 0) { + fprintf (stderr, _("Cannot create SELinux user key\n")); + ret = 1; + goto done; + } + + ret = semanage_seuser_exists (handle, key, &exists); + if (ret < 0) { + fprintf (stderr, _("Cannot verify the SELinux user\n")); + ret = 1; + goto done; + } + + if (0 == exists) { + fprintf (stderr, + _("Login mapping for %s is not defined, OK if default mapping was used\n"), + login_name); + ret = 0; /* probably default mapping */ + goto done; + } + + ret = semanage_seuser_exists_local (handle, key, &exists); + if (ret < 0) { + fprintf (stderr, _("Cannot verify the SELinux user\n")); + ret = 1; + goto done; + } + + if (0 == exists) { + fprintf (stderr, + _("Login mapping for %s is defined in policy, cannot be deleted\n"), + login_name); + ret = 0; /* Login mapping defined in policy can't be deleted */ + goto done; + } + + ret = semanage_seuser_del_local (handle, key); + if (ret != 0) { + fprintf (stderr, + _("Could not delete login mapping for %s"), + login_name); + ret = 1; + goto done; + } + + ret = semanage_commit (handle); + if (ret < 0) { + fprintf (stderr, _("Cannot commit SELinux transaction\n")); + ret = 1; + goto done; + } + + ret = 0; +done: + semanage_handle_destroy (handle); + return ret; +} +#else /* !WITH_SELINUX */ +extern int errno; /* warning: ANSI C forbids an empty source file */ +#endif /* !WITH_SELINUX */ diff --git a/libmisc/Makefile.am b/libmisc/Makefile.am index 41c9e901..9da2ec3f 100644 --- a/libmisc/Makefile.am +++ b/libmisc/Makefile.am @@ -50,7 +50,6 @@ libmisc_a_SOURCES = \ setugid.c \ setupenv.c \ shell.c \ - system.c \ strtoday.c \ sub.c \ sulog.c \ diff --git a/libmisc/system.c b/libmisc/system.c deleted file mode 100644 index 95054165..00000000 --- a/libmisc/system.c +++ /dev/null @@ -1,79 +0,0 @@ -/* - * Copyright (c) 2009 , Dan Walsh - * Copyright (c) 2010 , Nicolas François - * All rights reserved. - * - * Redistribution and use in source and binary forms, with or without - * modification, are permitted provided that the following conditions - * are met: - * 1. Redistributions of source code must retain the above copyright - * notice, this list of conditions and the following disclaimer. - * 2. Redistributions in binary form must reproduce the above copyright - * notice, this list of conditions and the following disclaimer in the - * documentation and/or other materials provided with the distribution. - * 3. The name of the copyright holders or contributors may not be used to - * endorse or promote products derived from this software without - * specific prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS - * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT - * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A - * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT - * HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, - * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT - * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, - * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY - * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE - * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ -#include - -#ident "$Id$" - -#include -#include -#include -#include "prototypes.h" -#include "defines.h" - -int safe_system (const char *command, - const char *argv[], - /*@null@*/const char *env[], - bool ignore_stderr) -{ - int status = -1; - int fd; - pid_t pid; - - pid = fork(); - if (pid < 0) { - return -1; - } - - if (pid != 0) { /* Parent */ - if (waitpid (pid, &status, 0) > 0) { - return status; - } else { - return -1; - } - } - - fd = open ("/dev/null", O_RDWR); - /* Child */ - /* Close Stdin */ - if (dup2 (fd, 0) == -1) { - exit (EXIT_FAILURE); - } - if (ignore_stderr) { - /* Close Stderr */ - if (dup2 (fd, 2) == -1) { - exit (EXIT_FAILURE); - } - } - - (void) execve (command, (char *const *) argv, (char *const *) env); - (void) fprintf (stderr, _("Failed to exec '%s'\n"), argv[0]); - exit (EXIT_FAILURE); -} - diff --git a/man/userdel.8.xml b/man/userdel.8.xml index 7b85c48c..40ba9bb1 100644 --- a/man/userdel.8.xml +++ b/man/userdel.8.xml @@ -136,6 +136,16 @@ + + + , + + + + Remove any SELinux user mapping for the user's login. + + + diff --git a/po/POTFILES.in b/po/POTFILES.in index b90be888..0320764b 100644 --- a/po/POTFILES.in +++ b/po/POTFILES.in @@ -17,6 +17,7 @@ lib/port.c lib/pwauth.c lib/pwio.c lib/pwmem.c +lib/selinux.c lib/sgetgrent.c lib/sgetpwent.c lib/sgetspent.c diff --git a/src/Makefile.am b/src/Makefile.am index e702cf51..88cae993 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -106,9 +106,9 @@ su_SOURCES = \ suauth.c su_LDADD = $(LDADD) $(LIBPAM) $(LIBCRYPT_NOPAM) $(LIBSKEY) $(LIBMD) sulogin_LDADD = $(LDADD) $(LIBCRYPT) -useradd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBACL) $(LIBATTR) -userdel_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) -usermod_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBACL) $(LIBATTR) +useradd_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBSEMANAGE) $(LIBACL) $(LIBATTR) +userdel_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBSEMANAGE) +usermod_LDADD = $(LDADD) $(LIBPAM_SUID) $(LIBAUDIT) $(LIBSELINUX) $(LIBSEMANAGE) $(LIBACL) $(LIBATTR) vipw_LDADD = $(LDADD) $(LIBSELINUX) install-am: all-am diff --git a/src/useradd.c b/src/useradd.c index 07451105..ca56dc18 100644 --- a/src/useradd.c +++ b/src/useradd.c @@ -112,7 +112,7 @@ static const char *user_shell = ""; static const char *create_mail_spool = ""; #ifdef WITH_SELINUX static const char *user_selinux = ""; -#endif +#endif /* WITH_SELINUX */ static long user_expire = -1; static bool is_shadow_pwd; @@ -145,6 +145,9 @@ static bool oflg = false, /* permit non-unique user ID to be specified with -u */ rflg = false, /* create a system account */ sflg = false, /* shell program for new account */ +#ifdef WITH_SELINUX + Zflg = false, /* new selinux user */ +#endif /* WITH_SELINUX */ uflg = false, /* specify user ID for new account */ Uflg = false; /* create a group having the same name as the user */ @@ -164,6 +167,7 @@ static bool home_added = false; #define E_GRP_UPDATE 10 /* can't update group file */ #define E_HOMEDIR 12 /* can't create home directory */ #define E_MAIL_SPOOL 13 /* can't create mail spool */ +#define E_SE_UPDATE 14 /* can't update SELinux user mapping */ #define DGROUP "GROUP=" #define DHOME "HOME=" @@ -181,9 +185,6 @@ static int set_defaults (void); static int get_groups (char *); static void usage (int status); static void new_pwent (struct passwd *); -#ifdef WITH_SELINUX -static void selinux_update_mapping (void); -#endif static long scale_age (long); static void new_spent (struct spwd *); @@ -730,7 +731,7 @@ static void usage (int status) (void) fputs (_(" -U, --user-group create a group with the same name as the user\n"), usageout); #ifdef WITH_SELINUX (void) fputs (_(" -Z, --selinux-user SEUSER use a specific SEUSER for the SELinux user mapping\n"), usageout); -#endif +#endif /* WITH_SELINUX */ (void) fputs ("\n", usageout); exit (status); } @@ -1004,15 +1005,15 @@ static void process_flags (int argc, char **argv) {"user-group", no_argument, NULL, 'U'}, #ifdef WITH_SELINUX {"selinux-user", required_argument, NULL, 'Z'}, -#endif +#endif /* WITH_SELINUX */ {NULL, 0, NULL, '\0'} }; while ((c = getopt_long (argc, argv, #ifdef WITH_SELINUX "b:c:d:De:f:g:G:hk:K:lmMNop:rR:s:u:UZ:", -#else +#else /* !WITH_SELINUX */ "b:c:d:De:f:g:G:hk:K:lmMNop:rR:s:u:U", -#endif +#endif /* !WITH_SELINUX */ long_options, NULL)) != -1) { switch (c) { case 'b': @@ -1213,6 +1214,7 @@ static void process_flags (int argc, char **argv) case 'Z': if (is_selinux_enabled () > 0) { user_selinux = optarg; + Zflg = true; } else { fprintf (stderr, _("%s: -Z requires SELinux enabled kernel\n"), @@ -1221,7 +1223,7 @@ static void process_flags (int argc, char **argv) exit (E_BAD_ARG); } break; -#endif +#endif /* WITH_SELINUX */ default: usage (E_USAGE); } @@ -1745,32 +1747,6 @@ static void usr_update (void) } } -#ifdef WITH_SELINUX -static void selinux_update_mapping (void) { - if (is_selinux_enabled () <= 0) return; - - if ('\0' != *user_selinux) { /* must be done after passwd write() */ - const char *argv[7]; - argv[0] = "/usr/sbin/semanage"; - argv[1] = "login"; - argv[2] = "-a"; - argv[3] = "-s"; - argv[4] = user_selinux; - argv[5] = user_name; - argv[6] = NULL; - if (safe_system (argv[0], argv, NULL, false) != 0) { - fprintf (stderr, - _("%s: warning: the user name %s to %s SELinux user mapping failed.\n"), - Prog, user_name, user_selinux); -#ifdef WITH_AUDIT - audit_logger (AUDIT_ADD_USER, Prog, - "adding SELinux user mapping", - user_name, (unsigned int) user_id, 0); -#endif - } - } -} -#endif /* * create_home - create the user's home directory * @@ -2082,8 +2058,20 @@ int main (int argc, char **argv) close_files (); #ifdef WITH_SELINUX - selinux_update_mapping (); -#endif + if (Zflg && ('\0' != *user_selinux)) { + if (set_seuser (user_name, user_selinux) != 0) { + fprintf (stderr, + _("%s: warning: the user name %s to %s SELinux user mapping failed.\n"), + Prog, user_name, user_selinux); +#ifdef WITH_AUDIT + audit_logger (AUDIT_ADD_USER, Prog, + "adding SELinux user mapping", + user_name, (unsigned int) user_id, 0); +#endif /* WITH_AUDIT */ + fail_exit (E_SE_UPDATE); + } + } +#endif /* WITH_SELINUX */ nscd_flush_cache ("passwd"); nscd_flush_cache ("group"); diff --git a/src/userdel.c b/src/userdel.c index 41813076..6d8d43e7 100644 --- a/src/userdel.c +++ b/src/userdel.c @@ -74,6 +74,7 @@ #define E_USER_BUSY 8 /* user currently logged in */ #define E_GRP_UPDATE 10 /* can't update group file */ #define E_HOMEDIR 12 /* can't remove home directory */ +#define E_SE_UPDATE 14 /* can't update SELinux user mapping */ /* * Global variables @@ -87,6 +88,7 @@ static char *user_home; static bool fflg = false; static bool rflg = false; +static bool Zflg = false; static bool is_shadow_pwd; @@ -134,6 +136,9 @@ static void usage (int status) (void) fputs (_(" -h, --help display this help message and exit\n"), usageout); (void) fputs (_(" -r, --remove remove home directory and mail spool\n"), usageout); (void) fputs (_(" -R, --root CHROOT_DIR directory to chroot into\n"), usageout); +#ifdef WITH_SELINUX + (void) fputs (_(" -Z, --selinux-user remove any SELinux user mapping for the user\n"), usageout); +#endif /* WITH_SELINUX */ (void) fputs ("\n", usageout); exit (status); } @@ -870,13 +875,21 @@ int main (int argc, char **argv) */ int c; static struct option long_options[] = { - {"force", no_argument, NULL, 'f'}, - {"help", no_argument, NULL, 'h'}, - {"remove", no_argument, NULL, 'r'}, - {"root", required_argument, NULL, 'R'}, + {"force", no_argument, NULL, 'f'}, + {"help", no_argument, NULL, 'h'}, + {"remove", no_argument, NULL, 'r'}, + {"root", required_argument, NULL, 'R'}, +#ifdef WITH_SELINUX + {"selinux-user", no_argument, NULL, 'Z'}, +#endif /* WITH_SELINUX */ {NULL, 0, NULL, '\0'} }; - while ((c = getopt_long (argc, argv, "fhrR:", + while ((c = getopt_long (argc, argv, +#ifdef WITH_SELINUX + "fhrR:Z", +#else /* !WITH_SELINUX */ + "fhrR:", +#endif /* !WITH_SELINUX */ long_options, NULL)) != -1) { switch (c) { case 'f': /* force remove even if not owned by user */ @@ -890,6 +903,19 @@ int main (int argc, char **argv) break; case 'R': /* no-op, handled in process_root_flag () */ break; +#ifdef WITH_SELINUX + case 'Z': + if (is_selinux_enabled () > 0) { + Zflg = true; + } else { + fprintf (stderr, + _("%s: -Z requires SELinux enabled kernel\n"), + Prog); + + exit (E_BAD_ARG); + } + break; +#endif /* WITH_SELINUX */ default: usage (E_USAGE); } @@ -1091,14 +1117,18 @@ int main (int argc, char **argv) #endif /* WITH_AUDIT */ #ifdef WITH_SELINUX - if (is_selinux_enabled () > 0) { - const char *args[5]; - args[0] = "/usr/sbin/semanage"; - args[1] = "login"; - args[2] = "-d"; - args[3] = user_name; - args[4] = NULL; - safe_system (args[0], args, NULL, true); + if (Zflg) { + if (del_seuser (user_name) != 0) { + fprintf (stderr, + _("%s: warning: the user name %s to SELinux user mapping removal failed.\n"), + Prog, user_name); +#ifdef WITH_AUDIT + audit_logger (AUDIT_ADD_USER, Prog, + "removing SELinux user mapping", + user_name, (unsigned int) user_id, 0); +#endif /* WITH_AUDIT */ + fail_exit (E_SE_UPDATE); + } } #endif /* WITH_SELINUX */ diff --git a/src/usermod.c b/src/usermod.c index 19781aad..b8e56fde 100644 --- a/src/usermod.c +++ b/src/usermod.c @@ -85,6 +85,7 @@ #define E_GRP_UPDATE 10 /* can't update group file */ /* #define E_NOSPACE 11 insufficient space to move home dir */ #define E_HOMEDIR 12 /* unable to complete home dir move */ +#define E_SE_UPDATE 13 /* can't update SELinux user mapping */ #define VALID(s) (strcspn (s, ":\n") == strlen (s)) /* * Global variables @@ -105,7 +106,7 @@ static char *user_newhome; static char *user_shell; #ifdef WITH_SELINUX static const char *user_selinux = ""; -#endif +#endif /* WITH_SELINUX */ static char *user_newshell; static long user_expire; static long user_newexpire; @@ -154,10 +155,6 @@ static void date_to_str (/*@unique@*//*@out@*/char *buf, size_t maxsize, static int get_groups (char *); static /*@noreturn@*/void usage (int status); static void new_pwent (struct passwd *); -#ifdef WITH_SELINUX -static void selinux_update_mapping (void); -#endif - static void new_spent (struct spwd *); static /*@noreturn@*/void fail_exit (int); static void update_group (void); @@ -338,8 +335,8 @@ static /*@noreturn@*/void usage (int status) (void) fputs (_(" -u, --uid UID new UID for the user account\n"), usageout); (void) fputs (_(" -U, --unlock unlock the user account\n"), usageout); #ifdef WITH_SELINUX - (void) fputs (_(" -Z, --selinux-user new SELinux user mapping for the user account\n"), usageout); -#endif + (void) fputs (_(" -Z, --selinux-user SEUSER new SELinux user mapping for the user account\n"), usageout); +#endif /* WITH_SELINUX */ (void) fputs ("\n", usageout); exit (status); } @@ -894,15 +891,15 @@ static void process_flags (int argc, char **argv) {"unlock", no_argument, NULL, 'U'}, #ifdef WITH_SELINUX {"selinux-user", required_argument, NULL, 'Z'}, -#endif +#endif /* WITH_SELINUX */ {NULL, 0, NULL, '\0'} }; while ((c = getopt_long (argc, argv, #ifdef WITH_SELINUX "ac:d:e:f:g:G:hl:Lmop:R:s:u:UZ:", -#else +#else /* !WITH_SELINUX */ "ac:d:e:f:g:G:hl:Lmop:R:s:u:U", -#endif +#endif /* !WITH_SELINUX */ long_options, NULL)) != -1) { switch (c) { case 'a': @@ -1033,7 +1030,7 @@ static void process_flags (int argc, char **argv) exit (E_BAD_ARG); } break; -#endif +#endif /* WITH_SELINUX */ default: usage (E_USAGE); } @@ -1175,7 +1172,7 @@ static void process_flags (int argc, char **argv) lflg || Gflg || gflg || fflg || eflg || dflg || cflg #ifdef WITH_SELINUX || Zflg -#endif +#endif /* WITH_SELINUX */ )) { fprintf (stderr, _("%s: no changes\n"), Prog); exit (E_SUCCESS); @@ -1893,10 +1890,20 @@ int main (int argc, char **argv) nscd_flush_cache ("group"); #ifdef WITH_SELINUX - if (Zflg) { - selinux_update_mapping (); + if (Zflg && *user_selinux) { + if (set_seuser (user_name, user_selinux) != 0) { + fprintf (stderr, + _("%s: warning: the user name %s to %s SELinux user mapping failed.\n"), + Prog, user_name, user_selinux); +#ifdef WITH_AUDIT + audit_logger (AUDIT_USER_CHAUTHTOK, Prog, + "modifying User mapping ", + user_name, (unsigned int) user_id, 0); +#endif /* WITH_AUDIT */ + fail_exit (E_SE_UPDATE); + } } -#endif +#endif /* WITH_SELINUX */ if (mflg) { move_home (); @@ -1906,7 +1913,7 @@ int main (int argc, char **argv) if (lflg || uflg) { move_mailbox (); } -#endif +#endif /* NO_MOVE_MAILBOX */ if (uflg) { update_lastlog (); @@ -1940,36 +1947,3 @@ int main (int argc, char **argv) return E_SUCCESS; } -#ifdef WITH_SELINUX -static void selinux_update_mapping (void) { - const char *argv[7]; - - if (is_selinux_enabled () <= 0) { - return; - } - - if ('\0' != *user_selinux) { - argv[0] = "/usr/sbin/semanage"; - argv[1] = "login"; - argv[2] = "-m"; - argv[3] = "-s"; - argv[4] = user_selinux; - argv[5] = user_name; - argv[6] = NULL; - if (safe_system (argv[0], argv, NULL, true) != 0) { - argv[2] = "-a"; - if (safe_system (argv[0], argv, NULL, false) != 0) { - fprintf (stderr, - _("%s: warning: the user name %s to %s SELinux user mapping failed.\n"), - Prog, user_name, user_selinux); -#ifdef WITH_AUDIT - audit_logger (AUDIT_USER_CHAUTHTOK, Prog, - "modifying User mapping ", - user_name, (unsigned int) user_id, 0); -#endif - } - } - } -} -#endif -