]> granicus.if.org Git - shadow/commitdiff
* NEWS, src/useradd.c, man/useradd.8.xml: add -Z option to map
authornekral-guest <nekral-guest@5a98b0ae-9ef6-0310-add3-de5d479b70d7>
Sat, 11 Apr 2009 15:34:10 +0000 (15:34 +0000)
committernekral-guest <nekral-guest@5a98b0ae-9ef6-0310-add3-de5d479b70d7>
Sat, 11 Apr 2009 15:34:10 +0000 (15:34 +0000)
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.

12 files changed:
ChangeLog
NEWS
TODO
lib/prototypes.h
libmisc/Makefile.am
libmisc/copydir.c
libmisc/system.c [new file with mode: 0644]
man/useradd.8.xml
man/usermod.8.xml
src/useradd.c
src/userdel.c
src/usermod.c

index 23547514f9ce85fafb87e222807a80a79b63a11a..748c4230c7fbf6bfb4616c6cd3c22a08f576b90c 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -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>
 
        * src/useradd.c (get_defaults): Close the default file after the
diff --git a/NEWS b/NEWS
index 1aaf14e1e80af76f1e3d3456b6c512586527f557..71ccdf56439fd449c3b570a498c54e44e8131da5 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -89,22 +89,26 @@ shadow-4.1.2.2 -> shadow-4.1.3                                              UNRELEASED
 - pwck
   * warn for users with UID set to (uid_t)-1.
 - su
-  * 
+  * Preserve COLORTERM in addition to TERM when su is called with the -l
+    option.
 - useradd
   * audit logging improvements.
   * Speedup (see "addition of users or groups" above).
   * See CREATE_HOME above.
   * New -M/--no-create-home option to disable CREATE_HOME.
   * do not create users with UID set to (gid_t)-1.
+  * Added -Z option to map SELinux user for user's login.
 - userdel
   * audit logging improvements.
   * 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
     not in the gshadow file.
+  * Delete the SELinux user mapping for user's login.
 - usermod
   * Allow adding LDAP users (or any user not present in the local passwd
     file) to local groups
   * 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
 
diff --git a/TODO b/TODO
index 13e4a953159e795c9b3318e24db2dd0be7ce64ac..85193989982b95c1a054480d35d6efc214a43241 100644 (file)
--- a/TODO
+++ b/TODO
@@ -46,6 +46,7 @@ testsuite
 newusers
  - add logging to SYSLOG & AUDIT
  - use CREATE_HOME
+ - Add a -Z option (see useradd / usermod)
 
 Document when/where option appeared, document whether an option is standard
 or not.
index 8a6eead963cbaae42fb18a16a7aa1b3a4d2735e8..f5528a46f77ebc45d56fb5e938f231134afcc46f 100644 (file)
@@ -118,6 +118,10 @@ extern int copy_tree (const char *src_root, const char *dst_root,
                       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 *);
 
@@ -304,6 +308,12 @@ extern struct spwd *__spw_dup (const struct spwd *spent);
 /* 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 *);
 
index e905d8796b590b814e5222bdd380ff73f1f1e38d..247eab13bf1fc0ff7fcbde11236061798a30880c 100644 (file)
@@ -48,6 +48,7 @@ libmisc_a_SOURCES = \
        setugid.c \
        setupenv.c \
        shell.c \
+       system.c \
        strtoday.c \
        sub.c \
        sulog.c \
index 951e69ace35d53ba282919f1d23a397cbc92510c..1da468c1952bc0f127064cf0d8ee1185ce2e7a71 100644 (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,
  *     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_enabled;
@@ -259,6 +262,12 @@ int copy_tree (const char *src_root, const char *dst_root,
                src_orig = NULL;
                dst_orig = NULL;
        }
+
+#ifdef WITH_SELINUX
+       /* Reset SELinux to create files with default contexts */
+       setfscreatecon (NULL);
+#endif
+
        return err;
 }
 
diff --git a/libmisc/system.c b/libmisc/system.c
new file mode 100644 (file)
index 0000000..f92b10b
--- /dev/null
@@ -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);
+}
+
index 8fce5c9c62e3a3f42b1e2f539e403887e26aabd1..cc78101515b317fec070c34aee45022671bdd5d0 100644 (file)
          </para>
        </listitem>
       </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>
 
     <refsect2 id='changing_the_default_values'>
index 6a8927001e1ef48f6ad5b78c67536ba63518af3f..9a02012d907da4df25ff3e646460e0b3077f5bfb 100644 (file)
          </para>
        </listitem>
       </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>
   </refsect1>
 
