From 73b16af8feec390afbabd9356d6e5e83c0390838 Mon Sep 17 00:00:00 2001 From: Bjørn Mork Date: Fri, 15 May 2015 10:20:47 +0200 Subject: busybox: imported from http://www.busybox.net/downloads/busybox-1.13.3.tar.bz2 MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Bjørn Mork --- selinux/Config.in | 123 +++++++++ selinux/Kbuild | 20 ++ selinux/chcon.c | 177 +++++++++++++ selinux/getenforce.c | 34 +++ selinux/getsebool.c | 66 +++++ selinux/load_policy.c | 22 ++ selinux/matchpathcon.c | 86 +++++++ selinux/runcon.c | 136 ++++++++++ selinux/selinuxenabled.c | 14 + selinux/sestatus.c | 202 +++++++++++++++ selinux/setenforce.c | 42 +++ selinux/setfiles.c | 645 +++++++++++++++++++++++++++++++++++++++++++++++ selinux/setsebool.c | 34 +++ 13 files changed, 1601 insertions(+) create mode 100644 selinux/Config.in create mode 100644 selinux/Kbuild create mode 100644 selinux/chcon.c create mode 100644 selinux/getenforce.c create mode 100644 selinux/getsebool.c create mode 100644 selinux/load_policy.c create mode 100644 selinux/matchpathcon.c create mode 100644 selinux/runcon.c create mode 100644 selinux/selinuxenabled.c create mode 100644 selinux/sestatus.c create mode 100644 selinux/setenforce.c create mode 100644 selinux/setfiles.c create mode 100644 selinux/setsebool.c (limited to 'selinux') diff --git a/selinux/Config.in b/selinux/Config.in new file mode 100644 index 0000000..e795e73 --- /dev/null +++ b/selinux/Config.in @@ -0,0 +1,123 @@ +# +# For a description of the syntax of this configuration file, +# see scripts/kbuild/config-language.txt. +# + +menu "SELinux Utilities" + depends on SELINUX + +config CHCON + bool "chcon" + default n + depends on SELINUX + help + Enable support to change the security context of file. + +config FEATURE_CHCON_LONG_OPTIONS + bool "Enable long options" + default y + depends on CHCON && GETOPT_LONG + help + Support long options for the chcon applet. + +config GETENFORCE + bool "getenforce" + default n + depends on SELINUX + help + Enable support to get the current mode of SELinux. + +config GETSEBOOL + bool "getsebool" + default n + depends on SELINUX + help + Enable support to get SELinux boolean values. + +config LOAD_POLICY + bool "load_policy" + default n + depends on SELINUX + help + Enable support to load SELinux policy. + +config MATCHPATHCON + bool "matchpathcon" + default n + depends on SELINUX + help + Enable support to get default security context of the + specified path from the file contexts configuration. + +config RESTORECON + bool "restorecon" + default n + depends on SELINUX + help + Enable support to relabel files. The feature is almost + the same as setfiles, but usage is a little different. + +config RUNCON + bool "runcon" + default n + depends on SELINUX + help + Enable support to run command in speficied security context. + +config FEATURE_RUNCON_LONG_OPTIONS + bool "Enable long options" + default y + depends on RUNCON && GETOPT_LONG + help + Support long options for the runcon applet. + +config SELINUXENABLED + bool "selinuxenabled" + default n + depends on SELINUX + help + Enable support for this command to be used within shell scripts + to determine if selinux is enabled. + +config SETENFORCE + bool "setenforce" + default n + depends on SELINUX + help + Enable support to modify the mode SELinux is running in. + +config SETFILES + bool "setfiles" + default n + depends on SELINUX + help + Enable support to modify to relabel files. + Notice: If you built libselinux with -D_FILE_OFFSET_BITS=64, + (It is default in libselinux's Makefile), you _must_ enable + CONFIG_LFS. + +config FEATURE_SETFILES_CHECK_OPTION + bool "Enable check option" + default n + depends on SETFILES + help + Support "-c" option (check the validity of the contexts against + the specified binary policy) for setfiles. Requires libsepol. + +config SETSEBOOL + bool "setsebool" + default n + depends on SELINUX + help + Enable support for change boolean. + semanage and -P option is not supported yet. + +config SESTATUS + bool "sestatus" + default n + depends on SELINUX + help + Displays the status of SELinux. + +endmenu + diff --git a/selinux/Kbuild b/selinux/Kbuild new file mode 100644 index 0000000..d0c190c --- /dev/null +++ b/selinux/Kbuild @@ -0,0 +1,20 @@ +# Makefile for busybox +# +# Copyright (C) 1999-2005 by Erik Andersen +# Copyright (C) 2007 by KaiGai Kohei +# +# Licensed under the GPL v2, see the file LICENSE in this tarball. + +lib-y:= +lib-$(CONFIG_CHCON) += chcon.o +lib-$(CONFIG_GETENFORCE) += getenforce.o +lib-$(CONFIG_GETSEBOOL) += getsebool.o +lib-$(CONFIG_LOAD_POLICY) += load_policy.o +lib-$(CONFIG_MATCHPATHCON) += matchpathcon.o +lib-$(CONFIG_RUNCON) += runcon.o +lib-$(CONFIG_SELINUXENABLED) += selinuxenabled.o +lib-$(CONFIG_SETENFORCE) += setenforce.o +lib-$(CONFIG_SETFILES) += setfiles.o +lib-$(CONFIG_RESTORECON) += setfiles.o +lib-$(CONFIG_SETSEBOOL) += setsebool.o +lib-$(CONFIG_SESTATUS) += sestatus.o diff --git a/selinux/chcon.c b/selinux/chcon.c new file mode 100644 index 0000000..80a030f --- /dev/null +++ b/selinux/chcon.c @@ -0,0 +1,177 @@ +/* + * chcon -- change security context, based on coreutils-5.97-13 + * + * Port to busybox: KaiGai Kohei + * + * Copyright (C) 2006 - 2007 KaiGai Kohei + */ +#include +#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("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: + 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< + * + */ + +#include "libbb.h" + +int getenforce_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int getenforce_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) +{ + int rc; + + rc = is_selinux_enabled(); + if (rc < 0) + bb_error_msg_and_die("is_selinux_enabled() failed"); + + if (rc == 1) { + rc = security_getenforce(); + if (rc < 0) + bb_error_msg_and_die("getenforce() failed"); + + if (rc) + puts("Enforcing"); + else + puts("Permissive"); + } else { + puts("Disabled"); + } + + return 0; +} diff --git a/selinux/getsebool.c b/selinux/getsebool.c new file mode 100644 index 0000000..ea080d4 --- /dev/null +++ b/selinux/getsebool.c @@ -0,0 +1,66 @@ +/* + * getsebool + * + * Based on libselinux 1.33.1 + * Port to BusyBox Hiroshi Shinji + * + */ + +#include "libbb.h" + +int getsebool_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int getsebool_main(int argc, char **argv) +{ + int i, rc = 0, active, pending, len = 0; + char **names; + unsigned opt; + + selinux_or_die(); + opt = getopt32(argv, "a"); + + if (opt) { /* -a */ + if (argc > 2) + bb_show_usage(); + + rc = security_get_boolean_names(&names, &len); + if (rc) + bb_perror_msg_and_die("cannot get boolean names"); + + if (!len) { + puts("No booleans"); + return 0; + } + } + + if (!len) { + if (argc < 2) + bb_show_usage(); + len = argc - 1; + names = xmalloc(sizeof(char *) * len); + for (i = 0; i < len; i++) + names[i] = xstrdup(argv[i + 1]); + } + + for (i = 0; i < len; i++) { + active = security_get_boolean_active(names[i]); + if (active < 0) { + bb_error_msg_and_die("error getting active value for %s", names[i]); + } + pending = security_get_boolean_pending(names[i]); + if (pending < 0) { + bb_error_msg_and_die("error getting pending value for %s", names[i]); + } + printf("%s --> %s", names[i], (active ? "on" : "off")); + if (pending != active) + printf(" pending: %s", (pending ? "on" : "off")); + bb_putchar('\n'); + } + + if (ENABLE_FEATURE_CLEAN_UP) { + for (i = 0; i < len; i++) + free(names[i]); + free(names); + } + + return rc; +} diff --git a/selinux/load_policy.c b/selinux/load_policy.c new file mode 100644 index 0000000..b7a5c6e --- /dev/null +++ b/selinux/load_policy.c @@ -0,0 +1,22 @@ +/* + * load_policy + * Author: Yuichi Nakamura + */ +#include "libbb.h" + +int load_policy_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int load_policy_main(int argc, char **argv UNUSED_PARAM) +{ + int rc; + + if (argc != 1) { + bb_show_usage(); + } + + rc = selinux_mkload_policy(1); + if (rc < 0) { + bb_perror_msg_and_die("can't load policy"); + } + + return 0; +} diff --git a/selinux/matchpathcon.c b/selinux/matchpathcon.c new file mode 100644 index 0000000..5cfd52a --- /dev/null +++ b/selinux/matchpathcon.c @@ -0,0 +1,86 @@ +/* matchpathcon - get the default security context for the specified + * path from the file contexts configuration. + * based on libselinux-1.32 + * Port to busybox: KaiGai Kohei + * + */ +#include "libbb.h" + +static int print_matchpathcon(char *path, int noprint) +{ + char *buf; + int rc = matchpathcon(path, 0, &buf); + if (rc < 0) { + bb_perror_msg("matchpathcon(%s) failed", path); + return 1; + } + if (!noprint) + printf("%s\t%s\n", path, buf); + else + puts(buf); + + freecon(buf); + return 0; +} + +#define OPT_NOT_PRINT (1<<0) /* -n */ +#define OPT_NOT_TRANS (1<<1) /* -N */ +#define OPT_FCONTEXT (1<<2) /* -f */ +#define OPT_PREFIX (1<<3) /* -p */ +#define OPT_VERIFY (1<<4) /* -V */ + +int matchpathcon_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int matchpathcon_main(int argc UNUSED_PARAM, char **argv) +{ + int error = 0; + unsigned opts; + char *fcontext, *prefix, *path; + + opt_complementary = "-1" /* at least one param reqd */ + ":?:f--p:p--f"; /* mutually exclusive */ + opts = getopt32(argv, "nNf:p:V", &fcontext, &prefix); + argv += optind; + + if (opts & OPT_NOT_TRANS) { + set_matchpathcon_flags(MATCHPATHCON_NOTRANS); + } + if (opts & OPT_FCONTEXT) { + if (matchpathcon_init(fcontext)) + bb_perror_msg_and_die("error while processing %s", fcontext); + } + if (opts & OPT_PREFIX) { + if (matchpathcon_init_prefix(NULL, prefix)) + bb_perror_msg_and_die("error while processing %s", prefix); + } + + while ((path = *argv++) != NULL) { + security_context_t con; + int rc; + + if (!(opts & OPT_VERIFY)) { + error += print_matchpathcon(path, opts & OPT_NOT_PRINT); + continue; + } + + if (selinux_file_context_verify(path, 0)) { + printf("%s verified\n", path); + continue; + } + + if (opts & OPT_NOT_TRANS) + rc = lgetfilecon_raw(path, &con); + else + rc = lgetfilecon(path, &con); + + if (rc >= 0) { + printf("%s has context %s, should be ", path, con); + error += print_matchpathcon(path, 1); + freecon(con); + continue; + } + printf("actual context unknown: %s, should be ", strerror(errno)); + error += print_matchpathcon(path, 1); + } + matchpathcon_fini(); + return error; +} diff --git a/selinux/runcon.c b/selinux/runcon.c new file mode 100644 index 0000000..a9471ef --- /dev/null +++ b/selinux/runcon.c @@ -0,0 +1,136 @@ +/* + * 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 + * - based on coreutils-5.97 (in Fedora Core 6) + */ +#include +#include +#include + +#include "libbb.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 char runcon_longopts[] ALIGN1 = + "user\0" Required_argument "u" + "role\0" Required_argument "r" + "type\0" Required_argument "t" + "range\0" Required_argument "l" + "compute\0" No_argument "c" + "help\0" No_argument "h" + ; +#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) MAIN_EXTERNALLY_VISIBLE; +int runcon_main(int argc UNUSED_PARAM, 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_longopts; +#endif + opt_complementary = "-1"; + opts = getopt32(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 given"); + } + + 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'", argv[0]); +} diff --git a/selinux/selinuxenabled.c b/selinux/selinuxenabled.c new file mode 100644 index 0000000..ea233d8 --- /dev/null +++ b/selinux/selinuxenabled.c @@ -0,0 +1,14 @@ +/* + * selinuxenabled + * + * Based on libselinux 1.33.1 + * Port to BusyBox Hiroshi Shinji + * + */ +#include "libbb.h" + +int selinuxenabled_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int selinuxenabled_main(int argc UNUSED_PARAM, char **argv UNUSED_PARAM) +{ + return !is_selinux_enabled(); +} diff --git a/selinux/sestatus.c b/selinux/sestatus.c new file mode 100644 index 0000000..eca557e --- /dev/null +++ b/selinux/sestatus.c @@ -0,0 +1,202 @@ +/* + * sestatus -- displays the status of SELinux + * + * Ported to busybox: KaiGai Kohei + * + * Copyright (C) KaiGai Kohei + */ + +#include "libbb.h" + +extern char *selinux_mnt; + +#define OPT_VERBOSE (1 << 0) +#define OPT_BOOLEAN (1 << 1) + +#define COL_FMT "%-31s " + +static void display_boolean(void) +{ + char **bools; + int i, active, pending, nbool; + + if (security_get_boolean_names(&bools, &nbool) < 0) + return; + + puts("\nPolicy booleans:"); + + for (i = 0; i < nbool; i++) { + active = security_get_boolean_active(bools[i]); + if (active < 0) + goto skip; + pending = security_get_boolean_pending(bools[i]); + if (pending < 0) + goto skip; + printf(COL_FMT "%s", + bools[i], active == 0 ? "off" : "on"); + if (active != pending) + printf(" (%sactivate pending)", pending == 0 ? "in" : ""); + bb_putchar('\n'); + skip: + if (ENABLE_FEATURE_CLEAN_UP) + free(bools[i]); + } + if (ENABLE_FEATURE_CLEAN_UP) + free(bools); +} + +static void read_config(char **pc, int npc, char **fc, int nfc) +{ + char *buf; + parser_t *parser; + int pc_ofs = 0, fc_ofs = 0, section = -1; + + pc[0] = fc[0] = NULL; + + parser = config_open("/etc/sestatus.conf"); + while (config_read(parser, &buf, 1, 1, "# \t", PARSE_NORMAL)) { + if (strcmp(buf, "[process]") == 0) { + section = 1; + } else if (strcmp(buf, "[files]") == 0) { + section = 2; + } else { + if (section == 1 && pc_ofs < npc -1) { + pc[pc_ofs++] = xstrdup(buf); + pc[pc_ofs] = NULL; + } else if (section == 2 && fc_ofs < nfc - 1) { + fc[fc_ofs++] = xstrdup(buf); + fc[fc_ofs] = NULL; + } + } + } + config_close(parser); +} + +static void display_verbose(void) +{ + security_context_t con, _con; + char *fc[50], *pc[50], *cterm; + pid_t *pidList; + int i; + + read_config(pc, ARRAY_SIZE(pc), fc, ARRAY_SIZE(fc)); + + /* process contexts */ + puts("\nProcess contexts:"); + + /* current context */ + if (getcon(&con) == 0) { + printf(COL_FMT "%s\n", "Current context:", con); + if (ENABLE_FEATURE_CLEAN_UP) + freecon(con); + } + /* /sbin/init context */ + if (getpidcon(1, &con) == 0) { + printf(COL_FMT "%s\n", "Init context:", con); + if (ENABLE_FEATURE_CLEAN_UP) + freecon(con); + } + + /* [process] context */ + for (i = 0; pc[i] != NULL; i++) { + pidList = find_pid_by_name(bb_basename(pc[i])); + if (pidList[0] > 0 && getpidcon(pidList[0], &con) == 0) { + printf(COL_FMT "%s\n", pc[i], con); + if (ENABLE_FEATURE_CLEAN_UP) + freecon(con); + } + if (ENABLE_FEATURE_CLEAN_UP) + free(pidList); + } + + /* files contexts */ + puts("\nFile contexts:"); + + cterm = ttyname(0); + puts(cterm); + if (cterm && lgetfilecon(cterm, &con) >= 0) { + printf(COL_FMT "%s\n", "Controlling term:", con); + if (ENABLE_FEATURE_CLEAN_UP) + freecon(con); + } + + for (i=0; fc[i] != NULL; i++) { + struct stat stbuf; + + if (lgetfilecon(fc[i], &con) < 0) + continue; + if (lstat(fc[i], &stbuf) == 0) { + if (S_ISLNK(stbuf.st_mode)) { + if (getfilecon(fc[i], &_con) >= 0) { + printf(COL_FMT "%s -> %s\n", fc[i], _con, con); + if (ENABLE_FEATURE_CLEAN_UP) + freecon(_con); + } + } else { + printf(COL_FMT "%s\n", fc[i], con); + } + } + if (ENABLE_FEATURE_CLEAN_UP) + freecon(con); + } +} + +int sestatus_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int sestatus_main(int argc UNUSED_PARAM, char **argv) +{ + unsigned opts; + const char *pol_path; + int rc; + + opt_complementary = "?0"; /* no arguments are required. */ + opts = getopt32(argv, "vb"); + + /* SELinux status: line */ + rc = is_selinux_enabled(); + if (rc < 0) + goto error; + printf(COL_FMT "%s\n", "SELinux status:", + rc == 1 ? "enabled" : "disabled"); + + /* SELinuxfs mount: line */ + if (!selinux_mnt) + goto error; + printf(COL_FMT "%s\n", "SELinuxfs mount:", + selinux_mnt); + + /* Current mode: line */ + rc = security_getenforce(); + if (rc < 0) + goto error; + printf(COL_FMT "%s\n", "Current mode:", + rc == 0 ? "permissive" : "enforcing"); + + /* Mode from config file: line */ + if (selinux_getenforcemode(&rc) != 0) + goto error; + printf(COL_FMT "%s\n", "Mode from config file:", + rc < 0 ? "disabled" : (rc == 0 ? "permissive" : "enforcing")); + + /* Policy version: line */ + rc = security_policyvers(); + if (rc < 0) + goto error; + printf(COL_FMT "%u\n", "Policy version:", rc); + + /* Policy from config file: line */ + pol_path = selinux_policy_root(); + if (!pol_path) + goto error; + printf(COL_FMT "%s\n", "Policy from config file:", + bb_basename(pol_path)); + + if (opts & OPT_BOOLEAN) + display_boolean(); + if (opts & OPT_VERBOSE) + display_verbose(); + + return 0; + + error: + bb_perror_msg_and_die("libselinux returns unknown state"); +} diff --git a/selinux/setenforce.c b/selinux/setenforce.c new file mode 100644 index 0000000..198324c --- /dev/null +++ b/selinux/setenforce.c @@ -0,0 +1,42 @@ +/* + * setenforce + * + * Based on libselinux 1.33.1 + * Port to BusyBox Hiroshi Shinji + * + */ + +#include "libbb.h" + +/* These strings are arranged so that odd ones + * result in security_setenforce(1) being done, + * the rest will do security_setenforce(0) */ +static const char *const setenforce_cmd[] = { + "0", + "1", + "permissive", + "enforcing", + NULL, +}; + +int setenforce_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int setenforce_main(int argc, char **argv) +{ + int i, rc; + + if (argc != 2) + bb_show_usage(); + + selinux_or_die(); + + for (i = 0; setenforce_cmd[i]; i++) { + if (strcasecmp(argv[1], setenforce_cmd[i]) != 0) + continue; + rc = security_setenforce(i & 1); + if (rc < 0) + bb_perror_msg_and_die("setenforce() failed"); + return 0; + } + + bb_show_usage(); +} diff --git a/selinux/setfiles.c b/selinux/setfiles.c new file mode 100644 index 0000000..8eb04e6 --- /dev/null +++ b/selinux/setfiles.c @@ -0,0 +1,645 @@ +/* + setfiles: based on policycoreutils 2.0.19 + policycoreutils was released under GPL 2. + Port to BusyBox (c) 2007 by Yuichi Nakamura +*/ + +#include "libbb.h" +#if ENABLE_FEATURE_SETFILES_CHECK_OPTION +#include +#endif + +#define MAX_EXCLUDES 50 + +struct edir { + char *directory; + size_t size; +}; + +struct globals { + FILE *outfile; + char *policyfile; + char *rootpath; + int rootpathlen; + unsigned count; + int excludeCtr; + int errors; + int verbose; /* getopt32 uses it, has to be int */ + smallint recurse; /* Recursive descent */ + smallint follow_mounts; + /* Behavior flags determined based on setfiles vs. restorecon */ + smallint expand_realpath; /* Expand paths via realpath */ + smallint abort_on_error; /* Abort the file tree walk upon an error */ + int add_assoc; /* Track inode associations for conflict detection */ + int matchpathcon_flags; /* Flags to matchpathcon */ + dev_t dev_id; /* Device id where target file exists */ + int nerr; + struct edir excludeArray[MAX_EXCLUDES]; +}; + +#define G (*(struct globals*)&bb_common_bufsiz1) +void BUG_setfiles_globals_too_big(void); +#define INIT_G() do { \ + if (sizeof(G) > COMMON_BUFSIZE) \ + BUG_setfiles_globals_too_big(); \ + /* memset(&G, 0, sizeof(G)); - already is */ \ +} while (0) +#define outfile (G.outfile ) +#define policyfile (G.policyfile ) +#define rootpath (G.rootpath ) +#define rootpathlen (G.rootpathlen ) +#define count (G.count ) +#define excludeCtr (G.excludeCtr ) +#define errors (G.errors ) +#define verbose (G.verbose ) +#define recurse (G.recurse ) +#define follow_mounts (G.follow_mounts ) +#define expand_realpath (G.expand_realpath ) +#define abort_on_error (G.abort_on_error ) +#define add_assoc (G.add_assoc ) +#define matchpathcon_flags (G.matchpathcon_flags) +#define dev_id (G.dev_id ) +#define nerr (G.nerr ) +#define excludeArray (G.excludeArray ) + +/* Must match getopt32 string! */ +enum { + OPT_d = (1 << 0), + OPT_e = (1 << 1), + OPT_f = (1 << 2), + OPT_i = (1 << 3), + OPT_l = (1 << 4), + OPT_n = (1 << 5), + OPT_p = (1 << 6), + OPT_q = (1 << 7), + OPT_r = (1 << 8), + OPT_s = (1 << 9), + OPT_v = (1 << 10), + OPT_o = (1 << 11), + OPT_F = (1 << 12), + OPT_W = (1 << 13), + OPT_c = (1 << 14), /* c only for setfiles */ + OPT_R = (1 << 14), /* R only for restorecon */ +}; +#define FLAG_d_debug (option_mask32 & OPT_d) +#define FLAG_e (option_mask32 & OPT_e) +#define FLAG_f (option_mask32 & OPT_f) +#define FLAG_i_ignore_enoent (option_mask32 & OPT_i) +#define FLAG_l_take_log (option_mask32 & OPT_l) +#define FLAG_n_dry_run (option_mask32 & OPT_n) +#define FLAG_p_progress (option_mask32 & OPT_p) +#define FLAG_q_quiet (option_mask32 & OPT_q) +#define FLAG_r (option_mask32 & OPT_r) +#define FLAG_s (option_mask32 & OPT_s) +#define FLAG_v (option_mask32 & OPT_v) +#define FLAG_o (option_mask32 & OPT_o) +#define FLAG_F_force (option_mask32 & OPT_F) +#define FLAG_W_warn_no_match (option_mask32 & OPT_W) +#define FLAG_c (option_mask32 & OPT_c) +#define FLAG_R (option_mask32 & OPT_R) + + +static void qprintf(const char *fmt UNUSED_PARAM, ...) +{ + /* quiet, do nothing */ +} + +static void inc_err(void) +{ + nerr++; + if (nerr > 9 && !FLAG_d_debug) { + bb_error_msg_and_die("exiting after 10 errors"); + } +} + +static void add_exclude(const char *const directory) +{ + struct stat sb; + size_t len; + + if (directory == NULL || directory[0] != '/') { + bb_error_msg_and_die("full path required for exclude: %s", directory); + + } + if (lstat(directory, &sb)) { + bb_error_msg("directory \"%s\" not found, ignoring", directory); + return; + } + if ((sb.st_mode & S_IFDIR) == 0) { + bb_error_msg("\"%s\" is not a directory: mode %o, ignoring", + directory, sb.st_mode); + return; + } + if (excludeCtr == MAX_EXCLUDES) { + bb_error_msg_and_die("maximum excludes %d exceeded", MAX_EXCLUDES); + } + + len = strlen(directory); + while (len > 1 && directory[len - 1] == '/') { + len--; + } + excludeArray[excludeCtr].directory = xstrndup(directory, len); + excludeArray[excludeCtr++].size = len; +} + +static bool exclude(const char *file) +{ + int i = 0; + for (i = 0; i < excludeCtr; i++) { + if (strncmp(file, excludeArray[i].directory, + excludeArray[i].size) == 0) { + if (file[excludeArray[i].size] == '\0' + || file[excludeArray[i].size] == '/') { + return 1; + } + } + } + return 0; +} + +static int match(const char *name, struct stat *sb, char **con) +{ + int ret; + char path[PATH_MAX + 1]; + char *tmp_path = xstrdup(name); + + if (excludeCtr > 0 && exclude(name)) { + goto err; + } + ret = lstat(name, sb); + if (ret) { + if (FLAG_i_ignore_enoent && errno == ENOENT) { + free(tmp_path); + return 0; + } + bb_error_msg("stat(%s)", name); + goto err; + } + + if (expand_realpath) { + if (S_ISLNK(sb->st_mode)) { + char *p = NULL; + char *file_sep; + + size_t len = 0; + + if (verbose > 1) + bb_error_msg("warning! %s refers to a symbolic link, not following last component", name); + + file_sep = strrchr(tmp_path, '/'); + if (file_sep == tmp_path) { + file_sep++; + path[0] = '\0'; + p = path; + } else if (file_sep) { + *file_sep++ = '\0'; + p = realpath(tmp_path, path); + } else { + file_sep = tmp_path; + p = realpath("./", path); + } + if (p) + len = strlen(p); + if (!p || len + strlen(file_sep) + 2 > PATH_MAX) { + bb_perror_msg("realpath(%s) failed", name); + goto err; + } + p += len; + /* ensure trailing slash of directory name */ + if (len == 0 || p[-1] != '/') { + *p++ = '/'; + } + strcpy(p, file_sep); + name = path; + if (excludeCtr > 0 && exclude(name)) + goto err; + + } else { + char *p; + p = realpath(name, path); + if (!p) { + bb_perror_msg("realpath(%s)", name); + goto err; + } + name = p; + if (excludeCtr > 0 && exclude(name)) + goto err; + } + } + + /* name will be what is matched in the policy */ + if (NULL != rootpath) { + if (0 != strncmp(rootpath, name, rootpathlen)) { + bb_error_msg("%s is not located in %s", + name, rootpath); + goto err; + } + name += rootpathlen; + } + + free(tmp_path); + if (rootpath != NULL && name[0] == '\0') + /* this is actually the root dir of the alt root */ + return matchpathcon_index("/", sb->st_mode, con); + return matchpathcon_index(name, sb->st_mode, con); + err: + free(tmp_path); + return -1; +} + +/* Compare two contexts to see if their differences are "significant", + * or whether the only difference is in the user. */ +static bool only_changed_user(const char *a, const char *b) +{ + if (FLAG_F_force) + return 0; + if (!a || !b) + return 0; + a = strchr(a, ':'); /* Rest of the context after the user */ + b = strchr(b, ':'); + if (!a || !b) + return 0; + return (strcmp(a, b) == 0); +} + +static int restore(const char *file) +{ + char *my_file; + struct stat my_sb; + int i, j, ret; + char *context = NULL; + char *newcon = NULL; + bool user_only_changed = 0; + int retval = 0; + + my_file = bb_simplify_path(file); + + i = match(my_file, &my_sb, &newcon); + + if (i < 0) /* No matching specification. */ + goto out; + + if (FLAG_p_progress) { + count++; + if (count % 0x400 == 0) { /* every 1024 times */ + count = (count % (80*0x400)); + if (count == 0) + bb_putchar('\n'); + bb_putchar('*'); + fflush(stdout); + } + } + + /* + * Try to add an association between this inode and + * this specification. If there is already an association + * for this inode and it conflicts with this specification, + * then use the last matching specification. + */ + if (add_assoc) { + j = matchpathcon_filespec_add(my_sb.st_ino, i, my_file); + if (j < 0) + goto err; + + if (j != i) { + /* There was already an association and it took precedence. */ + goto out; + } + } + + if (FLAG_d_debug) + printf("%s: %s matched by %s\n", applet_name, my_file, newcon); + + /* Get the current context of the file. */ + ret = lgetfilecon_raw(my_file, &context); + if (ret < 0) { + if (errno == ENODATA) { + context = NULL; /* paranoia */ + } else { + bb_perror_msg("lgetfilecon_raw on %s", my_file); + goto err; + } + user_only_changed = 0; + } else + user_only_changed = only_changed_user(context, newcon); + + /* + * Do not relabel the file if the matching specification is + * <> or the file is already labeled according to the + * specification. + */ + if ((strcmp(newcon, "<>") == 0) + || (context && (strcmp(context, newcon) == 0) && !FLAG_F_force)) { + goto out; + } + + if (!FLAG_F_force && context && (is_context_customizable(context) > 0)) { + if (verbose > 1) { + bb_error_msg("skipping %s. %s is customizable_types", + my_file, context); + } + goto out; + } + + if (verbose) { + /* If we're just doing "-v", trim out any relabels where + * the user has changed but the role and type are the + * same. For "-vv", emit everything. */ + if (verbose > 1 || !user_only_changed) { + bb_info_msg("%s: reset %s context %s->%s", + applet_name, my_file, context ?: "", newcon); + } + } + + if (FLAG_l_take_log && !user_only_changed) { + if (context) + bb_info_msg("relabeling %s from %s to %s", my_file, context, newcon); + else + bb_info_msg("labeling %s to %s", my_file, newcon); + } + + if (outfile && !user_only_changed) + fprintf(outfile, "%s\n", my_file); + + /* + * Do not relabel the file if -n was used. + */ + if (FLAG_n_dry_run || user_only_changed) + goto out; + + /* + * Relabel the file to the specified context. + */ + ret = lsetfilecon(my_file, newcon); + if (ret) { + bb_perror_msg("lsetfileconon(%s,%s)", my_file, newcon); + goto err; + } + + out: + freecon(context); + freecon(newcon); + free(my_file); + return retval; + err: + retval--; /* -1 */ + goto out; +} + +/* + * Apply the last matching specification to a file. + * This function is called by recursive_action on each file during + * the directory traversal. + */ +static int FAST_FUNC apply_spec( + const char *file, + struct stat *sb, + void *userData UNUSED_PARAM, + int depth UNUSED_PARAM) +{ + if (!follow_mounts) { + /* setfiles does not process across different mount points */ + if (sb->st_dev != dev_id) { + return SKIP; + } + } + errors |= restore(file); + if (abort_on_error && errors) + return FALSE; + return TRUE; +} + + +static int canoncon(const char *path, unsigned lineno, char **contextp) +{ + static const char err_msg[] ALIGN1 = "%s: line %u has invalid context %s"; + + char *tmpcon; + char *context = *contextp; + int invalid = 0; + +#if ENABLE_FEATURE_SETFILES_CHECK_OPTION + if (policyfile) { + if (sepol_check_context(context) >= 0) + return 0; + /* Exit immediately if we're in checking mode. */ + bb_error_msg_and_die(err_msg, path, lineno, context); + } +#endif + + if (security_canonicalize_context_raw(context, &tmpcon) < 0) { + if (errno != ENOENT) { + invalid = 1; + inc_err(); + } + } else { + free(context); + *contextp = tmpcon; + } + + if (invalid) { + bb_error_msg(err_msg, path, lineno, context); + } + + return invalid; +} + +static int process_one(char *name) +{ + struct stat sb; + int rc; + + rc = lstat(name, &sb); + if (rc < 0) { + if (FLAG_i_ignore_enoent && errno == ENOENT) + return 0; + bb_perror_msg("stat(%s)", name); + goto err; + } + dev_id = sb.st_dev; + + if (S_ISDIR(sb.st_mode) && recurse) { + if (recursive_action(name, + ACTION_RECURSE, + apply_spec, + apply_spec, + NULL, 0) != TRUE) { + bb_error_msg("error while labeling %s", name); + goto err; + } + } else { + rc = restore(name); + if (rc) + goto err; + } + + out: + if (add_assoc) { + if (FLAG_q_quiet) + set_matchpathcon_printf(&qprintf); + matchpathcon_filespec_eval(); + set_matchpathcon_printf(NULL); + matchpathcon_filespec_destroy(); + } + + return rc; + + err: + rc = -1; + goto out; +} + +int setfiles_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int setfiles_main(int argc, char **argv) +{ + struct stat sb; + int rc, i = 0; + const char *input_filename = NULL; + char *buf = NULL; + size_t buf_len; + int flags; + llist_t *exclude_dir = NULL; + char *out_filename = NULL; + + INIT_G(); + + if (applet_name[0] == 's') { /* "setfiles" */ + /* + * setfiles: + * Recursive descent, + * Does not expand paths via realpath, + * Aborts on errors during the file tree walk, + * Try to track inode associations for conflict detection, + * Does not follow mounts, + * Validates all file contexts at init time. + */ + recurse = 1; + abort_on_error = 1; + add_assoc = 1; + /* follow_mounts = 0; - already is */ + matchpathcon_flags = MATCHPATHCON_VALIDATE | MATCHPATHCON_NOTRANS; + } else { + /* + * restorecon: + * No recursive descent unless -r/-R, + * Expands paths via realpath, + * Do not abort on errors during the file tree walk, + * Do not try to track inode associations for conflict detection, + * Follows mounts, + * Does lazy validation of contexts upon use. + */ + expand_realpath = 1; + follow_mounts = 1; + matchpathcon_flags = MATCHPATHCON_NOTRANS; + /* restorecon only */ + selinux_or_die(); + } + + set_matchpathcon_flags(matchpathcon_flags); + + opt_complementary = "e::vv:v--p:p--v:v--q:q--v"; + /* Option order must match OPT_x definitions! */ + if (applet_name[0] == 'r') { /* restorecon */ + flags = getopt32(argv, "de:f:ilnpqrsvo:FWR", + &exclude_dir, &input_filename, &out_filename, &verbose); + } else { /* setfiles */ + flags = getopt32(argv, "de:f:ilnpqr:svo:FW" + USE_FEATURE_SETFILES_CHECK_OPTION("c:"), + &exclude_dir, &input_filename, &rootpath, &out_filename, + USE_FEATURE_SETFILES_CHECK_OPTION(&policyfile,) + &verbose); + } + +#if ENABLE_FEATURE_SETFILES_CHECK_OPTION + if ((applet_name[0] == 's') && (flags & OPT_c)) { + FILE *policystream; + + policystream = xfopen_for_read(policyfile); + if (sepol_set_policydb_from_file(policystream) < 0) { + bb_error_msg_and_die("sepol_set_policydb_from_file on %s", policyfile); + } + fclose(policystream); + + /* Only process the specified file_contexts file, not + any .homedirs or .local files, and do not perform + context translations. */ + set_matchpathcon_flags(MATCHPATHCON_BASEONLY | + MATCHPATHCON_NOTRANS | + MATCHPATHCON_VALIDATE); + } +#endif + + while (exclude_dir) + add_exclude(llist_pop(&exclude_dir)); + + if (flags & OPT_o) { + outfile = stdout; + if (NOT_LONE_CHAR(out_filename, '-')) { + outfile = xfopen_for_write(out_filename); + } + } + if (applet_name[0] == 'r') { /* restorecon */ + if (flags & (OPT_r | OPT_R)) + recurse = 1; + } else { /* setfiles */ + if (flags & OPT_r) + rootpathlen = strlen(rootpath); + } + if (flags & OPT_s) { + input_filename = "-"; + add_assoc = 0; + } + + if (applet_name[0] == 's') { /* setfiles */ + /* Use our own invalid context checking function so that + we can support either checking against the active policy or + checking against a binary policy file. */ + set_matchpathcon_canoncon(&canoncon); + if (argc == 1) + bb_show_usage(); + if (stat(argv[optind], &sb) < 0) { + bb_simple_perror_msg_and_die(argv[optind]); + } + if (!S_ISREG(sb.st_mode)) { + bb_error_msg_and_die("spec file %s is not a regular file", argv[optind]); + } + /* Load the file contexts configuration and check it. */ + rc = matchpathcon_init(argv[optind]); + if (rc < 0) { + bb_simple_perror_msg_and_die(argv[optind]); + } + + optind++; + + if (nerr) + exit(EXIT_FAILURE); + } + + if (input_filename) { + ssize_t len; + FILE *f = stdin; + + if (NOT_LONE_CHAR(input_filename, '-')) + f = xfopen_for_read(input_filename); + while ((len = getline(&buf, &buf_len, f)) > 0) { + buf[len - 1] = '\0'; + errors |= process_one(buf); + } + if (ENABLE_FEATURE_CLEAN_UP) + fclose_if_not_stdin(f); + } else { + if (optind >= argc) + bb_show_usage(); + for (i = optind; i < argc; i++) { + errors |= process_one(argv[i]); + } + } + + if (FLAG_W_warn_no_match) + matchpathcon_checkmatches(argv[0]); + + if (ENABLE_FEATURE_CLEAN_UP && outfile) + fclose(outfile); + + return errors; +} diff --git a/selinux/setsebool.c b/selinux/setsebool.c new file mode 100644 index 0000000..83e70e2 --- /dev/null +++ b/selinux/setsebool.c @@ -0,0 +1,34 @@ +/* + * setsebool + * Simple setsebool + * NOTE: -P option requires libsemanage, so this feature is + * omitted in this version + * Yuichi Nakamura + */ + +#include "libbb.h" + +int setsebool_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; +int setsebool_main(int argc, char **argv) +{ + char *p; + int value; + + if (argc != 3) + bb_show_usage(); + + p = argv[2]; + + if (LONE_CHAR(p, '1') || strcasecmp(p, "true") == 0 || strcasecmp(p, "on") == 0) { + value = 1; + } else if (LONE_CHAR(p, '0') || strcasecmp(p, "false") == 0 || strcasecmp(p, "off") == 0) { + value = 0; + } else { + bb_show_usage(); + } + + if (security_set_boolean(argv[1], value) < 0) + bb_error_msg_and_die("can't set boolean"); + + return 0; +} -- cgit v1.2.3