From eba9b69bbf88317f80e6ee602a0b63e844ba5e0f Mon Sep 17 00:00:00 2001 From: Daniel J Walsh Date: Thu, 21 Dec 2006 20:09:26 +0000 Subject: [PATCH] - Fix execution and creation of Home Directories under SELinux - Resolves: rhbz#217441 --- shadow-4.0.17-useradd.patch | 490 +++++++++++++++++++++++++++++++++--- shadow-utils.spec | 2 +- 2 files changed, 456 insertions(+), 36 deletions(-) diff --git a/shadow-4.0.17-useradd.patch b/shadow-4.0.17-useradd.patch index 75f480c..4f3a15c 100644 --- a/shadow-4.0.17-useradd.patch +++ b/shadow-4.0.17-useradd.patch @@ -1,46 +1,466 @@ -diff -rup shadow-4.0.17-orig/src/useradd.c shadow-4.0.17/src/useradd.c ---- shadow-4.0.17-orig/src/useradd.c 2006-11-29 18:31:43.000000000 -0500 -+++ shadow-4.0.17/src/useradd.c 2006-11-29 21:38:22.000000000 -0500 -@@ -45,6 +45,9 @@ - #include - #include - #include +--- shadow-4.0.17/src/useradd.c.useradd 2006-12-21 09:14:45.000000000 -0500 ++++ shadow-4.0.17/src/useradd.c 2006-12-21 09:14:45.000000000 -0500 +@@ -100,6 +100,7 @@ + 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 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 *); +@@ -361,6 +363,7 @@ + def_create_mail_spool = xstrdup (cp); + } + } ++ fclose(fp); + } + + /* +@@ -648,7 +651,10 @@ + " -p, --password PASSWORD use encrypted password for the new user\n" + " 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" +#ifdef WITH_SELINUX -+#include ++ " -Z, --selinux-user SEUSER use a specific SEUSER for the SELinux user mapping\n" +#endif - #include "chkname.h" - #include "defines.h" - #include "faillog.h" -@@ -1612,6 +1615,9 @@ static void usr_update (void) + "\n")); + exit (E_USAGE); + } +@@ -1048,11 +1054,18 @@ + {"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 = +- getopt_long (argc, argv, "b:c:d:De:f:g:G:k:K:mlMnrop:s:u:", ++#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': +@@ -1236,6 +1249,17 @@ + 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 (); + } +@@ -1603,6 +1628,33 @@ + 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 + * +@@ -1612,7 +1664,11 @@ */ static void create_home (void) { -+ mode_t mode = 0; + -+ mode = 0777 & ~getdef_num ("UMASK", GETDEF_DEFAULT_UMASK); 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)) { -@@ -1625,9 +1631,19 @@ static void create_home (void) - #endif - fail_exit (E_HOMEDIR); - } -+#ifdef WITH_SELINUX -+ { -+ security_context_t con = NULL; + fprintf (stderr, +@@ -1840,6 +1896,15 @@ + + usr_update (); + ++ create_mail (); + -+ if (!matchpathcon(user_home, mode, &con)) -+ { -+ setfilecon(user_home, con); -+ freecon(con); -+ } -+ } ++ nscd_flush_cache ("passwd"); ++ nscd_flush_cache ("group"); ++ ++ close_files (); ++ ++ selinux_update_mapping(); ++ + if (mflg) { + create_home (); + if (home_added) +@@ -1863,13 +1928,6 @@ + * with --gafton + */ + +- create_mail (); +- +- nscd_flush_cache ("passwd"); +- nscd_flush_cache ("group"); +- +- close_files (); +- + #ifdef USE_PAM + if (retval == PAM_SUCCESS) + pam_end (pamh, PAM_SUCCESS); +--- shadow-4.0.17/src/userdel.c.useradd 2006-12-21 09:14:45.000000000 -0500 ++++ shadow-4.0.17/src/userdel.c 2006-12-21 09:20:56.000000000 -0500 +@@ -792,6 +792,17 @@ + #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. +--- shadow-4.0.17/src/usermod.c.useradd 2006-12-21 09:14:45.000000000 -0500 ++++ shadow-4.0.17/src/usermod.c 2006-12-21 09:20:28.000000000 -0500 +@@ -90,6 +90,7 @@ + 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; +@@ -132,6 +133,7 @@ + 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); +@@ -301,6 +303,9 @@ + " -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 - chown (user_home, user_id, user_gid); -- chmod (user_home, -- 0777 & ~getdef_num ("UMASK", GETDEF_DEFAULT_UMASK)); -+ chmod (user_home, mode); - home_added++; - #ifdef WITH_AUDIT - audit_logger (AUDIT_USER_CHAUTHTOK, Prog, -Only in shadow-4.0.17/src: useradd.c.useradd + "\n")); + exit (E_USAGE); + } +@@ -925,13 +930,20 @@ + {"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': +@@ -1080,6 +1092,16 @@ + + 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 (); + } +@@ -1549,6 +1571,8 @@ + if (Gflg || lflg) + grp_err = grp_update (); + ++ selinux_update_mapping(); ++ + if (mflg) + move_home (); + +@@ -1580,3 +1604,56 @@ + 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; ++ safe_system(argv[0], argv, NULL,0); ++ } ++ ++ if (!mflg) { ++ argv[0] = "/sbin/restorecon"; ++ argv[1] = "-R"; ++ argv[2] = user_home; ++ argv[3] = 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 ++} ++ +--- shadow-4.0.17/man/usermod.8.xml.useradd 2006-06-16 12:11:04.000000000 -0400 ++++ shadow-4.0.17/man/usermod.8.xml 2006-12-21 09:14:45.000000000 -0500 +@@ -226,6 +226,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. ++ ++ ++ + + + +--- shadow-4.0.17/man/useradd.8.xml.useradd 2006-06-16 12:11:04.000000000 -0400 ++++ shadow-4.0.17/man/useradd.8.xml 2006-12-21 09:14:45.000000000 -0500 +@@ -251,6 +251,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. ++ ++ ++ + + + +--- shadow-4.0.17/man/useradd.8.useradd 2006-12-21 09:14:45.000000000 -0500 ++++ shadow-4.0.17/man/useradd.8 2006-12-21 09:14:45.000000000 -0500 +@@ -137,6 +137,9 @@ + The numerical value of the user's ID. This value must be unique, unless the + \fB\-o\fR + option is used. The value must be non\-negative. The default is to use the smallest ID value greater than 999 and greater than every other user. Values between 0 and 999 are typically reserved for system accounts. ++.TP 3n ++\fB\-Z\fR, \fB\-\-selinux-user\fR \fISEUSER\fR ++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. + .SS "Changing the default values" + .PP + When invoked with the +--- shadow-4.0.17/man/usermod.8.useradd 2006-12-21 09:14:45.000000000 -0500 ++++ shadow-4.0.17/man/usermod.8 2006-12-21 09:14:45.000000000 -0500 +@@ -90,6 +90,10 @@ + \fB\-p\fR + or + \fB\-L\fR. ++.TP 3n ++\fB\-Z\fR, \fB\-\-selinux-user\fR \fISEUSER\fR ++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. ++ + .SH "CAVEATS" + .PP + +--- /dev/null 2006-12-21 08:27:04.805433018 -0500 ++++ shadow-4.0.17/libmisc/system.c 2006-12-21 09:14:45.000000000 -0500 +@@ -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); ++} ++ +--- shadow-4.0.17/libmisc/Makefile.am.useradd 2005-09-05 12:21:37.000000000 -0400 ++++ shadow-4.0.17/libmisc/Makefile.am 2006-12-21 09:14:45.000000000 -0500 +@@ -41,6 +41,7 @@ + setugid.c \ + setupenv.c \ + shell.c \ ++ system.c \ + strtoday.c \ + sub.c \ + sulog.c \ +--- shadow-4.0.17/libmisc/copydir.c.useradd 2006-07-10 00:35:56.000000000 -0400 ++++ shadow-4.0.17/libmisc/copydir.c 2006-12-21 09:14:45.000000000 -0500 +@@ -54,7 +54,7 @@ + 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; + +--- shadow-4.0.17/lib/prototypes.h.useradd 2006-02-07 11:36:30.000000000 -0500 ++++ shadow-4.0.17/lib/prototypes.h 2006-12-21 09:14:45.000000000 -0500 +@@ -52,6 +52,9 @@ + /* 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 *); +@@ -147,6 +150,9 @@ + /* 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 *); + +--- shadow-4.0.17/lib/defines.h.useradd 2005-09-05 12:22:03.000000000 -0400 ++++ shadow-4.0.17/lib/defines.h 2006-12-21 09:14:45.000000000 -0500 +@@ -342,4 +342,7 @@ + #include + #endif + ++#ifdef WITH_SELINUX ++#include ++#endif + #endif /* _DEFINES_H_ */ diff --git a/shadow-utils.spec b/shadow-utils.spec index 538bf38..ea4214f 100644 --- a/shadow-utils.spec +++ b/shadow-utils.spec @@ -5,7 +5,7 @@ Summary: Utilities for managing accounts and shadow password files Name: shadow-utils Version: 4.0.18.1 -Release: 7%{?dist} +Release: 8%{?dist} Epoch: 2 URL: http://shadow.pld.org.pl/ Source0: ftp://ftp.pld.org.pl/software/shadow/shadow-%{version}.tar.bz2