next portion of selinux updates: chcon, runcon. From Yuichi Nakamura
No binary (build failed)
—
(log yok)
| @@ -89,7 +89,7 @@ int id_main(int argc, char **argv) | |
| if (flags & JUST_CONTEXT) { | |
| selinux_or_die(); | |
| if (argc - optind == 1) { | |
| - | bb_error_msg_and_die("can't print security context when user specified"); |
| + | bb_error_msg_and_die("user name can't be passed with -Z"); |
| } | |
| if (getcon(&scontext)) { | |
| @@ -1,6 +1,7 @@ | |
| /* vi: set sw=4 ts=4: */ | |
| /* | |
| - | * Copyright (C) 2003 by Glenn McGrath <[email protected]> |
| + | * Copyright (C) 2003 by Glenn McGrath <[email protected]> |
| + | * SELinux support: by Yuichi Nakamura <[email protected]> |
| * | |
| * Licensed under GPLv2 or later, see file LICENSE in this tarball for details. | |
| * | |
| @@ -41,6 +41,7 @@ | |
| #if ENABLE_SELINUX | |
| #include <selinux/selinux.h> | |
| + | #include <selinux/context.h> |
| #endif | |
| #if ENABLE_LOCALE_SUPPORT | |
| @@ -598,6 +599,8 @@ extern void run_shell(const char *shell, int loginshell, const char *command, co | |
| #if ENABLE_SELINUX | |
| extern void renew_current_security_context(void); | |
| extern void set_current_security_context(security_context_t sid); | |
| + | extern context_t set_security_context_component(security_context_t cur_context, |
| + | char *user, char *role, char *type, char *range); |
| #endif | |
| extern void selinux_or_die(void); | |
| extern int restricted_shell(const char *shell); | |
| @@ -106,6 +106,7 @@ lib-$(CONFIG_SU) += correct_password.o | |
| lib-$(CONFIG_LOGIN) += correct_password.o | |
| lib-$(CONFIG_DF) += find_mount_point.o | |
| lib-$(CONFIG_MKFS_MINIX) += find_mount_point.o | |
| + | lib-$(CONFIG_SELINUX) += selinux_common.o |
| # We shouldn't build xregcomp.c if we don't need it - this ensures we don't | |
| # require regex.h to be in the include dir even if we don't need it thereby | |
| @@ -0,0 +1,30 @@ | |
| + | /* |
| + | * libbb/selinux_common.c |
| + | * -- common SELinux utility functions |
| + | * |
| + | * Copyright 2007 KaiGai Kohei <[email protected]> |
| + | */ |
| + | #include "busybox.h" |
| + | #include <selinux/context.h> |
| + | |
| + | context_t set_security_context_component(security_context_t cur_context, |
| + | char *user, char *role, char *type, char *range) |
| + | { |
| + | context_t con = context_new(cur_context); |
| + | if (!con) |
| + | return NULL; |
| + | |
| + | if (user && context_user_set(con, user)) |
| + | goto error; |
| + | if (type && context_type_set(con, type)) |
| + | goto error; |
| + | if (range && context_range_set(con, range)) |
| + | goto error; |
| + | if (role && context_role_set(con, role)) |
| + | goto error; |
| + | return con; |
| + | |
| + | error: |
| + | context_free(con); |
| + | return NULL; |
| + | } |
| @@ -0,0 +1,175 @@ | |
| + | /* |
| + | * chcon -- change security context, based on coreutils-5.97-13 |
| + | * |
| + | * Port to busybox: KaiGai Kohei <[email protected]> |
| + | * |
| + | * Copyright (C) 2006 - 2007 KaiGai Kohei <[email protected]> |
| + | */ |
| + | #include "busybox.h" |
| + | #include <getopt.h> |
| + | #include <selinux/context.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 change_filedir_context(const char *fname, struct stat *stbuf, void *userData, int depth) |
| + | { |
| + | 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("cannot obtain security context: %s", fname); |
| + | goto skip; |
| + | } |
| + | |
| + | if (file_context == NULL && specified_context == NULL) { |
| + | bb_error_msg("cannot 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("cannot 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("cannot 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" |
| + | : "failed to change context of %s to %s\n", |
| + | fname, context_string); |
| + | } |
| + | if (!fail) { |
| + | rc = TRUE; |
| + | } else if ((option_mask32 & OPT_QUIET) == 0) { |
| + | bb_error_msg("failed to 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: |
| + | /* FIXME: aren't these work ok on NULL ptr? Remove if() then */ |
| + | if (context) |
| + | context_free(context); |
| + | if (file_context) |
| + | freecon(file_context); |
| + | |
| + | return rc; |
| + | } |
| + | |
| + | #if ENABLE_FEATURE_CHCON_LONG_OPTIONS |
| + | static struct option chcon_options[] = { |
| + | { "recursive", 0, NULL, 'R' }, |
| + | { "changes", 0, NULL, 'c' }, |
| + | { "no-dereference", 0, NULL, 'h' }, |
| + | { "silent", 0, NULL, 'f' }, |
| + | { "quiet", 0, NULL, 'f' }, |
| + | { "user", 1, NULL, 'u' }, |
| + | { "role", 1, NULL, 'r' }, |
| + | { "type", 1, NULL, 't' }, |
| + | { "range", 1, NULL, 'l' }, |
| + | { "verbose", 0, NULL, 'v' }, |
| + | { "reference", 1, NULL, 0xff }, /* no short option */ |
| + | { NULL, 0, NULL, 0 }, |
| + | }; |
| + | #endif |
| + | |
| + | int chcon_main(int argc, char *argv[]); |
| + | int chcon_main(int argc, char *argv[]) |
| + | { |
| + | char *reference_file; |
| + | char *fname; |
| + | int i, errors = 0; |
| + | |
| + | #if ENABLE_FEATURE_CHCON_LONG_OPTIONS |
| + | applet_long_options = chcon_options; |
| + | #endif |
| + | opt_complementary = "-1" /* at least 1 param */ |
| + | ":?:f--v:v--f" /* 'verbose' and 'quiet' are exclusive */ |
| + | ":\xff--urtl:u--\xff:r--\xff:t--\xff:l--\xff"; |
| + | getopt32(argc, argv, "Rchf:u: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, |
| + | option_mask32 & OPT_RECURSIVE, |
| + | FALSE, /* followLinks */ |
| + | FALSE, /* depthFirst */ |
| + | change_filedir_context, |
| + | change_filedir_context, |
| + | NULL, 0) != TRUE) |
| + | errors = 1; |
| + | } |
| + | return errors; |
| + | } |
| @@ -0,0 +1,137 @@ | |
| + | /* |
| + | * runcon [ context | |
| + | * ( [ -c ] [ -r role ] [-t type] [ -u user ] [ -l levelrange ] ) |
| + | * command [arg1 [arg2 ...] ] |
| + | * |
| + | * attempt to run the specified command with the specified context. |
| + | * |
| + | * -r role : use the current context with the specified role |
| + | * -t type : use the current context with the specified type |
| + | * -u user : use the current context with the specified user |
| + | * -l level : use the current context with the specified level range |
| + | * -c : compute process transition context before modifying |
| + | * |
| + | * Contexts are interpreted as follows: |
| + | * |
| + | * Number of MLS |
| + | * components system? |
| + | * |
| + | * 1 - type |
| + | * 2 - role:type |
| + | * 3 Y role:type:range |
| + | * 3 N user:role:type |
| + | * 4 Y user:role:type:range |
| + | * 4 N error |
| + | * |
| + | * Port to busybox: KaiGai Kohei <[email protected]> |
| + | * - based on coreutils-5.97 (in Fedora Core 6) |
| + | */ |
| + | #include "busybox.h" |
| + | #include <getopt.h> |
| + | #include <selinux/context.h> |
| + | #include <selinux/flask.h> |
| + | |
| + | static context_t runcon_compute_new_context(char *user, char *role, char *type, char *range, |
| + | char *command, int compute_trans) |
| + | { |
| + | context_t con; |
| + | security_context_t cur_context; |
| + | |
| + | if (getcon(&cur_context)) |
| + | bb_error_msg_and_die("cannot get current context"); |
| + | |
| + | if (compute_trans) { |
| + | security_context_t file_context, new_context; |
| + | |
| + | if (getfilecon(command, &file_context) < 0) |
| + | bb_error_msg_and_die("cannot retrieve attributes of '%s'", |
| + | command); |
| + | if (security_compute_create(cur_context, file_context, |
| + | SECCLASS_PROCESS, &new_context)) |
| + | bb_error_msg_and_die("unable to compute a new context"); |
| + | cur_context = new_context; |
| + | } |
| + | |
| + | con = context_new(cur_context); |
| + | if (!con) |
| + | bb_error_msg_and_die("'%s' is not a valid context", cur_context); |
| + | if (user && context_user_set(con, user)) |
| + | bb_error_msg_and_die("failed to set new user '%s'", user); |
| + | if (type && context_type_set(con, type)) |
| + | bb_error_msg_and_die("failed to set new type '%s'", type); |
| + | if (range && context_range_set(con, range)) |
| + | bb_error_msg_and_die("failed to set new range '%s'", range); |
| + | if (role && context_role_set(con, role)) |
| + | bb_error_msg_and_die("failed to set new role '%s'", role); |
| + | |
| + | return con; |
| + | } |
| + | |
| + | #if ENABLE_FEATURE_RUNCON_LONG_OPTIONS |
| + | static const struct option runcon_options[] = { |
| + | { "user", 1, NULL, 'u' }, |
| + | { "role", 1, NULL, 'r' }, |
| + | { "type", 1, NULL, 't' }, |
| + | { "range", 1, NULL, 'l' }, |
| + | { "compute", 0, NULL, 'c' }, |
| + | { "help", 0, NULL, 'h' }, |
| + | { NULL, 0, NULL, 0 }, |
| + | }; |
| + | #endif |
| + | |
| + | #define OPTS_ROLE (1<<0) /* r */ |
| + | #define OPTS_TYPE (1<<1) /* t */ |
| + | #define OPTS_USER (1<<2) /* u */ |
| + | #define OPTS_RANGE (1<<3) /* l */ |
| + | #define OPTS_COMPUTE (1<<4) /* c */ |
| + | #define OPTS_HELP (1<<5) /* h */ |
| + | #define OPTS_CONTEXT_COMPONENT (OPTS_ROLE | OPTS_TYPE | OPTS_USER | OPTS_RANGE) |
| + | |
| + | int runcon_main(int argc, char *argv[]); |
| + | int runcon_main(int argc, char *argv[]) |
| + | { |
| + | char *role = NULL; |
| + | char *range = NULL; |
| + | char *user = NULL; |
| + | char *type = NULL; |
| + | char *context = NULL; |
| + | unsigned opts; |
| + | context_t con; |
| + | |
| + | selinux_or_die(); |
| + | |
| + | #if ENABLE_FEATURE_RUNCON_LONG_OPTIONS |
| + | applet_long_options = runcon_options; |
| + | #endif |
| + | opt_complementary = "-1"; |
| + | opts = getopt32(argc, argv, "r:t:u:l:ch", &role, &type, &user, &range); |
| + | argv += optind; |
| + | |
| + | if (!(opts & OPTS_CONTEXT_COMPONENT)) { |
| + | context = *argv++; |
| + | if (!argv[0]) |
| + | bb_error_msg_and_die("no command found"); |
| + | } |
| + | |
| + | if (context) { |
| + | con = context_new(context); |
| + | if (!con) |
| + | bb_error_msg_and_die("'%s' is not a valid context", context); |
| + | } else { |
| + | con = runcon_compute_new_context(user, role, type, range, |
| + | argv[0], opts & OPTS_COMPUTE); |
| + | } |
| + | |
| + | if (security_check_context(context_str(con))) |
| + | bb_error_msg_and_die("'%s' is not a valid context", |
| + | context_str(con)); |
| + | |
| + | if (setexeccon(context_str(con))) |
| + | bb_error_msg_and_die("cannot set up security context '%s'", |
| + | context_str(con)); |
| + | |
| + | execvp(argv[0], argv); |
| + | |
| + | bb_perror_msg_and_die("cannot execute '%s'", command); |
| + | return 1; |
| + | } |