>From aa0c25ceeda99cb9df0e089aa927a4ac382c67bf Mon Sep 17 00:00:00 2001 From: rhatdan Date: Tue, 30 Oct 2012 09:48:15 -0400 Subject: [PATCH] build: Change -Z opt w/out arg label target with default label --- src/chcon.c | 2 +- src/copy.c | 52 +++++------- src/copy.h | 3 + src/cp.c | 35 ++++++-- src/install.c | 16 ++-- src/local.mk | 15 +++- src/mkdir.c | 19 ++++- src/mkfifo.c | 13 ++- src/mknod.c | 14 ++- src/mv.c | 16 +++- src/runcon.c | 2 +- src/selinux.c | 269 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ src/selinux.h | 26 ++++++ 13 files changed, 425 insertions(+), 57 deletions(-) create mode 100644 src/selinux.c create mode 100644 src/selinux.h diff --git a/src/chcon.c b/src/chcon.c index 34e92e4..0cf8fa6 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 16aed03..c91a756 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 @@ -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 61b31af..017e4da 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} @@ -229,6 +230,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[=CONTEXT] set security context of destination file to default type or to CONTEXT if specified\n\ "), stdout); fputs (HELP_OPTION_DESCRIPTION, stdout); fputs (VERSION_OPTION_DESCRIPTION, stdout); @@ -786,6 +788,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; @@ -877,8 +880,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: @@ -892,7 +897,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; @@ -935,7 +940,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) { @@ -962,7 +967,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; @@ -1092,6 +1097,26 @@ 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 ) { + fprintf( stderr, "Warning: ignoring --context (-Z). " + "It requires a SELinux enabled kernel.\n" ); + break; + } + 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..a1511bf 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,7 +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\ + -Z, --context[=CONTEXT] set SELinux security context of files and directories\ \n\ "), stdout); @@ -783,7 +784,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,8 +861,11 @@ 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) @@ -870,8 +874,10 @@ main (int argc, char **argv) "this kernel is not SELinux-enabled")); break; } - scontext = optarg; - use_default_selinux_context = false; + 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 f40f681..113544a 100644 --- a/src/local.mk +++ b/src/local.mk @@ -306,6 +306,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 \ @@ -317,12 +321,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 @@ -335,12 +339,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..80e9fa5 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,10 @@ main (int argc, char **argv) options.created_directory_format = _("created directory %s"); break; case 'Z': - scontext = optarg; + 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..bd51a53 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,10 @@ main (int argc, char **argv) specified_mode = optarg; break; case 'Z': - scontext = optarg; + if (optarg) + scontext = optarg; + else + set_security_context = true; break; case_GETOPT_HELP_CHAR; case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); @@ -128,6 +133,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..b1b35eb 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,10 @@ main (int argc, char **argv) specified_mode = optarg; break; case 'Z': - scontext = optarg; + if (optarg) + scontext = optarg; + else + set_security_context = true; break; case_GETOPT_HELP_CHAR; case_GETOPT_VERSION_CHAR (PROGRAM_NAME, AUTHORS); @@ -212,6 +217,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..2711d9f 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,16 @@ 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 ) { + fprintf( stderr, "Warning: ignoring --context (-Z). " + "It requires a SELinux enabled kernel.\n" ); + break; + } + 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 . */ + +/* Written by Daniel Walsh */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#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 . */ + +/* Written by Daniel Walsh */ + +#ifndef COREUTILS_SELINUX_H +#define COREUTILS_SELINUX_H + +#include +#include +extern bool restorecon (char const *path, bool recurse, bool preserve); +extern int defaultcon (char const *path, mode_t mode); +#endif -- 1.7.12.1