[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
- Re: Make mv work better with SELinux., Daniel J Walsh, 2012/11/08
- Re: Make mv work better with SELinux., Pádraig Brady, 2012/11/08
- Re: Make mv work better with SELinux., Pádraig Brady, 2012/11/27
- [PATCH 4/9] cp: -Z: s/fprintf/error/, Pádraig Brady, 2012/11/27
- [PATCH 6/9] cp: -Z: add selinux.c to POTFILES.in, Pádraig Brady, 2012/11/27
- [PATCH 3/9] cp: -Z: spelling fixes, Pádraig Brady, 2012/11/27
- [PATCH 7/9] cp: -Z: remove redundant includes from selinux.[ch], Pádraig Brady, 2012/11/27
- [PATCH 5/9] cp: -Z: wrap/clarify/isolate --help messages, Pádraig Brady, 2012/11/27
- [PATCH 2/9] cp: -Z: formatting cleanups, Pádraig Brady, 2012/11/27
- [PATCH 8/9] cp: -Z: fix a logic error due to incorrect braces in mkfifo, Pádraig Brady, 2012/11/27
- [PATCH 1/9] cp: -Z: adjust utils to run restorecon with -Z,
Pádraig Brady <=
- [PATCH 9/9] cp: -Z: adjust an existing selinux test to the new scheme, Pádraig Brady, 2012/11/27
- [PATCH] cp: -Z: fix memory leak edge case, Pádraig Brady, 2012/11/28
- Re: Make mv work better with SELinux., Jim Meyering, 2012/11/29