summaryrefslogtreecommitdiff
path: root/src/install.c
diff options
context:
space:
mode:
authorJim Meyering <jim@meyering.net>2007-01-20 16:10:43 +0100
committerJim Meyering <jim@meyering.net>2007-03-29 21:37:06 +0200
commit85ddc626be5fd202f04aa8ced398b5119174b556 (patch)
treefdece904533e6747c797254cff27512a3e82cb3d /src/install.c
parent5a7fe9c0f8a3154d52d44265c73675b91441b209 (diff)
downloadcoreutils-85ddc626be5fd202f04aa8ced398b5119174b556.tar.xz
cp, mv, install: add SELinux support, but unlike with the Red Hat
patch, mv and cp do not provide the "-Z context" option. * src/copy.c: Include <selinux/selinux.h>. (restore_default_fscreatecon): New function. (copy_reg): Make cp --preserve=context work for existing destination. (copy_internal): Likewise for new destinations. * src/copy.h (cp_options) [preserve_security_context]: New member. * src/cp.c: Include <selinux/selinux.h>. (selinux_enabled): New global. (usage): Mention new --preserve=context option. (PRESERVE_CONTEXT): Define/use. (decode_preserve_arg): Handle PRESERVE_CONTEXT. (main): Remove an obsolete comment. If --preserve=context is specified on a system without SELinux enabled, give a diagnostic and fail. * src/mv.c: Include <selinux/selinux.h>. Set x->preserve_security_context if SELinux is enabled. * src/install.c: Accept new "-Z, --context=C" option. Accept --preserve-context option (but not -P option). Accept alternate spelling: --preserve_context, for now. Include <selinux/selinux.h> and "quotearg.h". (selinux_enabled, use_default_selinux_context): New globals. (PRESERVE_CONTEXT_OPTION): Define. (cp_option_init): Default: do not preserve security context. (setdefaultfilecon): New function. (main): Honor new options. * src/Makefile.am (mv_LDADD, cp_LDADD, ginstall_LDADD): Add $(LIB_SELINUX).
Diffstat (limited to 'src/install.c')
-rw-r--r--src/install.c103
1 files changed, 100 insertions, 3 deletions
diff --git a/src/install.c b/src/install.c
index 6f85a24f4..f6152f355 100644
--- a/src/install.c
+++ b/src/install.c
@@ -24,6 +24,7 @@
#include <signal.h>
#include <pwd.h>
#include <grp.h>
+#include <selinux/selinux.h>
#include "system.h"
#include "backupfile.h"
@@ -35,6 +36,7 @@
#include "mkdir-p.h"
#include "modechange.h"
#include "quote.h"
+#include "quotearg.h"
#include "savewd.h"
#include "stat-time.h"
#include "utimens.h"
@@ -49,6 +51,9 @@
# include <sys/wait.h>
#endif
+static int selinux_enabled = 0;
+static bool use_default_selinux_context = true;
+
#if ! HAVE_ENDGRENT
# define endgrent() ((void) 0)
#endif
@@ -121,15 +126,28 @@ static bool strip_files;
/* If true, install a directory instead of a regular file. */
static bool dir_arg;
+/* For long options that have no equivalent short option, use a
+ non-character as a pseudo short option, starting with CHAR_MAX + 1. */
+enum
+{
+ PRESERVE_CONTEXT_OPTION = CHAR_MAX + 1
+};
+
static struct option const long_options[] =
{
{"backup", optional_argument, NULL, 'b'},
+ {GETOPT_SELINUX_CONTEXT_OPTION_DECL},
{"directory", no_argument, NULL, 'd'},
{"group", required_argument, NULL, 'g'},
{"mode", required_argument, NULL, 'm'},
{"no-target-directory", no_argument, NULL, 'T'},
{"owner", required_argument, NULL, 'o'},
{"preserve-timestamps", no_argument, NULL, 'p'},
+ {"preserve-context", no_argument, NULL, PRESERVE_CONTEXT_OPTION},
+ /* Continue silent support for --preserve_context until Jan 2008. FIXME-obs
+ After that, FIXME-obs: warn in, say, late 2008, and disable altogether
+ a year or two later. */
+ {"preserve_context", no_argument, NULL, PRESERVE_CONTEXT_OPTION},
{"strip", no_argument, NULL, 's'},
{"suffix", required_argument, NULL, 'S'},
{"target-directory", required_argument, NULL, 't'},
@@ -169,11 +187,47 @@ cp_option_init (struct cp_options *x)
x->stdin_tty = false;
x->update = false;
+ x->preserve_security_context = false;
x->verbose = false;
x->dest_info = NULL;
x->src_info = NULL;
}
+/* Modify file context to match the specified policy.
+ If an error occurs the file will remain with the default directory
+ context. */
+static void
+setdefaultfilecon (char const *file)
+{
+ struct stat st;
+ security_context_t scontext = NULL;
+ if (selinux_enabled != 1)
+ {
+ /* Indicate no context found. */
+ return;
+ }
+ if (lstat (file, &st) != 0)
+ return;
+
+ /* If there's an error determining the context, or it has none,
+ return to allow default context */
+ if ((matchpathcon (file, st.st_mode, &scontext) != 0) ||
+ (strcmp (scontext, "<<none>>") == 0))
+ {
+ if (scontext != NULL)
+ freecon (scontext);
+ return;
+ }
+
+ if (lsetfilecon (file, scontext) < 0 && errno != ENOTSUP)
+ error (0, errno,
+ _("warning: %s: failed to change context to %s"),
+ quotearg_colon (file), scontext);
+
+ freecon (scontext);
+ return;
+}
+
/* FILE is the last operand of this command. Return true if FILE is a
directory. But report an error there is a problem accessing FILE,
or if FILE does not exist but would have to refer to an existing
@@ -222,6 +276,9 @@ main (int argc, char **argv)
bool no_target_directory = false;
int n_files;
char **file;
+ security_context_t scontext = NULL;
+ /* set iff kernel has extra selinux system calls */
+ selinux_enabled = (0 < is_selinux_enabled ());
initialize_main (&argc, &argv);
program_name = argv[0];
@@ -243,7 +300,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, "bcsDdg:m:o:pt:TvS:", long_options,
+ while ((optc = getopt_long (argc, argv, "bcsDdg:m:o:pt:TvS:Z:", long_options,
NULL)) != -1)
{
switch (optc)
@@ -305,6 +362,27 @@ main (int argc, char **argv)
case 'T':
no_target_directory = true;
break;
+
+ case PRESERVE_CONTEXT_OPTION:
+ if ( ! selinux_enabled)
+ {
+ error (0, 0, _("Warning: ignoring --preserve-context; "
+ "this kernel is not SELinux-enabled."));
+ break;
+ }
+ 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;
+ break;
case_GETOPT_HELP_CHAR;
case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS);
default:
@@ -320,6 +398,11 @@ main (int argc, char **argv)
error (EXIT_FAILURE, 0,
_("target directory not allowed when installing a directory"));
+ if (x.preserve_security_context && scontext != NULL)
+ error (EXIT_FAILURE, 0,
+ _("cannot force target context to %s and preserve it"),
+ quote (scontext));
+
if (backup_suffix_string)
simple_backup_suffix = xstrdup (backup_suffix_string);
@@ -328,6 +411,11 @@ main (int argc, char **argv)
version_control_string)
: no_backups);
+ if (scontext && setfscreatecon (scontext) < 0)
+ error (EXIT_FAILURE, errno,
+ _("failed to set default file creation context to %s"),
+ quote (scontext));
+
n_files = argc - optind;
file = argv + optind;
@@ -503,6 +591,7 @@ copy_file (const char *from, const char *to, const struct cp_options *x)
static bool
change_attributes (char const *name)
{
+ bool ok = false;
/* chown must precede chmod because on some systems,
chown clears the set[ug]id bits for non-superusers,
resulting in incorrect permissions.
@@ -521,9 +610,12 @@ change_attributes (char const *name)
else if (chmod (name, mode) != 0)
error (0, errno, _("cannot change permissions of %s"), quote (name));
else
- return true;
+ ok = true;
+
+ if (use_default_selinux_context)
+ setdefaultfilecon (name);
- return false;
+ return ok;
}
/* Set the timestamps of file TO to match those of file FROM.
@@ -687,6 +779,11 @@ Mandatory arguments to long options are mandatory for short options too.\n\
-T, --no-target-directory treat DEST as a normal file\n\
-v, --verbose print the name of each directory as it is created\n\
"), stdout);
+ fputs (_("\
+ --preserve-context preserve SELinux security context\n\
+ -Z, --context=CONTEXT set SELinux security context of files and directories\n\
+"), stdout);
+
fputs (HELP_OPTION_DESCRIPTION, stdout);
fputs (VERSION_OPTION_DESCRIPTION, stdout);
fputs (_("\