/* * chcon -- change security context, based on coreutils-5.97-13 * * Port to busybox: KaiGai Kohei * * Copyright (C) 2006 - 2007 KaiGai Kohei * * Licensed under GPLv2, see file LICENSE in this source tree. */ //usage:#define chcon_trivial_usage //usage: "[OPTIONS] CONTEXT FILE..." //usage: "\n chcon [OPTIONS] [-u USER] [-r ROLE] [-l RANGE] [-t TYPE] FILE..." //usage: IF_FEATURE_CHCON_LONG_OPTIONS( //usage: "\n chcon [OPTIONS] --reference=RFILE FILE..." //usage: ) //usage:#define chcon_full_usage "\n\n" //usage: "Change the security context of each FILE to CONTEXT\n" //usage: IF_FEATURE_CHCON_LONG_OPTIONS( //usage: "\n -v,--verbose Verbose" //usage: "\n -c,--changes Report changes made" //usage: "\n -h,--no-dereference Affect symlinks instead of their targets" //usage: "\n -f,--silent,--quiet Suppress most error messages" //usage: "\n --reference=RFILE Use RFILE's group instead of using a CONTEXT value" //usage: "\n -u,--user=USER Set user/role/type/range in the target" //usage: "\n -r,--role=ROLE security context" //usage: "\n -t,--type=TYPE" //usage: "\n -l,--range=RANGE" //usage: "\n -R,--recursive Recurse" //usage: ) //usage: IF_NOT_FEATURE_CHCON_LONG_OPTIONS( //usage: "\n -v Verbose" //usage: "\n -c Report changes made" //usage: "\n -h Affect symlinks instead of their targets" //usage: "\n -f Suppress most error messages" //usage: "\n -u USER Set user/role/type/range in the target security context" //usage: "\n -r ROLE" //usage: "\n -t TYPE" //usage: "\n -l RNG" //usage: "\n -R Recurse" //usage: ) #include #include "libbb.h" #define OPT_RECURSIVE (1<<0) /* 'R' */ #define OPT_CHANHES (1<<1) /* 'c' */ #define OPT_NODEREFERENCE (1<<2) /* 'h' */ #define OPT_QUIET (1<<3) /* 'f' */ #define OPT_USER (1<<4) /* 'u' */ #define OPT_ROLE (1<<5) /* 'r' */ #define OPT_TYPE (1<<6) /* 't' */ #define OPT_RANGE (1<<7) /* 'l' */ #define OPT_VERBOSE (1<<8) /* 'v' */ #define OPT_REFERENCE ((1<<9) * ENABLE_FEATURE_CHCON_LONG_OPTIONS) #define OPT_COMPONENT_SPECIFIED (OPT_USER | OPT_ROLE | OPT_TYPE | OPT_RANGE) static char *user = NULL; static char *role = NULL; static char *type = NULL; static char *range = NULL; static char *specified_context = NULL; static int FAST_FUNC change_filedir_context( const char *fname, struct stat *stbuf UNUSED_PARAM, void *userData UNUSED_PARAM, int depth UNUSED_PARAM) { context_t context = NULL; security_context_t file_context = NULL; security_context_t context_string; int rc = FALSE; int status = 0; if (option_mask32 & OPT_NODEREFERENCE) { status = lgetfilecon(fname, &file_context); } else { status = getfilecon(fname, &file_context); } if (status < 0 && errno != ENODATA) { if ((option_mask32 & OPT_QUIET) == 0) bb_error_msg("can't obtain security context: %s", fname); goto skip; } if (file_context == NULL && specified_context == NULL) { bb_error_msg("can't apply partial context to unlabeled file %s", fname); goto skip; } if (specified_context == NULL) { context = set_security_context_component(file_context, user, role, type, range); if (!context) { bb_error_msg("can't compute security context from %s", file_context); goto skip; } } else { context = context_new(specified_context); if (!context) { bb_error_msg("invalid context: %s", specified_context); goto skip; } } context_string = context_str(context); if (!context_string) { bb_error_msg("can't obtain security context in text expression"); goto skip; } if (file_context == NULL || strcmp(context_string, file_context) != 0) { int fail; if (option_mask32 & OPT_NODEREFERENCE) { fail = lsetfilecon(fname, context_string); } else { fail = setfilecon(fname, context_string); } if ((option_mask32 & OPT_VERBOSE) || ((option_mask32 & OPT_CHANHES) && !fail)) { printf(!fail ? "context of %s changed to %s\n" : "can't change context of %s to %s\n", fname, context_string); } if (!fail) { rc = TRUE; } else if ((option_mask32 & OPT_QUIET) == 0) { bb_error_msg("can't change context of %s to %s", fname, context_string); } } else if (option_mask32 & OPT_VERBOSE) { printf("context of %s retained as %s\n", fname, context_string); rc = TRUE; } skip: context_free(context); freecon(file_context); return rc; } #if ENABLE_FEATURE_CHCON_LONG_OPTIONS static const char chcon_longopts[] ALIGN1 = "recursive\0" No_argument "R" "changes\0" No_argument "c" "no-dereference\0" No_argument "h" "silent\0" No_argument "f" "quiet\0" No_argument "f" "user\0" Required_argument "u" "role\0" Required_argument "r" "type\0" Required_argument "t" "range\0" Required_argument "l" "verbose\0" No_argument "v" "reference\0" Required_argument "\xff" /* no short option */ ; #endif int chcon_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int chcon_main(int argc UNUSED_PARAM, char **argv) { char *reference_file; char *fname; int i, errors = 0; #if ENABLE_FEATURE_CHCON_LONG_OPTIONS applet_long_options = chcon_longopts; #endif opt_complementary = "-1" /* at least 1 param */ ":?" /* error if exclusivity constraints are violated */ #if ENABLE_FEATURE_CHCON_LONG_OPTIONS ":\xff--urtl:u--\xff:r--\xff:t--\xff:l--\xff" #endif ":f--v:v--f"; /* 'verbose' and 'quiet' are exclusive */ getopt32(argv, "Rchfu:r:t:l:v", &user, &role, &type, &range, &reference_file); argv += optind; #if ENABLE_FEATURE_CHCON_LONG_OPTIONS if (option_mask32 & OPT_REFERENCE) { /* FIXME: lgetfilecon() should be used when '-h' is specified. * But current implementation follows the original one. */ if (getfilecon(reference_file, &specified_context) < 0) bb_perror_msg_and_die("getfilecon('%s') failed", reference_file); } else #endif if ((option_mask32 & OPT_COMPONENT_SPECIFIED) == 0) { specified_context = *argv++; /* specified_context is never NULL - * "-1" in opt_complementary prevents this. */ if (!argv[0]) bb_error_msg_and_die("too few arguments"); } for (i = 0; (fname = argv[i]) != NULL; i++) { int fname_len = strlen(fname); while (fname_len > 1 && fname[fname_len - 1] == '/') fname_len--; fname[fname_len] = '\0'; if (recursive_action(fname, 1<