diff -up /dev/null shadow-4.1.1/libmisc/system.c --- /dev/null 2008-03-19 11:34:26.687502959 +0100 +++ shadow-4.1.1/libmisc/system.c 2008-04-05 14:55:29.000000000 +0200 @@ -0,0 +1,37 @@ +#include + +#ident "$Id: shell.c,v 1.13 2006/01/18 19:38:27 kloczek Exp $" + +#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 -up shadow-4.1.1/libmisc/copydir.c.selinux shadow-4.1.1/libmisc/copydir.c --- shadow-4.1.1/libmisc/copydir.c.selinux 2008-01-06 13:02:04.000000000 +0100 +++ shadow-4.1.1/libmisc/copydir.c 2008-04-05 14:55:29.000000000 +0200 @@ -82,7 +82,7 @@ static int copy_file (const char *src, c * symlink, directory, ... * */ -static int selinux_file_context (const char *dst_name) +int selinux_file_context (const char *dst_name) { security_context_t scontext = NULL; @@ -253,6 +253,12 @@ int copy_tree (const char *src_root, con src_orig = 0; dst_orig = 0; } + +#ifdef WITH_SELINUX + /* Reset SELinux to create files with default contexts */ + setfscreatecon (NULL); +#endif + return err; } diff -up shadow-4.1.1/libmisc/Makefile.am.selinux shadow-4.1.1/libmisc/Makefile.am --- shadow-4.1.1/libmisc/Makefile.am.selinux 2008-01-27 15:21:48.000000000 +0100 +++ shadow-4.1.1/libmisc/Makefile.am 2008-04-05 14:55:29.000000000 +0200 @@ -43,6 +43,7 @@ libmisc_a_SOURCES = \ setugid.c \ setupenv.c \ shell.c \ + system.c \ strtoday.c \ sub.c \ sulog.c \ diff -up shadow-4.1.1/src/useradd.c.selinux shadow-4.1.1/src/useradd.c --- shadow-4.1.1/src/useradd.c.selinux 2008-04-05 14:55:29.000000000 +0200 +++ shadow-4.1.1/src/useradd.c 2008-04-05 14:55:29.000000000 +0200 @@ -101,6 +101,7 @@ static const char *user_comment = ""; static const char *user_home = ""; static const char *user_shell = ""; static const char *create_mail_spool = ""; +static const char *user_selinux = ""; static long user_expire = -1; static int is_shadow_pwd; @@ -173,6 +174,7 @@ static int set_defaults (void); static int get_groups (char *); static void usage (void); static void new_pwent (struct passwd *); +static void selinux_update_mapping (void); static long scale_age (long); static void new_spent (struct spwd *); @@ -373,6 +375,7 @@ static void get_defaults (void) def_create_mail_spool = xstrdup (cp); } } + fclose(fp); } /* @@ -665,6 +668,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); } @@ -880,12 +886,19 @@ static void process_flags (int argc, cha {"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 = +#ifdef WITH_SELINUX + getopt_long (argc, argv, "b:c:d:De:f:g:G:k:K:lmMnNop:rs:u:UZ:", +#else getopt_long (argc, argv, "b:c:d:De:f:g:G:k:K:lmMnNop:rs:u:U", +#endif long_options, NULL)) != -1) { switch (c) { case 'b': @@ -1070,6 +1083,17 @@ static void process_flags (int argc, cha case 'U': Uflg++; 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 (); } @@ -1476,6 +1500,33 @@ static void usr_update (void) grp_update (); } +static void selinux_update_mapping () { + +#ifdef WITH_SELINUX + 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_USER_CHAUTHTOK, Prog, + "adding SELinux user mapping", user_name, user_id, 0); +#endif + } + } +#endif + +} /* * create_home - create the user's home directory * @@ -1485,7 +1536,11 @@ static void usr_update (void) */ static void create_home (void) { + if (access (user_home, F_OK)) { +#ifdef WITH_SELINUX + selinux_file_context (user_home); +#endif /* XXX - create missing parent directories. --marekm */ if (mkdir (user_home, 0)) { fprintf (stderr, @@ -1507,6 +1562,10 @@ static void create_home (void) audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "adding home directory", user_name, user_id, 1); #endif +#ifdef WITH_SELINUX + /* Reset SELinux to create files with default contexts */ + setfscreatecon (NULL); +#endif } } @@ -1760,6 +1819,8 @@ int main (int argc, char **argv) close_files (); + selinux_update_mapping(); + nscd_flush_cache ("passwd"); nscd_flush_cache ("group"); diff -up shadow-4.1.1/src/usermod.c.selinux shadow-4.1.1/src/usermod.c --- shadow-4.1.1/src/usermod.c.selinux 2008-02-24 13:35:13.000000000 +0100 +++ shadow-4.1.1/src/usermod.c 2008-04-05 14:55:29.000000000 +0200 @@ -91,6 +91,7 @@ static char *user_newcomment; static char *user_home; static char *user_newhome; static char *user_shell; +static const char *user_selinux = ""; static char *user_newshell; static long user_expire; static long user_newexpire; @@ -138,6 +139,7 @@ static void date_to_str (char *buf, size static int get_groups (char *); static void usage (void); static void new_pwent (struct passwd *); +static void selinux_update_mapping (void); static void new_spent (struct spwd *); static void fail_exit (int); @@ -320,6 +322,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); } @@ -846,13 +851,20 @@ static void process_flags (int argc, cha {"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, "ac:d:e:f:g:G:hl:Lmop:s:u:U", +#ifdef WITH_SELINUX + getopt_long (argc, argv, "ac:d:e:f:g:G:hl:Lmop:s:u:UZ:", +#else + getopt_long (argc, argv, "ac:d:e:f:g:G:hl:Lmop:s:u:U", +#endif long_options, NULL)) != -1) { switch (c) { case 'a': @@ -953,6 +965,16 @@ static void process_flags (int argc, cha case 'U': Uflg++; 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 (); } @@ -1530,6 +1552,8 @@ int main (int argc, char **argv) nscd_flush_cache ("passwd"); nscd_flush_cache ("group"); + selinux_update_mapping(); + if (mflg) move_home (); @@ -1558,3 +1582,62 @@ int main (int argc, char **argv) exit (E_SUCCESS); /* NOT REACHED */ } + +static void selinux_update_mapping () { +#ifdef WITH_SELINUX + 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, user_id, 0); +#endif + } + } + } + + if (dflg || *user_selinux) { + argv[0] = "/usr/sbin/genhomedircon"; + argv[1] = NULL; + if(safe_system(argv[0], argv, NULL,0)) { + fprintf (stderr, + _("%s: warning: unable to relabel the homedir %s for %s.\n"), + Prog, user_home, user_name); +#ifdef WITH_AUDIT + audit_logger (AUDIT_USER_CHAUTHTOK, Prog, + "relabeling home directory", user_name, user_id, 0); +#endif + } + + argv[0] = "/sbin/restorecon"; + argv[1] = "-F"; + argv[2] = "-R"; + argv[3] = user_home; + argv[4] = NULL; + if (safe_system(argv[0], argv, NULL, 0)) { + fprintf (stderr, + _("%s: warning: unable to relabel the homedir %s for %s.\n"), + Prog, user_home, user_name); +#ifdef WITH_AUDIT + audit_logger (AUDIT_USER_CHAUTHTOK, Prog, + "relabeling home directory", user_name, user_id, 0); +#endif + } + } +#endif +} diff -up shadow-4.1.1/src/userdel.c.selinux shadow-4.1.1/src/userdel.c --- shadow-4.1.1/src/userdel.c.selinux 2008-03-08 21:48:26.000000000 +0100 +++ shadow-4.1.1/src/userdel.c 2008-04-05 14:55:29.000000000 +0200 @@ -809,6 +809,17 @@ int main (int argc, char **argv) #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 /* * Cancel any crontabs or at jobs. Have to do this before we remove * the entry from /etc/passwd. diff -up shadow-4.1.1/man/useradd.8.selinux shadow-4.1.1/man/useradd.8 --- shadow-4.1.1/man/useradd.8.selinux 2008-04-05 14:55:29.000000000 +0200 +++ shadow-4.1.1/man/useradd.8 2008-04-05 15:00:03.000000000 +0200 @@ -219,6 +219,11 @@ options are not specified) is defined by variable in \fIlogin\.defs\fR\. .RE +.PP +\fB\-Z\fR, \fB\-\-selinux-user\fR \fISEUSER\fR +.RS 4 +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\. +.RE .SS "Changing the default values" .PP When invoked with only the diff -up shadow-4.1.1/man/usermod.8.xml.selinux shadow-4.1.1/man/usermod.8.xml --- shadow-4.1.1/man/usermod.8.xml.selinux 2007-12-31 17:48:34.000000000 +0100 +++ shadow-4.1.1/man/usermod.8.xml 2008-04-05 14:55:29.000000000 +0200 @@ -245,6 +245,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 -up shadow-4.1.1/man/usermod.8.selinux shadow-4.1.1/man/usermod.8 --- shadow-4.1.1/man/usermod.8.selinux 2008-04-03 00:43:16.000000000 +0200 +++ shadow-4.1.1/man/usermod.8 2008-04-05 14:55:29.000000000 +0200 @@ -133,6 +133,11 @@ Note: if you wish to unlock the account value from \fI/etc/default/useradd\fR)\. .RE +.PP +\fB\-Z\fR, \fB\-\-selinux-user\fR \fISEUSER\fR +.RS 4 +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. +.RE .SH "CAVEATS" .PP diff -up shadow-4.1.1/man/useradd.8.xml.selinux shadow-4.1.1/man/useradd.8.xml --- shadow-4.1.1/man/useradd.8.xml.selinux 2008-02-25 22:01:23.000000000 +0100 +++ shadow-4.1.1/man/useradd.8.xml 2008-04-05 14:55:29.000000000 +0200 @@ -326,6 +326,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 -up shadow-4.1.1/lib/defines.h.selinux shadow-4.1.1/lib/defines.h --- shadow-4.1.1/lib/defines.h.selinux 2008-02-03 18:52:52.000000000 +0100 +++ shadow-4.1.1/lib/defines.h 2008-04-05 14:55:29.000000000 +0200 @@ -321,4 +321,7 @@ extern char *strerror (); # define unused #endif +#ifdef WITH_SELINUX +#include +#endif #endif /* _DEFINES_H_ */ diff -up shadow-4.1.1/lib/prototypes.h.selinux shadow-4.1.1/lib/prototypes.h --- shadow-4.1.1/lib/prototypes.h.selinux 2008-03-18 00:01:32.000000000 +0100 +++ shadow-4.1.1/lib/prototypes.h 2008-04-05 15:03:41.000000000 +0200 @@ -51,6 +51,10 @@ extern int copy_tree (const char *src_ro 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 *); @@ -194,6 +198,9 @@ extern struct spwd *__spw_dup (const str /* 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 *);