* 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.
This commit is contained in:
nekral-guest 2009-04-11 15:34:10 +00:00
parent 2c400eff94
commit 8d136297c4
12 changed files with 285 additions and 3 deletions

View File

@ -1,3 +1,17 @@
2009-04-11 Peter Vrabec <pvrabec@redhat.com>
* 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 <pvrabec@redhat.com> 2009-04-11 Peter Vrabec <pvrabec@redhat.com>
* src/useradd.c (get_defaults): Close the default file after the * src/useradd.c (get_defaults): Close the default file after the

6
NEWS
View File

@ -89,22 +89,26 @@ shadow-4.1.2.2 -> shadow-4.1.3 UNRELEASED
- pwck - pwck
* warn for users with UID set to (uid_t)-1. * warn for users with UID set to (uid_t)-1.
- su - su
* * Preserve COLORTERM in addition to TERM when su is called with the -l
option.
- useradd - useradd
* audit logging improvements. * audit logging improvements.
* Speedup (see "addition of users or groups" above). * Speedup (see "addition of users or groups" above).
* See CREATE_HOME above. * See CREATE_HOME above.
* New -M/--no-create-home option to disable CREATE_HOME. * New -M/--no-create-home option to disable CREATE_HOME.
* do not create users with UID set to (gid_t)-1. * do not create users with UID set to (gid_t)-1.
* Added -Z option to map SELinux user for user's login.
- userdel - userdel
* audit logging improvements. * audit logging improvements.
* Do not fail if the removed user is not in the shadow database. * 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 * When the user's group shall be removed, do not fail if this group is
not in the gshadow file. not in the gshadow file.
* Delete the SELinux user mapping for user's login.
- usermod - usermod
* Allow adding LDAP users (or any user not present in the local passwd * Allow adding LDAP users (or any user not present in the local passwd
file) to local groups file) to local groups
* do not create users with UID set to (gid_t)-1. * 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 shadow-4.1.2.1 -> shadow-4.1.2.2 23-11-2008

1
TODO
View File

@ -46,6 +46,7 @@ testsuite
newusers newusers
- add logging to SYSLOG & AUDIT - add logging to SYSLOG & AUDIT
- use CREATE_HOME - use CREATE_HOME
- Add a -Z option (see useradd / usermod)
Document when/where option appeared, document whether an option is standard Document when/where option appeared, document whether an option is standard
or not. or not.

View File

@ -118,6 +118,10 @@ extern int copy_tree (const char *src_root, const char *dst_root,
long int uid, long int gid); long int uid, long int gid);
extern int remove_tree (const char *root); extern int remove_tree (const char *root);
#ifdef WITH_SELINUX
extern int selinux_file_context (const char *dst_name);
#endif
/* encrypt.c */ /* encrypt.c */
extern char *pw_encrypt (const char *, const char *); extern char *pw_encrypt (const char *, const char *);
@ -304,6 +308,12 @@ extern struct spwd *__spw_dup (const struct spwd *spent);
/* shell.c */ /* shell.c */
extern int shell (const char *, const char *, char *const *); 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 */ /* strtoday.c */
extern long strtoday (const char *); extern long strtoday (const char *);

View File

@ -48,6 +48,7 @@ libmisc_a_SOURCES = \
setugid.c \ setugid.c \
setupenv.c \ setupenv.c \
shell.c \ shell.c \
system.c \
strtoday.c \ strtoday.c \
sub.c \ sub.c \
sulog.c \ sulog.c \

View File

@ -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, * selinux_file_context () should be called before any creation of file,
* symlink, directory, ... * 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_checked = false;
static bool selinux_enabled; static bool selinux_enabled;
@ -259,6 +262,12 @@ int copy_tree (const char *src_root, const char *dst_root,
src_orig = NULL; src_orig = NULL;
dst_orig = NULL; dst_orig = NULL;
} }
#ifdef WITH_SELINUX
/* Reset SELinux to create files with default contexts */
setfscreatecon (NULL);
#endif
return err; return err;
} }

69
libmisc/system.c Normal file
View File

@ -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 <config.h>
#ident "$Id$"
#include <stdio.h>
#include <sys/wait.h>
#include <fcntl.h>
#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);
}

