coreutils
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH 1/9] cp: -Z: adjust utils to run restorecon with -Z


From: Pádraig Brady
Subject: [PATCH 1/9] cp: -Z: adjust utils to run restorecon with -Z
Date: Wed, 28 Nov 2012 01:43:11 +0000

From: Daniel J Walsh <address@hidden>

TODO: details
---
 src/chcon.c   |    2 +-
 src/copy.c    |   52 +++++-------
 src/copy.h    |    3 +
 src/cp.c      |   32 ++++++-
 src/install.c |   26 +++---
 src/local.mk  |   15 +++-
 src/mkdir.c   |   22 ++++-
 src/mkfifo.c  |   16 +++-
 src/mknod.c   |   17 +++-
 src/mv.c      |   13 +++-
 src/runcon.c  |    2 +-
 src/selinux.c |  269 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 src/selinux.h |   26 ++++++
 src/system.h  |    2 +-
 14 files changed, 432 insertions(+), 65 deletions(-)
 create mode 100644 src/selinux.c
 create mode 100644 src/selinux.h

diff --git a/src/chcon.c b/src/chcon.c
index 66075f5..17d40d7 100644
--- a/src/chcon.c
+++ b/src/chcon.c
@@ -355,7 +355,7 @@ Usage: %s [OPTION]... CONTEXT FILE...\n\
 "),
         program_name, program_name, program_name);
       fputs (_("\
-Change the security context of each FILE to CONTEXT.\n\
+Change the SELinux security context of each FILE to CONTEXT.\n\
 With --reference, change the security context of each FILE to that of RFILE.\n\
 \n\
 "), stdout);
diff --git a/src/copy.c b/src/copy.c
index 7a35414..501801c 100644
--- a/src/copy.c
+++ b/src/copy.c
@@ -60,6 +60,7 @@
 #include "write-any-file.h"
 #include "areadlink.h"
 #include "yesno.h"
+#include "selinux.h"
 
 #if USE_XATTR
 # include <attr/error_context.h>
@@ -837,41 +838,18 @@ copy_reg (char const *src_name, char const *dst_name,
          1) the src context may prohibit writing, and
          2) because it's more consistent to use the same context
          that is used when the destination file doesn't already exist.  */
