diff -up /dev/null shadow-4.1.0/libmisc/system.c --- /dev/null 2007-12-08 00:31:02.590331462 +0100 +++ shadow-4.1.0/libmisc/system.c 2007-12-12 14:13:30.000000000 +0100 @@ -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.0/libmisc/copydir.c.selinux shadow-4.1.0/libmisc/copydir.c --- shadow-4.1.0/libmisc/copydir.c.selinux 2007-11-11 00:45:59.000000000 +0100 +++ shadow-4.1.0/libmisc/copydir.c 2007-12-12 14:13:30.000000000 +0100 @@ -54,7 +54,7 @@ struct link_name { static struct link_name *links; #ifdef WITH_SELINUX -static int selinux_file_context (const char *dst_name) +int selinux_file_context (const char *dst_name) { security_context_t scontext = NULL; diff -up shadow-4.1.0/libmisc/Makefile.am.selinux shadow-4.1.0/libmisc/Makefile.am --- shadow-4.1.0/libmisc/Makefile.am.selinux 2007-11-23 10:15:48.000000000 +0100 +++ shadow-4.1.0/libmisc/Makefile.am 2007-12-12 14:13:30.000000000 +0100 @@ -42,6 +42,7 @@ libmisc_a_SOURCES = \ setugid.c \ setupenv.c \ shell.c \ + system.c \ strtoday.c \ sub.c \ sulog.c \ diff -up shadow-4.1.0/src/useradd.c.selinux shadow-4.1.0/src/useradd.c --- shadow-4.1.0/src/useradd.c.selinux 2007-12-12 14:11:41.000000000 +0100 +++ shadow-4.1.0/src/useradd.c 2007-12-12 14:24:12.000000000 +0100 @@ -100,6 +100,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; @@ -170,6 +171,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 *); @@ -356,6 +358,7 @@ static void get_defaults (void) def_create_mail_spool = xstrdup (cp); } } + fclose(fp); } /* @@ -644,6 +647,10 @@ static void usage (void) " 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" +#ifdef WITH_SELINUX + " -Z, --selinux-user SEUSER use a specific SEUSER for the SELinux user mapping\n" +#endif + "\n")); exit (E_USAGE); } @@ -1030,11 +1037,18 @@ static void process_flags (int argc, cha {"non-unique", no_argument, NULL, 'o'}, {"password", required_argument, NULL, 'p'}, {"shell", required_argument, NULL, 's'}, +#ifdef WITH_SELINUX + {"selinux-user", required_argument, NULL, 'Z'}, +#endif {"uid", required_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:mlMnrop:s:u:Z:", +#else getopt_long (argc, argv, "b:c:d:De:f:g:G:k:K:mlMnrop:s:u:", +#endif long_options, NULL)) != -1) { switch (c) { case 'b': @@ -1215,6 +1229,17 @@ static void process_flags (int argc, cha case 'M': Mflg++; 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 (); } @@ -1583,6 +1608,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 * @@ -1592,7 +1644,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, @@ -1818,6 +1874,8 @@ int main (int argc, char **argv) usr_update (); + selinux_update_mapping(); + if (mflg) { create_home (); if (home_added) diff -up shadow-4.1.0/src/usermod.c.selinux shadow-4.1.0/src/usermod.c --- shadow-4.1.0/src/usermod.c.selinux 2007-11-24 23:41:19.000000000 +0100 +++ shadow-4.1.0/src/usermod.c 2007-12-12 14:21:44.000000000 +0100 @@ -90,6 +90,7 @@ static char *user_comment; static char *user_home; static char *user_newhome; static char *user_shell; +static const char *user_selinux = ""; static long user_expire; static long user_inactive; static long sys_ngroups; @@ -139,6 +140,7 @@ static int sgr_locked = 0; 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); @@ -302,6 +304,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")); exit (E_USAGE); } @@ -888,13 +893,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 = +#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': @@ -1028,6 +1040,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 (); } @@ -1575,6 +1597,8 @@ int main (int argc, char **argv) nscd_flush_cache ("passwd"); nscd_flush_cache ("group"); + selinux_update_mapping(); + if (mflg) move_home (); @@ -1603,3 +1627,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.0/src/userdel.c.selinux shadow-4.1.0/src/userdel.c --- shadow-4.1.0/src/userdel.c.selinux 2007-11-24 23:41:19.000000000 +0100 +++ shadow-4.1.0/src/userdel.c 2007-12-12 14:13:30.000000000 +0100 @@ -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.0/man/useradd.8.selinux shadow-4.1.0/man/useradd.8 --- shadow-4.1.0/man/useradd.8.selinux 2007-12-12 14:11:41.000000000 +0100 +++ shadow-4.1.0/man/useradd.8 2007-12-12 14:19:21.000000000 +0100 @@ -163,6 +163,11 @@ doesn\'t work yet\. Allow the creation of a user account with a duplicate (non\-unique) UID\. .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 +.PP \fB\-p\fR, \fB\-\-password\fR \fIPASSWORD\fR .RS 4 The encrypted password, as returned by diff -up shadow-4.1.0/man/usermod.8.xml.selinux shadow-4.1.0/man/usermod.8.xml --- shadow-4.1.0/man/usermod.8.xml.selinux 2007-12-09 00:24:36.000000000 +0100 +++ shadow-4.1.0/man/usermod.8.xml 2007-12-12 14:13:30.000000000 +0100 @@ -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.0/man/usermod.8.selinux shadow-4.1.0/man/usermod.8 --- shadow-4.1.0/man/usermod.8.selinux 2007-12-10 00:07:16.000000000 +0100 +++ shadow-4.1.0/man/usermod.8 2007-12-12 14:17:10.000000000 +0100 @@ -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.0/man/useradd.8.xml.selinux shadow-4.1.0/man/useradd.8.xml --- shadow-4.1.0/man/useradd.8.xml.selinux 2007-12-09 00:24:36.000000000 +0100 +++ shadow-4.1.0/man/useradd.8.xml 2007-12-12 14:13:30.000000000 +0100 @@ -274,6 +274,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.0/lib/defines.h.selinux shadow-4.1.0/lib/defines.h --- shadow-4.1.0/lib/defines.h.selinux 2007-11-24 12:18:35.000000000 +0100 +++ shadow-4.1.0/lib/defines.h 2007-12-12 14:13:30.000000000 +0100 @@ -342,4 +342,7 @@ extern char *strerror (); #include #endif +#ifdef WITH_SELINUX +#include +#endif #endif /* _DEFINES_H_ */ diff -up shadow-4.1.0/lib/prototypes.h.selinux shadow-4.1.0/lib/prototypes.h --- shadow-4.1.0/lib/prototypes.h.selinux 2007-11-23 21:10:52.000000000 +0100 +++ shadow-4.1.0/lib/prototypes.h 2007-12-12 14:13:30.000000000 +0100 @@ -53,6 +53,9 @@ extern int is_listed (const char *, cons /* copydir.c */ extern int copy_tree (const char *, const char *, uid_t, gid_t); extern int remove_tree (const char *); +#ifdef WITH_SELINUX +extern int selinux_file_context (const char *dst_name); +#endif /* encrypt.c */ extern char *pw_encrypt (const char *, const char *); @@ -151,6 +154,9 @@ extern void setup_env (struct passwd *); /* 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 *);