diff -upb shadow-4.1.0/libmisc/system.c.selinux shadow-4.1.0/libmisc/system.c --- shadow-4.1.0/libmisc/system.c.selinux 2008-03-03 14:18:17.000000000 +0100 +++ shadow-4.1.0/libmisc/system.c 2008-03-03 14:18:17.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 -upb 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 2008-03-03 14:18:17.000000000 +0100 @@ -42,6 +42,7 @@ libmisc_a_SOURCES = \ setugid.c \ setupenv.c \ shell.c \ + system.c \ strtoday.c \ sub.c \ sulog.c \ diff -upb 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 2008-03-03 14:19:01.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; @@ -199,7 +199,7 @@ int copy_tree (const char *src_root, con if (strlen (src_root) + strlen (ent->d_name) + 2 > sizeof src_name) { err++; - break; + break; } snprintf (src_name, sizeof src_name, "%s/%s", src_root, ent->d_name); @@ -207,7 +207,7 @@ int copy_tree (const char *src_root, con if (strlen (dst_root) + strlen (ent->d_name) + 2 > sizeof dst_name) { err++; - break; + break; } snprintf (dst_name, sizeof dst_name, "%s/%s", dst_root, ent->d_name); @@ -313,7 +313,7 @@ int copy_tree (const char *src_root, con if (mknod (dst_name, sb.st_mode & ~07777, sb.st_rdev) || chown (dst_name, uid == (uid_t) - 1 ? sb.st_uid : uid, - gid == (gid_t) - 1 ? sb.st_gid : gid) + gid == (gid_t) - 1 ? sb.st_gid : gid) || chmod (dst_name, sb.st_mode & 07777)) { err++; break; @@ -363,6 +363,10 @@ 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 ? -1 : 0; } diff -upb 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 2008-03-03 14:18:17.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 -upb shadow-4.1.0/man/useradd.8.selinux shadow-4.1.0/man/useradd.8 --- shadow-4.1.0/man/useradd.8.selinux 2008-03-03 14:14:45.000000000 +0100 +++ shadow-4.1.0/man/useradd.8 2008-03-03 14:18:17.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 -upb 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 2008-03-03 14:18:17.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 -upb 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 2008-03-03 14:18:17.000000000 +0100 @@ -273,6 +273,19 @@ between 0 and 999 are typically reserved for system accounts. + + + + , + 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. + + @@ -346,7 +359,7 @@ - + @@ -399,7 +412,7 @@ FILES - + /etc/passwd diff -upb 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 2008-03-03 14:18:17.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 *); diff -upb 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 2008-03-03 14:18:17.000000000 +0100 @@ -342,4 +342,7 @@ extern char *strerror (); #include #endif +#ifdef WITH_SELINUX +#include +#endif #endif /* _DEFINES_H_ */ diff -upb 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 2008-03-03 14:18:17.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 -upb 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 2008-03-03 14:18:17.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); @@ -250,12 +252,12 @@ static int get_groups (char *list) #endif if (ngroups == sys_ngroups) { - fprintf (stderr, + fprintf (stderr, _ ("%s: too many groups specified (max %d).\n"), Prog, ngroups); break; - } + } /* * Add the group name to the user's list of groups. @@ -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); } @@ -332,7 +337,7 @@ static char *new_pw_passwd (char *pw_pas "You should set a password with usermod -p to unlock this user account.\n"), Prog); return pw_pass; - } + } #ifdef WITH_AUDIT audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "updating password", @@ -405,7 +410,7 @@ static void new_pwent (struct passwd *pw #else pwent->pw_gecos = user_comment; #endif - } + } if (dflg) { #ifdef WITH_AUDIT @@ -826,7 +831,7 @@ static void process_flags (int argc, cha user_comment = xstrdup (pwd->pw_gecos); user_home = xstrdup (pwd->pw_dir); user_shell = xstrdup (pwd->pw_shell); - } + } #ifdef WITH_AUDIT user_newname = user_name; user_newid = user_id; @@ -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': @@ -966,7 +978,7 @@ static void process_flags (int argc, cha fprintf (stderr, _("%s: unknown group %s\n"), Prog, optarg); - exit (E_NOTFOUND); + exit (E_NOTFOUND); } user_newgid = grp->gr_gid; gflg++; @@ -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 (); } @@ -1040,7 +1062,7 @@ static void process_flags (int argc, cha exit (E_USAGE); } if (!is_shadow_pwd && (eflg || fflg)) { - fprintf (stderr, + fprintf (stderr, _ ("%s: shadow passwords required for -e and -f\n"), Prog); @@ -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 -upb shadow-4.1.0/src/useradd.c.selinux shadow-4.1.0/src/useradd.c --- shadow-4.1.0/src/useradd.c.selinux 2008-03-03 14:14:45.000000000 +0100 +++ shadow-4.1.0/src/useradd.c 2008-03-03 14:19:01.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); } /* @@ -586,7 +589,7 @@ static int get_groups (char *list) #endif if (ngroups == sys_ngroups) { - fprintf (stderr, + fprintf (stderr, _ ("%s: too many groups specified (max %d).\n"), Prog, ngroups); @@ -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); } @@ -696,7 +703,7 @@ static void new_spent (struct spwd *spen spent->sp_warn = scale_age (getdef_num ("PASS_WARN_AGE", -1)); spent->sp_inact = scale_age (def_inactive); spent->sp_expire = scale_age (user_expire); - } + } else { spent->sp_min = scale_age(-1); spent->sp_max = scale_age(-1); @@ -1030,32 +1037,39 @@ 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': if (!VALID (optarg) || optarg[0] != '/') { - fprintf (stderr, + fprintf (stderr, _ ("%s: invalid base directory '%s'\n"), Prog, optarg); - exit (E_BAD_ARG); + exit (E_BAD_ARG); } def_home = optarg; bflg++; break; case 'c': if (!VALID (optarg)) { - fprintf (stderr, + fprintf (stderr, _ ("%s: invalid comment '%s'\n"), Prog, optarg); - exit (E_BAD_ARG); + exit (E_BAD_ARG); } user_comment = optarg; cflg++; @@ -1063,11 +1077,11 @@ static void process_flags (int argc, cha case 'd': if (!VALID (optarg) || optarg[0] != '/') { - fprintf (stderr, + fprintf (stderr, _ ("%s: invalid home directory '%s'\n"), Prog, optarg); - exit (E_BAD_ARG); + exit (E_BAD_ARG); } user_home = optarg; dflg++; @@ -1161,7 +1175,7 @@ static void process_flags (int argc, cha _ ("%s: -K requires KEY=VALUE\n"), Prog); - exit (E_BAD_ARG); + exit (E_BAD_ARG); } /* terminate name, point to value */ *cp++ = '\0'; @@ -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 (); } @@ -1238,7 +1263,7 @@ static void process_flags (int argc, cha */ if (Dflg) { if (optind != argc) - usage (); + usage (); if (uflg || oflg || Gflg || dflg || cflg || mflg) usage (); @@ -1253,7 +1278,7 @@ static void process_flags (int argc, cha ("%s: invalid user name '%s'\n"), Prog, user_name); #ifdef WITH_AUDIT - audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "adding user", + audit_logger (AUDIT_USER_CHAUTHTOK, Prog, "adding user", user_name, -1, 0); #endif exit (E_BAD_ARG); @@ -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, @@ -1614,6 +1670,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 } } @@ -1847,6 +1907,8 @@ int main (int argc, char **argv) close_files (); + selinux_update_mapping(); + nscd_flush_cache ("passwd"); nscd_flush_cache ("group");