From 8d136297c4be438e5982df3f63433e42456da416 Mon Sep 17 00:00:00 2001 From: nekral-guest Date: Sat, 11 Apr 2009 15:34:10 +0000 Subject: [PATCH] * NEWS, src/useradd.c, man/useradd.8.xml: add -Z option to map SELinux user for user's login. * NEWS, src/usermod.c, man/usermod.8.xml: Likewise. * libmisc/system.c, libmisc/Makefile.am, lib/prototypes.h: Added safe_system(). Used to run semanage. * lib/prototypes.h, libmisc/copydir.c: Make a selinux_file_context() an extern function. * libmisc/copydir.c: Reset SELinux to create files with default contexts at the end of copy_tree(). * NEWS, src/userdel.c: Delete the SELinux user mapping for user's login. --- ChangeLog | 14 +++++++++ NEWS | 6 +++- TODO | 1 + lib/prototypes.h | 10 +++++++ libmisc/Makefile.am | 1 + libmisc/copydir.c | 11 ++++++- libmisc/system.c | 69 ++++++++++++++++++++++++++++++++++++++++++ man/useradd.8.xml | 13 ++++++++ man/usermod.8.xml | 13 ++++++++ src/useradd.c | 66 ++++++++++++++++++++++++++++++++++++++++ src/userdel.c | 11 +++++++ src/usermod.c | 73 ++++++++++++++++++++++++++++++++++++++++++++- 12 files changed, 285 insertions(+), 3 deletions(-) create mode 100644 libmisc/system.c diff --git a/ChangeLog b/ChangeLog index 23547514..748c4230 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,17 @@ +2009-04-11 Peter Vrabec + + * NEWS, src/useradd.c, man/useradd.8.xml: add -Z option to map + SELinux user for user's login. + * NEWS, src/usermod.c, man/usermod.8.xml: Likewise. + * libmisc/system.c, libmisc/Makefile.am, lib/prototypes.h: Added + safe_system(). Used to run semanage. + * lib/prototypes.h, libmisc/copydir.c: Make a + selinux_file_context() an extern function. + * libmisc/copydir.c: Reset SELinux to create files with default + contexts at the end of copy_tree(). + * NEWS, src/userdel.c: Delete the SELinux user mapping for user's + login. + 2009-04-11 Peter Vrabec * src/useradd.c (get_defaults): Close the default file after the diff --git a/NEWS b/NEWS index 1aaf14e1..71ccdf56 100644 --- a/NEWS +++ b/NEWS @@ -89,22 +89,26 @@ shadow-4.1.2.2 -> shadow-4.1.3 UNRELEASED - pwck * warn for users with UID set to (uid_t)-1. - su - * + * Preserve COLORTERM in addition to TERM when su is called with the -l + option. - useradd * audit logging improvements. * Speedup (see "addition of users or groups" above). * See CREATE_HOME above. * New -M/--no-create-home option to disable CREATE_HOME. * do not create users with UID set to (gid_t)-1. + * Added -Z option to map SELinux user for user's login. - userdel * audit logging improvements. * Do not fail if the removed user is not in the shadow database. * When the user's group shall be removed, do not fail if this group is not in the gshadow file. + * Delete the SELinux user mapping for user's login. - usermod * Allow adding LDAP users (or any user not present in the local passwd file) to local groups * do not create users with UID set to (gid_t)-1. + * Added -Z option to map SELinux user for user's login. shadow-4.1.2.1 -> shadow-4.1.2.2 23-11-2008 diff --git a/TODO b/TODO index 13e4a953..85193989 100644 --- a/TODO +++ b/TODO @@ -46,6 +46,7 @@ testsuite newusers - add logging to SYSLOG & AUDIT - use CREATE_HOME + - Add a -Z option (see useradd / usermod) Document when/where option appeared, document whether an option is standard or not. diff --git a/lib/prototypes.h b/lib/prototypes.h index 8a6eead9..f5528a46 100644 --- a/lib/prototypes.h +++ b/lib/prototypes.h @@ -118,6 +118,10 @@ extern int copy_tree (const char *src_root, const char *dst_root, long int uid, long int gid); extern int remove_tree (const char *root); +#ifdef WITH_SELINUX +extern int selinux_file_context (const char *dst_name); +#endif + /* encrypt.c */ extern char *pw_encrypt (const char *, const char *); @@ -304,6 +308,12 @@ extern struct spwd *__spw_dup (const struct spwd *spent); /* shell.c */ extern int shell (const char *, const char *, char *const *); +/* system.c */ +extern int safe_system (const char *command, + const char *argv[], + const char *env[], + int ignore_stderr); + /* strtoday.c */ extern long strtoday (const char *); diff --git a/libmisc/Makefile.am b/libmisc/Makefile.am index e905d879..247eab13 100644 --- a/libmisc/Makefile.am +++ b/libmisc/Makefile.am @@ -48,6 +48,7 @@ libmisc_a_SOURCES = \ setugid.c \ setupenv.c \ shell.c \ + system.c \ strtoday.c \ sub.c \ sulog.c \ diff --git a/libmisc/copydir.c b/libmisc/copydir.c index 951e69ac..1da468c1 100644 --- a/libmisc/copydir.c +++ b/libmisc/copydir.c @@ -83,8 +83,11 @@ static int copy_file (const char *src, const char *dst, * selinux_file_context () should be called before any creation of file, * symlink, directory, ... * + * Callers may have to Reset SELinux to create files with default + * contexts: + * setfscreatecon (NULL); */ -static int selinux_file_context (const char *dst_name) +int selinux_file_context (const char *dst_name) { static bool selinux_checked = false; static bool selinux_enabled; @@ -259,6 +262,12 @@ int copy_tree (const char *src_root, const char *dst_root, src_orig = NULL; dst_orig = NULL; } + +#ifdef WITH_SELINUX + /* Reset SELinux to create files with default contexts */ + setfscreatecon (NULL); +#endif + return err; } diff --git a/libmisc/system.c b/libmisc/system.c new file mode 100644 index 00000000..f92b10be --- /dev/null +++ b/libmisc/system.c @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2009 - , 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 + +#ident "$Id$" + +#include +#include +#include +#include "prototypes.h" +#include "defines.h" + +int safe_system (const char *command, + const char *argv[], + const char *env[], + int ignore_stderr) +{ + int status = -1; + int fd; + pid_t pid; + + pid = fork(); + if (pid < 0) { + return -1; + } + + if (pid) { /* Parent */ + waitpid (pid, &status, 0); + return status; + } + + fd = open ("/dev/null", O_RDWR); + /* Child */ + dup2 (fd, 0); // Close Stdin + if (ignore_stderr) { + dup2 (fd, 2); // Close Stderr + } + + execve (command, (char *const *) argv, (char *const *) env); + fprintf (stderr, _("Failed to exec '%s'\n"), argv[0]); + exit (-1); +} + diff --git a/man/useradd.8.xml b/man/useradd.8.xml index 8fce5c9c..cc781015 100644 --- a/man/useradd.8.xml +++ b/man/useradd.8.xml @@ -459,6 +459,19 @@ + + + , + SEUSER + + + + The SELinux user for the user's login. The default is to leave this + field blank, which causes the system to select the default SELinux + user. + + + diff --git a/man/usermod.8.xml b/man/usermod.8.xml index 6a892700..9a02012d 100644 --- a/man/usermod.8.xml +++ b/man/usermod.8.xml @@ -289,6 +289,19 @@ + + + , + SEUSER + + + + The SELinux user for the user's login. The default is to leave + this field the blank, which causes the system to select the + default SELinux user. + + + diff --git a/src/useradd.c b/src/useradd.c index 476587d7..444cc22e 100644 --- a/src/useradd.c +++ b/src/useradd.c @@ -108,6 +108,9 @@ static const char *user_comment = ""; static const char *user_home = ""; static const char *user_shell = ""; static const char *create_mail_spool = ""; +#ifdef WITH_SELINUX +static const char *user_selinux = ""; +#endif static long user_expire = -1; static bool is_shadow_pwd; @@ -175,6 +178,9 @@ static int set_defaults (void); static int get_groups (char *); static void usage (void); 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 *); @@ -692,6 +698,9 @@ static void usage (void) " -s, --shell SHELL the login shell for the new user account\n" " -u, --uid UID force use the UID for the new user account\n" " -U, --user-group create a group with the same name as the user\n" +#ifdef WITH_SELINUX + " -Z, --selinux-user SEUSER use a specific SEUSER for the SELinux user mapping\n" +#endif "\n"), stderr); exit (E_USAGE); } @@ -954,12 +963,19 @@ static void process_flags (int argc, char **argv) {"password", required_argument, NULL, 'p'}, {"system", no_argument, NULL, 'r'}, {"shell", required_argument, NULL, 's'}, +#ifdef WITH_SELINUX + {"selinux-user", required_argument, NULL, 'Z'}, +#endif {"uid", required_argument, NULL, 'u'}, {"user-group", no_argument, NULL, 'U'}, {NULL, 0, NULL, '\0'} }; while ((c = getopt_long (argc, argv, +#ifdef WITH_SELINUX + "b:c:d:De:f:g:G:k:K:lmMNop:rs:u:UZ:", +#else "b:c:d:De:f:g:G:k:K:lmMNop:rs:u:U", +#endif long_options, NULL)) != -1) { switch (c) { case 'b': @@ -1153,6 +1169,19 @@ static void process_flags (int argc, char **argv) case 'U': Uflg = true; break; +#ifdef WITH_SELINUX + case 'Z': + if (is_selinux_enabled () > 0) { + user_selinux = optarg; + } else { + fprintf (stderr, + _("%s: -Z requires SELinux enabled kernel\n"), + Prog); + + exit (E_BAD_ARG); + } + break; +#endif default: usage (); } @@ -1659,6 +1688,32 @@ static void usr_update (void) } } +#ifdef WITH_SELINUX +static void selinux_update_mapping (void) { + if (is_selinux_enabled () <= 0) return; + + if (*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, 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 * @@ -1669,6 +1724,9 @@ static void usr_update (void) static void create_home (void) { if (access (user_home, F_OK) != 0) { +#ifdef WITH_SELINUX + selinux_file_context (user_home); +#endif /* XXX - create missing parent directories. --marekm */ if (mkdir (user_home, 0) != 0) { fprintf (stderr, @@ -1691,6 +1749,10 @@ static void create_home (void) "adding home directory", user_name, (unsigned int) user_id, SHADOW_AUDIT_SUCCESS); +#endif +#ifdef WITH_SELINUX + /* Reset SELinux to create files with default contexts */ + setfscreatecon (NULL); #endif } } @@ -1940,6 +2002,10 @@ int main (int argc, char **argv) close_files (); +#ifdef WITH_SELINUX + selinux_update_mapping (); +#endif + nscd_flush_cache ("passwd"); nscd_flush_cache ("group"); diff --git a/src/userdel.c b/src/userdel.c index 907a3cd5..52a30231 100644 --- a/src/userdel.c +++ b/src/userdel.c @@ -797,6 +797,17 @@ int main (int argc, char **argv) audit_help_open (); #endif +#ifdef WITH_SELINUX + if (is_selinux_enabled () > 0) { + const char *argv[5]; + argv[0] = "/usr/sbin/semanage"; + argv[1] = "login"; + argv[2] = "-d"; + argv[3] = user_name; + argv[4] = NULL; + safe_system (argv[0], argv, NULL, 1); + } +#endif /* * Get my name so that I can use it to report errors. */ diff --git a/src/usermod.c b/src/usermod.c index 39695637..e860c368 100644 --- a/src/usermod.c +++ b/src/usermod.c @@ -98,6 +98,9 @@ static char *user_newcomment; static char *user_home; static char *user_newhome; static char *user_shell; +#ifdef WITH_SELINUX +static const char *user_selinux = ""; +#endif static char *user_newshell; static long user_expire; static long user_newexpire; @@ -120,6 +123,9 @@ static bool oflg = false, /* permit non-unique user ID to be specified with -u */ pflg = false, /* new encrypted password */ sflg = false, /* new shell program */ +#ifdef WITH_SELINUX + Zflg = false, /* new selinux user */ +#endif uflg = false, /* specify new user ID */ Uflg = false; /* unlock the password */ @@ -143,6 +149,9 @@ static void date_to_str (char *buf, size_t maxsize, static int get_groups (char *); static void usage (void); static void new_pwent (struct passwd *); +#ifdef WITH_SELINUX +static void selinux_update_mapping (void); +#endif static void new_spent (struct spwd *); static void fail_exit (int); @@ -314,6 +323,9 @@ static void usage (void) " -s, --shell SHELL new login shell for the user account\n" " -u, --uid UID new UID for the user account\n" " -U, --unlock unlock the user account\n" +#ifdef WITH_SELINUX + " -Z, --selinux-user new SELinux user mapping for the user account\n" +#endif "\n"), stderr); exit (E_USAGE); } @@ -876,13 +888,20 @@ static void process_flags (int argc, char **argv) {"move-home", no_argument, NULL, 'm'}, {"non-unique", no_argument, NULL, 'o'}, {"password", required_argument, NULL, 'p'}, +#ifdef WITH_SELINUX + {"selinux-user", required_argument, NULL, 'Z'}, +#endif {"shell", required_argument, NULL, 's'}, {"uid", required_argument, NULL, 'u'}, {"unlock", no_argument, NULL, 'U'}, {NULL, 0, NULL, '\0'} }; while ((c = getopt_long (argc, argv, +#ifdef WITH_SELINUX + "ac:d:e:f:g:G:hl:Lmop:s:u:UZ:", +#else "ac:d:e:f:g:G:hl:Lmop:s:u:U", +#endif long_options, NULL)) != -1) { switch (c) { case 'a': @@ -996,6 +1015,19 @@ static void process_flags (int argc, char **argv) case 'U': Uflg = true; break; +#ifdef WITH_SELINUX + case 'Z': + if (is_selinux_enabled () > 0) { + user_selinux = optarg; + Zflg = true; + } else { + fprintf (stderr, + _("%s: -Z requires SELinux enabled kernel\n"), + Prog); + exit (E_BAD_ARG); + } + break; +#endif default: usage (); } @@ -1036,7 +1068,11 @@ static void process_flags (int argc, char **argv) } if (!(Uflg || uflg || sflg || pflg || oflg || mflg || Lflg || - lflg || Gflg || gflg || fflg || eflg || dflg || cflg)) { + lflg || Gflg || gflg || fflg || eflg || dflg || cflg +#ifdef WITH_SELINUX + || Zflg +#endif + )) { fprintf (stderr, _("%s: no changes\n"), Prog); exit (E_SUCCESS); } @@ -1722,6 +1758,10 @@ int main (int argc, char **argv) nscd_flush_cache ("passwd"); nscd_flush_cache ("group"); +#ifdef WITH_SELINUX + selinux_update_mapping (); +#endif + if (mflg) { move_home (); } @@ -1749,3 +1789,34 @@ int main (int argc, char **argv) /* NOT REACHED */ } +#ifdef WITH_SELINUX +static void selinux_update_mapping (void) { + const char *argv[7]; + + if (is_selinux_enabled () <= 0) return; + + if (*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, 1)) { + argv[2] = "-a"; + if (safe_system (argv[0], argv, NULL, 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 +