View File

@ -459,6 +459,19 @@
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>
<option>-Z</option>, <option>--selinux-user</option>
<replaceable>SEUSER</replaceable>
</term>
<listitem>
<para>
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.
</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
<refsect2 id='changing_the_default_values'> <refsect2 id='changing_the_default_values'>

View File

@ -289,6 +289,19 @@
</para> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>
<varlistentry>
<term>
<option>-Z</option>, <option>--selinux-user</option>
<replaceable>SEUSER</replaceable>
</term>
<listitem>
<para>
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.
</para>
</listitem>
</varlistentry>
</variablelist> </variablelist>
</refsect1> </refsect1>

View File

@ -108,6 +108,9 @@ static const char *user_comment = "";
static const char *user_home = ""; static const char *user_home = "";
static const char *user_shell = ""; static const char *user_shell = "";
static const char *create_mail_spool = ""; static const char *create_mail_spool = "";
#ifdef WITH_SELINUX
static const char *user_selinux = "";
#endif
static long user_expire = -1; static long user_expire = -1;
static bool is_shadow_pwd; static bool is_shadow_pwd;
@ -175,6 +178,9 @@ static int set_defaults (void);
static int get_groups (char *); static int get_groups (char *);
static void usage (void); static void usage (void);
static void new_pwent (struct passwd *); static void new_pwent (struct passwd *);
#ifdef WITH_SELINUX
static void selinux_update_mapping (void);
#endif
static long scale_age (long); static long scale_age (long);
static void new_spent (struct spwd *); 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" " -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, --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" " -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); "\n"), stderr);
exit (E_USAGE); exit (E_USAGE);
} }
@ -954,12 +963,19 @@ static void process_flags (int argc, char **argv)
{"password", required_argument, NULL, 'p'}, {"password", required_argument, NULL, 'p'},
{"system", no_argument, NULL, 'r'}, {"system", no_argument, NULL, 'r'},
{"shell", required_argument, NULL, 's'}, {"shell", required_argument, NULL, 's'},
#ifdef WITH_SELINUX
{"selinux-user", required_argument, NULL, 'Z'},
#endif
{"uid", required_argument, NULL, 'u'}, {"uid", required_argument, NULL, 'u'},
{"user-group", no_argument, NULL, 'U'}, {"user-group", no_argument, NULL, 'U'},
{NULL, 0, NULL, '\0'} {NULL, 0, NULL, '\0'}
}; };
while ((c = getopt_long (argc, argv, 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", "b:c:d:De:f:g:G:k:K:lmMNop:rs:u:U",
#endif
long_options, NULL)) != -1) { long_options, NULL)) != -1) {
switch (c) { switch (c) {
case 'b': case 'b':
@ -1153,6 +1169,19 @@ static void process_flags (int argc, char **argv)
case 'U': case 'U':
Uflg = true; Uflg = true;
break; 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: default:
usage (); 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 * create_home - create the user's home directory
* *
@ -1669,6 +1724,9 @@ static void usr_update (void)
static void create_home (void) static void create_home (void)
{ {
if (access (user_home, F_OK) != 0) { if (access (user_home, F_OK) != 0) {
#ifdef WITH_SELINUX
selinux_file_context (user_home);
#endif
/* XXX - create missing parent directories. --marekm */ /* XXX - create missing parent directories. --marekm */
if (mkdir (user_home, 0) != 0) { if (mkdir (user_home, 0) != 0) {
fprintf (stderr, fprintf (stderr,
@ -1691,6 +1749,10 @@ static void create_home (void)
"adding home directory", "adding home directory",
user_name, (unsigned int) user_id, user_name, (unsigned int) user_id,
SHADOW_AUDIT_SUCCESS); SHADOW_AUDIT_SUCCESS);
#endif
#ifdef WITH_SELINUX
/* Reset SELinux to create files with default contexts */
setfscreatecon (NULL);
#endif #endif
} }
} }
@ -1940,6 +2002,10 @@ int main (int argc, char **argv)
close_files (); close_files ();
#ifdef WITH_SELINUX
selinux_update_mapping ();
#endif
nscd_flush_cache ("passwd"); nscd_flush_cache ("passwd");
nscd_flush_cache ("group"); nscd_flush_cache ("group");

View File

@ -797,6 +797,17 @@ int main (int argc, char **argv)
audit_help_open (); audit_help_open ();
#endif #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. * Get my name so that I can use it to report errors.
*/ */

View File

@ -98,6 +98,9 @@ static char *user_newcomment;
static char *user_home; static char *user_home;
static char *user_newhome; static char *user_newhome;
static char *user_shell; static char *user_shell;
#ifdef WITH_SELINUX
static const char *user_selinux = "";
#endif
static char *user_newshell; static char *user_newshell;
static long user_expire; static long user_expire;
static long user_newexpire; static long user_newexpire;
@ -120,6 +123,9 @@ static bool
oflg = false, /* permit non-unique user ID to be specified with -u */ oflg = false, /* permit non-unique user ID to be specified with -u */
pflg = false, /* new encrypted password */ pflg = false, /* new encrypted password */
sflg = false, /* new shell program */ sflg = false, /* new shell program */
#ifdef WITH_SELINUX
Zflg = false, /* new selinux user */
#endif
uflg = false, /* specify new user ID */ uflg = false, /* specify new user ID */
Uflg = false; /* unlock the password */ 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 int get_groups (char *);
static void usage (void); static void usage (void);
static void new_pwent (struct passwd *); static void new_pwent (struct passwd *);
#ifdef WITH_SELINUX
static void selinux_update_mapping (void);
#endif
static void new_spent (struct spwd *); static void new_spent (struct spwd *);
static void fail_exit (int); static void fail_exit (int);
@ -314,6 +323,9 @@ static void usage (void)
" -s, --shell SHELL new login shell for the user account\n" " -s, --shell SHELL new login shell for the user account\n"
" -u, --uid UID new UID for the user account\n" " -u, --uid UID new UID for the user account\n"
" -U, --unlock unlock 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); "\n"), stderr);
exit (E_USAGE); exit (E_USAGE);
} }
@ -876,13 +888,20 @@ static void process_flags (int argc, char **argv)
{"move-home", no_argument, NULL, 'm'}, {"move-home", no_argument, NULL, 'm'},
{"non-unique", no_argument, NULL, 'o'}, {"non-unique", no_argument, NULL, 'o'},
{"password", required_argument, NULL, 'p'}, {"password", required_argument, NULL, 'p'},
#ifdef WITH_SELINUX
{"selinux-user", required_argument, NULL, 'Z'},
#endif
{"shell", required_argument, NULL, 's'}, {"shell", required_argument, NULL, 's'},
{"uid", required_argument, NULL, 'u'}, {"uid", required_argument, NULL, 'u'},
{"unlock", no_argument, NULL, 'U'}, {"unlock", no_argument, NULL, 'U'},
{NULL, 0, NULL, '\0'} {NULL, 0, NULL, '\0'}
}; };
while ((c = getopt_long (argc, argv, 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", "ac:d:e:f:g:G:hl:Lmop:s:u:U",
#endif
long_options, NULL)) != -1) { long_options, NULL)) != -1) {
switch (c) { switch (c) {
case 'a': case 'a':
@ -996,6 +1015,19 @@ static void process_flags (int argc, char **argv)
case 'U': case 'U':
Uflg = true; Uflg = true;
break; 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: default:
usage (); usage ();
} }
@ -1036,7 +1068,11 @@ static void process_flags (int argc, char **argv)
} }
if (!(Uflg || uflg || sflg || pflg || oflg || mflg || Lflg || 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); fprintf (stderr, _("%s: no changes\n"), Prog);
exit (E_SUCCESS); exit (E_SUCCESS);
} }
@ -1722,6 +1758,10 @@ int main (int argc, char **argv)
nscd_flush_cache ("passwd"); nscd_flush_cache ("passwd");
nscd_flush_cache ("group"); nscd_flush_cache ("group");
#ifdef WITH_SELINUX
selinux_update_mapping ();
#endif
if (mflg) { if (mflg) {
move_home (); move_home ();
} }
@ -1749,3 +1789,34 @@ int main (int argc, char **argv)
/* NOT REACHED */ /* 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