-      if (x->preserve_security_context && 0 <= dest_desc)
+      if ((x->set_security_context || x->preserve_security_context) && 0 <= 
dest_desc)
         {
           bool all_errors = (!x->data_copy_required
                              || x->require_preserve_context);
           bool some_errors = !all_errors && !x->reduce_diagnostics;
-          security_context_t con = NULL;
 
-          if (getfscreatecon (&con) < 0)
-            {
-              if (all_errors || (some_errors && !errno_unsupported (errno)))
-                error (0, errno, _("failed to get file system create 
context"));
-              if (x->require_preserve_context)
-                {
-                  return_val = false;
-                  goto close_src_and_dst_desc;
-                }
-            }
-
-          if (con)
-            {
-              if (fsetfilecon (dest_desc, con) < 0)
-                {
-                  if (all_errors || (some_errors && !errno_unsupported 
(errno)))
-                    error (0, errno,
-                           _("failed to set the security context of %s to %s"),
-                           quote_n (0, dst_name), quote_n (1, con));
-                  if (x->require_preserve_context)
-                    {
-                      return_val = false;
-                      freecon (con);
-                      goto close_src_and_dst_desc;
-                    }
-                }
-              freecon (con);
-            }
+          if (restorecon(dst_name, 0, x->preserve_security_context) < 0)  {
+            if (all_errors || (some_errors && !errno_unsupported (errno)))
+              error (0, errno, _("failed to set file system context on %s"), 
quote_n (0, dst_name));
+            return_val = false;
+            goto close_src_and_dst_desc;
+          }
         }
 
       if (dest_desc < 0 && x->unlink_dest_after_failed_open)
@@ -892,6 +870,9 @@ copy_reg (char const *src_name, char const *dst_name,
 
   if (*new_dst)
     {
+      if (x->set_security_context && (! x->require_preserve_context))
+        defaultcon(dst_name, dst_mode);
+
     open_with_O_CREAT:;
 
       int open_flags = O_WRONLY | O_CREAT | O_BINARY;
@@ -974,6 +955,9 @@ copy_reg (char const *src_name, char const *dst_name,
       goto close_src_and_dst_desc;
     }
 
+  if (x->set_security_context && ! x->preserve_security_context)
+    restorecon(dst_name, 1, false);
+
   /* --attributes-only overrides --reflink.  */
   if (data_copy_required && x->reflink_mode)
     {
@@ -2092,6 +2076,9 @@ copy_internal (char const *src_name, char const *dst_name,
             emit_verbose (src_name, dst_name,
                           backup_succeeded ? dst_backup : NULL);
 
+          if (x->set_security_context)
+            restorecon(dst_name, 1, false);
+
           if (rename_succeeded)
             *rename_succeeded = true;
 
@@ -2231,6 +2218,11 @@ copy_internal (char const *src_name, char const 
*dst_name,
             return false;
         }
     }
+  else
+  {
+    if (x->set_security_context)
+      restorecon(dst_name, 1, false);
+  }
 
   if (S_ISDIR (src_mode))
     {
diff --git a/src/copy.h b/src/copy.h
index 440d3bb..d6044aa 100644
--- a/src/copy.h
+++ b/src/copy.h
@@ -159,6 +159,9 @@ struct cp_options
   bool preserve_timestamps;
   bool explicit_no_preserve_mode;
 
+  /* If true, attempt to set specified security context */
+  bool set_security_context;
+
   /* Enabled for mv, and for cp by the --preserve=links option.
      If true, attempt to preserve in the destination files any
      logical hard links between the source files.  If used with cp's
diff --git a/src/cp.c b/src/cp.c
index 231d6a3..365fad4 100644
--- a/src/cp.c
+++ b/src/cp.c
@@ -141,6 +141,7 @@ static struct option const long_opts[] =
   {"target-directory", required_argument, NULL, 't'},
   {"update", no_argument, NULL, 'u'},
   {"verbose", no_argument, NULL, 'v'},
+  {GETOPT_SELINUX_CONTEXT_OPTION_DECL},
   {GETOPT_HELP_OPTION_DECL},
   {GETOPT_VERSION_OPTION_DECL},
   {NULL, 0, NULL, 0}
@@ -228,6 +229,7 @@ Mandatory arguments to long options are mandatory for short 
options too.\n\
                                  destination file is missing\n\
   -v, --verbose                explain what is being done\n\
   -x, --one-file-system        stay on this file system\n\
+  -Z, --context[=CTX]      set security context of destination file to default 
type or to CTX if specified\n\
 "), stdout);
       fputs (HELP_OPTION_DESCRIPTION, stdout);
       fputs (VERSION_OPTION_DESCRIPTION, stdout);
@@ -785,6 +787,7 @@ cp_option_init (struct cp_options *x)
   x->explicit_no_preserve_mode = false;
   x->preserve_security_context = false;
   x->require_preserve_context = false;
+  x->set_security_context = false;
   x->preserve_xattr = false;
   x->reduce_diagnostics = false;
   x->require_preserve_xattr = false;
@@ -876,8 +879,10 @@ decode_preserve_arg (char const *arg, struct cp_options 
*x, bool on_off)
           break;
 
         case PRESERVE_CONTEXT:
-          x->preserve_security_context = on_off;
-          x->require_preserve_context = on_off;
+          if (! x->set_security_context) {
+            x->preserve_security_context = on_off;
+            x->require_preserve_context = on_off;
+          }
           break;
 
         case PRESERVE_XATTR:
@@ -891,7 +896,7 @@ decode_preserve_arg (char const *arg, struct cp_options *x, 
bool on_off)
           x->preserve_ownership = on_off;
           x->preserve_links = on_off;
           x->explicit_no_preserve_mode = !on_off;
-          if (selinux_enabled)
+          if (selinux_enabled && (! x->set_security_context))
             x->preserve_security_context = on_off;
           x->preserve_xattr = on_off;
           break;
@@ -934,7 +939,7 @@ main (int argc, char **argv)
      we'll actually use backup_suffix_string.  */
   backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
 
-  while ((c = getopt_long (argc, argv, "abdfHilLnprst:uvxPRS:T",
+  while ((c = getopt_long (argc, argv, "abdfHilLnprst:uvxPRS:TZ",
                            long_opts, NULL))
          != -1)
     {
@@ -961,7 +966,7 @@ main (int argc, char **argv)
           x.preserve_mode = true;
           x.preserve_timestamps = true;
           x.require_preserve = true;
-          if (selinux_enabled)
+          if (selinux_enabled && (! x.set_security_context))
              x.preserve_security_context = true;
           x.preserve_xattr = true;
           x.reduce_diagnostics = true;
@@ -1091,6 +1096,23 @@ main (int argc, char **argv)
           x.one_file_system = true;
           break;
 
+
+        case 'Z':
+          /* politely decline if we're not on a selinux-enabled kernel. */
+          if( selinux_enabled ) {
+                  if (optarg) {
+                          /* if there's a security_context given set new path
+                             components to that context, too */
+                          if ( setfscreatecon(optarg) < 0 ) {
+                                  (void) fprintf(stderr, _("cannot set default 
security context %s\n"), optarg);
+                                  exit( 1 );
+                          }
+                  }
+                  x.set_security_context = true;
+                  x.preserve_security_context = false;
+          }
+         break;
+
         case 'S':
           make_backups = true;
           backup_suffix_string = optarg;
diff --git a/src/install.c b/src/install.c
index 8ea5491..0b9b317 100644
--- a/src/install.c
+++ b/src/install.c
@@ -280,6 +280,7 @@ cp_option_init (struct cp_options *x)
   x->data_copy_required = true;
   x->require_preserve = false;
   x->require_preserve_context = false;
+  x->set_security_context = false;
   x->require_preserve_xattr = false;
   x->recursive = false;
   x->sparse_mode = SPARSE_AUTO;
@@ -641,8 +642,7 @@ Mandatory arguments to long options are mandatory for short 
options too.\n\
 "), stdout);
       fputs (_("\
       --preserve-context  preserve SELinux security context\n\
-  -Z, --context=CONTEXT  set SELinux security context of files and directories\
-\n\
+  -Z, --context[=CTX]      set security context of destination file to default 
type or to CTX if specified\n\
 "), stdout);
 
       fputs (HELP_OPTION_DESCRIPTION, stdout);
@@ -783,7 +783,7 @@ main (int argc, char **argv)
      we'll actually use backup_suffix_string.  */
   backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
 
-  while ((optc = getopt_long (argc, argv, "bcCsDdg:m:o:pt:TvS:Z:", 
long_options,
+  while ((optc = getopt_long (argc, argv, "bcCsDdg:m:o:pt:TvS:Z", long_options,
                               NULL)) != -1)
     {
       switch (optc)
@@ -860,18 +860,20 @@ main (int argc, char **argv)
                              "this kernel is not SELinux-enabled"));
               break;
             }
+          if ( x.set_security_context || scontext ) {
+             (void) fprintf(stderr, "%s: cannot force target context and 
preserve it\n", argv[0]);
+             exit( 1 );
+          }
           x.preserve_security_context = true;
-          use_default_selinux_context = false;
           break;
         case 'Z':
-          if ( ! selinux_enabled)
-            {
-              error (0, 0, _("WARNING: ignoring --context (-Z); "
-                             "this kernel is not SELinux-enabled"));
-              break;
-            }
-          scontext = optarg;
-          use_default_selinux_context = false;
+          if ( selinux_enabled )
+          {
+                  if (optarg)
+                          scontext = optarg;
+                  else
+                          x.set_security_context = true;
+          }
           break;
         case_GETOPT_HELP_CHAR;
         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
diff --git a/src/local.mk b/src/local.mk
index ead3b8b..bd6711e 100644
--- a/src/local.mk
+++ b/src/local.mk
@@ -307,6 +307,10 @@ RELEASE_YEAR = \
   `sed -n '/.*COPYRIGHT_YEAR = \([0-9][0-9][0-9][0-9]\) };/s//\1/p' \
     $(top_srcdir)/lib/version-etc.c`
 
+selinux_sources = \
+  src/selinux.c \
+  src/selinux.h
+
 copy_sources = \
   src/copy.c \
   src/cp-hash.c \
@@ -318,12 +322,12 @@ copy_sources = \
 # to install before applying any user-specified name transformations.
 
 transform = s/ginstall/install/; $(program_transform_name)
-src_ginstall_SOURCES = src/install.c src/prog-fprintf.c $(copy_sources)
+src_ginstall_SOURCES = src/install.c src/prog-fprintf.c $(copy_sources) 
$(selinux_sources)
 
 # This is for the '[' program.  Automake transliterates '[' and '/' to '_'.
 src___SOURCES = src/lbracket.c
 
-src_cp_SOURCES = src/cp.c $(copy_sources)
+src_cp_SOURCES = src/cp.c $(copy_sources) $(selinux_sources)
 src_dir_SOURCES = src/ls.c src/ls-dir.c
 src_vdir_SOURCES = src/ls.c src/ls-vdir.c
 src_id_SOURCES = src/id.c src/group-list.c
@@ -336,12 +340,15 @@ src_kill_SOURCES = src/kill.c src/operand2sig.c
 src_realpath_SOURCES = src/realpath.c src/relpath.c src/relpath.h
 src_timeout_SOURCES = src/timeout.c src/operand2sig.c
 
-src_mv_SOURCES = src/mv.c src/remove.c $(copy_sources)
+src_mv_SOURCES = src/mv.c src/remove.c $(copy_sources) $(selinux_sources)
 src_rm_SOURCES = src/rm.c src/remove.c
 
-src_mkdir_SOURCES = src/mkdir.c src/prog-fprintf.c
+src_mkdir_SOURCES = src/mkdir.c src/prog-fprintf.c $(selinux_sources)
 src_rmdir_SOURCES = src/rmdir.c src/prog-fprintf.c
 
+src_mkfifo_SOURCES = src/mkfifo.c $(selinux_sources)
+src_mknod_SOURCES = src/mknod.c $(selinux_sources)
+
 src_df_SOURCES = src/df.c src/find-mount-point.c
 src_stat_SOURCES = src/stat.c src/find-mount-point.c
 
diff --git a/src/mkdir.c b/src/mkdir.c
index 32f79d4..548030c 100644
--- a/src/mkdir.c
+++ b/src/mkdir.c
@@ -29,6 +29,7 @@
 #include "prog-fprintf.h"
 #include "quote.h"
 #include "savewd.h"
+#include "selinux.h"
 
 /* The official name of this program (e.g., no 'g' prefix).  */
 #define PROGRAM_NAME "mkdir"
@@ -65,8 +66,8 @@ Mandatory arguments to long options are mandatory for short 
options too.\n\
   -m, --mode=MODE   set file mode (as in chmod), not a=rwx - umask\n\
   -p, --parents     no error if existing, make parent directories as needed\n\
   -v, --verbose     print a message for each created directory\n\
-  -Z, --context=CTX  set the SELinux security context of each created\n\
-                      directory to CTX\n\
+  -Z, --context[=CTX]  set the SELinux security context of each created\n\
+                      directory to default type or to CTX if specified\n\
 "), stdout);
       fputs (HELP_OPTION_DESCRIPTION, stdout);
       fputs (VERSION_OPTION_DESCRIPTION, stdout);
@@ -91,6 +92,9 @@ struct mkdir_options
   /* File mode bits affected by MODE.  */
   mode_t mode_bits;
 
+  /* Set the SELinux File Context.  */
+  int set_security_context;
+
   /* If not null, format to use when reporting newly made directories.  */
   char const *created_directory_format;
 };
@@ -113,6 +117,9 @@ static int
 make_ancestor (char const *dir, char const *component, void *options)
 {
   struct mkdir_options const *o = options;
+
+  if (o->set_security_context)
+    defaultcon(dir, S_IFDIR);
   int r = mkdir (component, o->ancestor_mode);
   if (r == 0)
     {
@@ -146,6 +153,7 @@ main (int argc, char **argv)
   options.mode = S_IRWXUGO;
   options.mode_bits = 0;
   options.created_directory_format = NULL;
+  options.set_security_context = false;
 
   initialize_main (&argc, &argv);
   set_program_name (argv[0]);
@@ -155,7 +163,7 @@ main (int argc, char **argv)
 
   atexit (close_stdout);
 
-  while ((optc = getopt_long (argc, argv, "pm:vZ:", longopts, NULL)) != -1)
+  while ((optc = getopt_long (argc, argv, "pm:vZ", longopts, NULL)) != -1)
     {
       switch (optc)
         {
@@ -169,7 +177,13 @@ main (int argc, char **argv)
           options.created_directory_format = _("created directory %s");
           break;
         case 'Z':
-          scontext = optarg;
+          if ( is_selinux_enabled() > 0 )
+          {
+            if (optarg)
+              scontext = optarg;
+            else
+              options.set_security_context = true;
+          }
           break;
         case_GETOPT_HELP_CHAR;
         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
diff --git a/src/mkfifo.c b/src/mkfifo.c
index e524c44..3253640 100644
--- a/src/mkfifo.c
+++ b/src/mkfifo.c
@@ -26,6 +26,7 @@
 #include "error.h"
 #include "modechange.h"
 #include "quote.h"
+#include "selinux.h"
 
 /* The official name of this program (e.g., no 'g' prefix).  */
 #define PROGRAM_NAME "mkfifo"
@@ -60,7 +61,7 @@ Mandatory arguments to long options are mandatory for short 
options too.\n\
   -m, --mode=MODE    set file permission bits to MODE, not a=rw - umask\n\
 "), stdout);
       fputs (_("\
-  -Z, --context=CTX  set the SELinux security context of each NAME to CTX\n\
+  -Z, --context[=CTX]  set the SELinux security context of each NAME to 
default type or CTX if specified\n\
 "), stdout);
       fputs (HELP_OPTION_DESCRIPTION, stdout);
       fputs (VERSION_OPTION_DESCRIPTION, stdout);
@@ -74,6 +75,7 @@ main (int argc, char **argv)
 {
   mode_t newmode;
   char const *specified_mode = NULL;
+  int set_security_context = false;
   int exit_status = EXIT_SUCCESS;
   int optc;
   security_context_t scontext = NULL;
@@ -86,7 +88,7 @@ main (int argc, char **argv)
 
   atexit (close_stdout);
 
-  while ((optc = getopt_long (argc, argv, "m:Z:", longopts, NULL)) != -1)
+  while ((optc = getopt_long (argc, argv, "m:Z", longopts, NULL)) != -1)
     {
       switch (optc)
         {
@@ -94,7 +96,13 @@ main (int argc, char **argv)
           specified_mode = optarg;
           break;
         case 'Z':
-          scontext = optarg;
+          if ( is_selinux_enabled() > 0 )
+          {
+            if (optarg)
+              scontext = optarg;
+            else
+              set_security_context = true;
+          }
           break;
         case_GETOPT_HELP_CHAR;
         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
@@ -128,6 +136,8 @@ main (int argc, char **argv)
     }
 
   for (; optind < argc; ++optind)
+    if (set_security_context)
+      defaultcon(argv[optind], S_IFIFO);
     if (mkfifo (argv[optind], newmode) != 0)
       {
         error (0, errno, _("cannot create fifo %s"), quote (argv[optind]));
diff --git a/src/mknod.c b/src/mknod.c
index dc158b4..6977ba8 100644
--- a/src/mknod.c
+++ b/src/mknod.c
@@ -27,6 +27,7 @@
 #include "modechange.h"
 #include "quote.h"
 #include "xstrtol.h"
+#include "selinux.h"
 
 /* The official name of this program (e.g., no 'g' prefix).  */
 #define PROGRAM_NAME "mknod"
@@ -62,7 +63,7 @@ Mandatory arguments to long options are mandatory for short 
options too.\n\
   -m, --mode=MODE    set file permission bits to MODE, not a=rw - umask\n\
 "), stdout);
       fputs (_("\
-  -Z, --context=CTX  set the SELinux security context of NAME to CTX\n\
+  -Z, --context[=CTX]  set the SELinux security context of NAME to default 
type or to CTX if specified\n\
 "), stdout);
       fputs (HELP_OPTION_DESCRIPTION, stdout);
       fputs (VERSION_OPTION_DESCRIPTION, stdout);
@@ -94,6 +95,7 @@ main (int argc, char **argv)
   int expected_operands;
   mode_t node_type;
   security_context_t scontext = NULL;
+  int set_security_context = false;
 
   initialize_main (&argc, &argv);
   set_program_name (argv[0]);
@@ -103,7 +105,7 @@ main (int argc, char **argv)
 
   atexit (close_stdout);
 
-  while ((optc = getopt_long (argc, argv, "m:Z:", longopts, NULL)) != -1)
+  while ((optc = getopt_long (argc, argv, "m:Z", longopts, NULL)) != -1)
     {
       switch (optc)
         {
@@ -111,7 +113,13 @@ main (int argc, char **argv)
           specified_mode = optarg;
           break;
         case 'Z':
-          scontext = optarg;
+          if ( is_selinux_enabled() > 0 )
+          {
+            if (optarg)
+              scontext = optarg;
+            else
+              set_security_context = true;
+          }
           break;
         case_GETOPT_HELP_CHAR;
         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
@@ -212,6 +220,9 @@ main (int argc, char **argv)
           error (EXIT_FAILURE, 0, _("invalid device %s %s"), s_major, s_minor);
 #endif
 
+        if (set_security_context)
+          defaultcon(argv[optind], node_type);
+
         if (mknod (argv[optind], newmode | node_type, device) != 0)
           error (EXIT_FAILURE, errno, "%s", quote (argv[optind]));
       }
diff --git a/src/mv.c b/src/mv.c
index 5b08fdd..683c649 100644
--- a/src/mv.c
+++ b/src/mv.c
@@ -55,6 +55,7 @@ static bool remove_trailing_slashes;
 static struct option const long_options[] =
 {
   {"backup", optional_argument, NULL, 'b'},
+  {"context", no_argument, NULL, 'Z'},
   {"force", no_argument, NULL, 'f'},
   {"interactive", no_argument, NULL, 'i'},
   {"no-clobber", no_argument, NULL, 'n'},
@@ -120,6 +121,7 @@ cp_option_init (struct cp_options *x)
   x->preserve_timestamps = true;
   x->explicit_no_preserve_mode= false;
   x->preserve_security_context = selinux_enabled;
+  x->set_security_context = false;
   x->reduce_diagnostics = false;
   x->data_copy_required = true;
   x->require_preserve = false;  /* FIXME: maybe make this an option */
@@ -317,6 +319,7 @@ If you specify more than one of -i, -f, -n, only the final 
one takes effect.\n\
                                  than the destination file or when the\n\
                                  destination file is missing\n\
   -v, --verbose                explain what is being done\n\
+  -Z, --context                set security context of destination file to 
default type\n \
 "), stdout);
       fputs (HELP_OPTION_DESCRIPTION, stdout);
       fputs (VERSION_OPTION_DESCRIPTION, stdout);
@@ -351,6 +354,7 @@ main (int argc, char **argv)
   bool no_target_directory = false;
   int n_files;
   char **file;
+  bool selinux_enabled = (0 < is_selinux_enabled ());
 
   initialize_main (&argc, &argv);
   set_program_name (argv[0]);
@@ -369,7 +373,7 @@ main (int argc, char **argv)
      we'll actually use backup_suffix_string.  */
   backup_suffix_string = getenv ("SIMPLE_BACKUP_SUFFIX");
 
-  while ((c = getopt_long (argc, argv, "bfint:uvS:T", long_options, NULL))
+  while ((c = getopt_long (argc, argv, "bfint:uvS:TZ", long_options, NULL))
          != -1)
     {
       switch (c)
@@ -418,6 +422,13 @@ main (int argc, char **argv)
           make_backups = true;
           backup_suffix_string = optarg;
           break;
+        case 'Z':
+          /* politely decline if we're not on a selinux-enabled kernel. */
+          if( selinux_enabled ) {
+            x.preserve_security_context = false;
+            x.set_security_context = true;
+          }
+          break;
         case_GETOPT_HELP_CHAR;
         case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
         default:
diff --git a/src/runcon.c b/src/runcon.c
index 875441f..7162f65 100644
--- a/src/runcon.c
+++ b/src/runcon.c
@@ -85,7 +85,7 @@ Usage: %s CONTEXT COMMAND [args]\n\
   or:  %s [ -c ] [-u USER] [-r ROLE] [-t TYPE] [-l RANGE] COMMAND [args]\n\
 "), program_name, program_name);
       fputs (_("\
-Run a program in a different security context.\n\
+Run a program in a different SELinux security context.\n\
 With neither CONTEXT nor COMMAND, print the current security context.\n\
 \n\
   CONTEXT            Complete security context\n\
diff --git a/src/selinux.c b/src/selinux.c
new file mode 100644
index 0000000..6045dd5
--- /dev/null
+++ b/src/selinux.c
@@ -0,0 +1,269 @@
+/* selinux - core functions for maintaining SELinux labelking
+   Copyright (C) 2012 Red Hat, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Written by Daniel Walsh <address@hidden> */
+
+#include <config.h>
+#include <selinux/selinux.h>
+#include <selinux/flask.h>
+#include <selinux/context.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <libgen.h>
+#include <string.h>
+#include <stdlib.h>
+#include <errno.h>
+#include <unistd.h>
+#include "selinux.h"
+
+#include "error.h"
+#include "system.h"
+#include "fts.h"
+
+/*
+  This function has being added to libselinux-2.1.12-5, but is here
+  for support with older versions of SELinux
+
+  Translates a mode into an Internal SELinux security_class definition.
+  Returns 0 on failure, with errno set to EINVAL.
+*/
+static security_class_t mode_to_security_class(mode_t m) {
+
+  if (S_ISREG(m))
+    return string_to_security_class("file");
+  if (S_ISDIR(m))
+    return string_to_security_class("dir");
+  if (S_ISCHR(m))
+    return string_to_security_class("chr_file");
+  if (S_ISBLK(m))
+    return string_to_security_class("blk_file");
+  if (S_ISFIFO(m))
+    return string_to_security_class("fifo_file");
+  if (S_ISLNK(m))
+    return string_to_security_class("lnk_file");
+  if (S_ISSOCK(m))
+    return string_to_security_class("sock_file");
+
+  errno=EINVAL;
+  return 0;
+}
+
+/*
+  This function takes a path and a mode and then asks SELinux what the label
+  of the path object would be if the current process label created it.
+  it then returns the label.
+
+  Returns -1 on failure. errno will be set approptiately.
+*/
+
+static int computecon(char const *path, mode_t mode, security_context_t *con) {
+  security_context_t scon = NULL;
+  security_context_t tcon = NULL;
+  security_class_t tclass;
+  int rc = -1;
+
+  char *dir = strdup(path);
+  if (!dir)
+    goto quit;
+  if (getcon(&scon) < 0)
+    goto quit;
+  if (getfilecon(dirname((char *) dir), &tcon) < 0)
+    goto quit;
+  tclass = mode_to_security_class(mode);
+  if (!tclass)
+    goto quit;
+  rc = security_compute_create(scon, tcon, tclass, con);
+
+quit:
+  free(dir);
+  freecon(scon);
+  freecon(tcon);
+  return rc;
+}
+
+/*
+  This function takes a path and a mode, it asks calls computecon to get the
+  label of the path object if the current process created it, then it calls
+  matchpathcon to get the default type for the object.  It substitutes the
+  default type into label.  It tells the SELinux Kernel to label all new file
+  system objects created by the current process with this label.
+
+  Returns -1 on failure. errno will be set approptiately.
+*/
+int defaultcon (char const *path, mode_t mode) {
+  int rc = -1;
+  security_context_t scon = NULL, tcon = NULL;
+  context_t scontext = NULL, tcontext = NULL;
+
+  rc = matchpathcon(path, mode,  &scon);
+  if (rc < 0)
+    goto quit;
+  rc = computecon(path, mode,  &tcon);
+  if (rc < 0)
+    goto quit;
+  scontext = context_new(scon);
+  rc = -1;
+  if (!scontext)
+    goto quit;
+  tcontext = context_new(tcon);
+  if (!tcontext)
+    goto quit;
+
+  context_type_set(tcontext, context_type_get(scontext));
+  rc = setfscreatecon (context_str(tcontext));
+
+//  printf("defaultcon %s %s\n", path, context_str(tcontext));
+quit:
+  if (scontext)
+    context_free(scontext);
+  if (scontext)
+    context_free(tcontext);
+  freecon(scon);
+  freecon(tcon);
+  return rc;
+}
+
+/*
+  This function takes a path of an existing file system object, and a boolean
+  that indicates whether the function should preserve the objects label or
+  generate a new label using matchpathcon.  If the function
+  is called with preserve, it will ask the SELinux Kernel what the default 
label
+  for all objects created should be and then sets the label on the object.
+  Otherwise it calls matchpathcon on the object to ask the system what the
+  default label should be, extracts the type field and then modifies the file
+  system object.
+
+  Returns -1 on failure. errno will be set approptiately.
+*/
+static int restorecon_private (char const *path, bool preserve) {
+  int rc = -1;
+  struct stat sb;
+  security_context_t scon = NULL, tcon = NULL;
+  context_t scontext = NULL, tcontext = NULL;
+  int fd;
+
+  if (preserve) {
+    if (getfscreatecon (&tcon) < 0)
+      return rc;
+    rc = lsetfilecon (path, tcon);
+    freecon(tcon);
+    return rc;
+  }
+
+  fd = open (path, O_RDONLY | O_NOFOLLOW);
+  if (!fd && (errno != ELOOP))
+    goto quit;
+
+  if (fd) {
+    rc = fstat (fd, &sb);
+    if (rc < 0)
+      goto quit;
+  } else {
+    rc = lstat (path, &sb);
+    if (rc < 0)
+      goto quit;
+  }
+
+  rc = matchpathcon(path, sb.st_mode,  &scon);
+  if (rc < 0)
+    goto quit;
+  scontext = context_new(scon);
+  rc = -1;
+  if (!scontext)
+    goto quit;
+
+  if (fd) {
+    rc = fgetfilecon (fd, &tcon);
+    if (!rc)
+      goto quit;
+  } else  {
+    rc = lgetfilecon (path, &tcon);
+    if (!rc)
+      goto quit;
+  }
+  tcontext = context_new(tcon);
+  if (!tcontext)
+    goto quit;
+
+  context_type_set(tcontext, context_type_get(scontext));
+
+  if (fd)
+        rc = fsetfilecon (fd, context_str(tcontext));
+  else
+        rc = lsetfilecon (path, context_str(tcontext));
+
+//  printf("restorcon %s %s\n", path, context_str(tcontext));
+quit:
+  close(fd);
+  if (scontext)
+    context_free(scontext);
+  if (scontext)
+    context_free(tcontext);
+  freecon(scon);
+  freecon(tcon);
+  return rc;
+}
+
+/*
+  This function takes three parameters:
+  Path of an existing file system object.
+  A boolean indicating whether it should call restorecon_private recursively
+  or not.
+  A boolean that indicates whether the function should preserve the objects
+  label or generate a new label using matchpathcon.
+
+  If Recurse is selected and the file system object is a directory, restorecon
+  calls restorecon_private on every file system object in the directory.
+
+  Returns false on failure. errno will be set approptiately.
+*/
+bool restorecon (char const *path, bool recurse, bool preserve) {
+  const char *mypath[2] = { path, NULL };
+  FTS *fts;
+  bool ok = true;
+
+  if (!recurse)
+    return restorecon_private(path, preserve);
+
+  fts = fts_open ((char *const *)mypath, FTS_PHYSICAL, NULL);
+  while (1)
+    {
+      FTSENT *ent;
+
+      ent = fts_read (fts);
+      if (ent == NULL)
+        {
+          if (errno != 0)
+            {
+              /* FIXME: try to give a better message  */
+              error (0, errno, _("fts_read failed"));
+              ok = false;
+            }
+          break;
+        }
+
+      ok &= restorecon_private(fts->fts_path, preserve);
+    }
+
+  if (fts_close (fts) != 0)
+    {
+      error (0, errno, _("fts_close failed"));
+      ok = false;
+    }
+
+  return ok;
+}
diff --git a/src/selinux.h b/src/selinux.h
new file mode 100644
index 0000000..c032c05
--- /dev/null
+++ b/src/selinux.h
@@ -0,0 +1,26 @@
+/* selinux - core functions for maintaining SELinux labelking
+   Copyright (C) 2012 Red Hat, Inc.
+
+   This program is free software: you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation, either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+/* Written by Daniel Walsh <address@hidden> */
+
+#ifndef COREUTILS_SELINUX_H
+#define COREUTILS_SELINUX_H
+
+#include <stdbool.h>
+#include <sys/stat.h>
+extern bool restorecon (char const *path, bool recurse, bool preserve);
+extern int defaultcon (char const *path, mode_t mode);
+#endif
diff --git a/src/system.h b/src/system.h
index 06cc803..b5d750c 100644
--- a/src/system.h
+++ b/src/system.h
@@ -330,7 +330,7 @@ enum
 #define GETOPT_VERSION_OPTION_DECL \
   "version", no_argument, NULL, GETOPT_VERSION_CHAR
 #define GETOPT_SELINUX_CONTEXT_OPTION_DECL \
-  "context", required_argument, NULL, 'Z'
+  "context", optional_argument, NULL, 'Z'
 
 #define case_GETOPT_HELP_CHAR                  \
   case GETOPT_HELP_CHAR:                       \
-- 
1.7.6.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]