index 476587d7d2c26dc5d536b5ff6b6f16f2ce272234..444cc22edf60e046134848462bc35b3ea6752c59 100644 (file)
@@ -108,6 +108,9 @@ static const char *user_comment = "";
 static const char *user_home = "";
 static const char *user_shell = "";
 static const char *create_mail_spool = "";
+#ifdef WITH_SELINUX
+static const char *user_selinux = "";
+#endif
 
 static long user_expire = -1;
 static bool is_shadow_pwd;
@@ -175,6 +178,9 @@ static int set_defaults (void);
 static int get_groups (char *);
 static void usage (void);
 static void new_pwent (struct passwd *);
+#ifdef WITH_SELINUX
+static void selinux_update_mapping (void);
+#endif
 
 static long scale_age (long);
 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"
                 "  -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);
 }
@@ -954,12 +963,19 @@ static void process_flags (int argc, char **argv)
                        {"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 = 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",
+#endif
                                         long_options, NULL)) != -1) {
                        switch (c) {
                        case 'b':
@@ -1153,6 +1169,19 @@ static void process_flags (int argc, char **argv)
                        case 'U':
                                Uflg = true;
                                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 ();
                        }
@@ -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
  *
@@ -1669,6 +1724,9 @@ static void usr_update (void)
 static void create_home (void)
 {
        if (access (user_home, F_OK) != 0) {
+#ifdef WITH_SELINUX
+               selinux_file_context (user_home);
+#endif
                /* XXX - create missing parent directories.  --marekm */
                if (mkdir (user_home, 0) != 0) {
                        fprintf (stderr,
@@ -1691,6 +1749,10 @@ static void create_home (void)
                              "adding home directory",
                              user_name, (unsigned int) user_id,
                              SHADOW_AUDIT_SUCCESS);
+#endif
+#ifdef WITH_SELINUX
+               /* Reset SELinux to create files with default contexts */
+               setfscreatecon (NULL);
 #endif
        }
 }
@@ -1940,6 +2002,10 @@ int main (int argc, char **argv)
 
        close_files ();
 
+#ifdef WITH_SELINUX
+       selinux_update_mapping ();
+#endif
+
        nscd_flush_cache ("passwd");
        nscd_flush_cache ("group");
 
index 907a3cd5bcb2d41820a5c9bf66258f1406129750..52a302314b068da7ea2aef1b58ae97edccaaaef8 100644 (file)
@@ -797,6 +797,17 @@ int main (int argc, char **argv)
        audit_help_open ();
 #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.
         */
index 39695637352cdc1f69b14678b19f8a11d7f903cc..e860c3685598d741bd3a3e9baed4f62f41513def 100644 (file)
@@ -98,6 +98,9 @@ static char *user_newcomment;
 static char *user_home;
 static char *user_newhome;
 static char *user_shell;
+#ifdef WITH_SELINUX
+static const char *user_selinux = "";
+#endif
 static char *user_newshell;
 static long user_expire;
 static long user_newexpire;
@@ -120,6 +123,9 @@ static bool
     oflg = false,              /* permit non-unique user ID to be specified with -u */
     pflg = false,              /* new encrypted password */
     sflg = false,              /* new shell program */
+#ifdef WITH_SELINUX
+    Zflg = false,              /* new selinux user */
+#endif
     uflg = false,              /* specify new user ID */
     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 void usage (void);
 static void new_pwent (struct passwd *);
+#ifdef WITH_SELINUX
+static void selinux_update_mapping (void);
+#endif
 
 static void new_spent (struct spwd *);
 static void fail_exit (int);
@@ -314,6 +323,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);
 }
@@ -876,13 +888,20 @@ static void process_flags (int argc, char **argv)
                        {"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,
+#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",
+#endif
                                         long_options, NULL)) != -1) {
                        switch (c) {
                        case 'a':
@@ -996,6 +1015,19 @@ static void process_flags (int argc, char **argv)
                        case 'U':
                                Uflg = true;
                                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:
                                usage ();
                        }
@@ -1036,7 +1068,11 @@ static void process_flags (int argc, char **argv)
        }
 
        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);
                exit (E_SUCCESS);
        }
@@ -1722,6 +1758,10 @@ int main (int argc, char **argv)
        nscd_flush_cache ("passwd");
        nscd_flush_cache ("group");
 
+#ifdef WITH_SELINUX
+       selinux_update_mapping ();
+#endif
+
        if (mflg) {
                move_home ();
        }
@@ -1749,3 +1789,34 @@ int main (int argc, char **argv)
        /* 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
+