busybox/selinux/chcon.c
<<
>>
Prefs
   1/*
   2 * chcon -- change security context, based on coreutils-5.97-13
   3 *
   4 * Port to busybox: KaiGai Kohei <kaigai@kaigai.gr.jp>
   5 *
   6 * Copyright (C) 2006 - 2007 KaiGai Kohei <kaigai@kaigai.gr.jp>
   7 *
   8 * Licensed under GPLv2, see file LICENSE in this source tree.
   9 */
  10//config:config CHCON
  11//config:       bool "chcon (8.9 kb)"
  12//config:       default n
  13//config:       depends on SELINUX
  14//config:       help
  15//config:       Enable support to change the security context of file.
  16
  17//applet:IF_CHCON(APPLET(chcon, BB_DIR_USR_BIN, BB_SUID_DROP))
  18
  19//kbuild:lib-$(CONFIG_CHCON) += chcon.o
  20
  21//usage:#define chcon_trivial_usage
  22//usage:       "[-chfRv] CONTEXT FILE..."
  23//usage:       "\n      chcon [-chfRv] [-u USER] [-r ROLE] [-l RANGE] [-t TYPE] FILE..."
  24//usage:        IF_LONG_OPTS(
  25//usage:       "\n      chcon [-chfRv] --reference=RFILE FILE..."
  26//usage:        )
  27//usage:
  28//usage:#define chcon_full_usage "\n\n"
  29//usage:       "Change the security context of FILEs to CONTEXT\n"
  30//usage:     "\n        -v      Verbose"
  31//usage:     "\n        -c      Report changes made"
  32//usage:     "\n        -h      Affect symlinks instead of their targets"
  33//usage:     "\n        -f      Suppress most error messages"
  34//usage:        IF_LONG_OPTS(
  35//usage:     "\n        --reference RFILE Use RFILE's group instead of using a CONTEXT value"
  36//usage:        )
  37//usage:     "\n        -u USER Set user/role/type/range in the target security context"
  38//usage:     "\n        -r ROLE"
  39//usage:     "\n        -t TYPE"
  40//usage:     "\n        -l RANGE"
  41//usage:     "\n        -R      Recurse"
  42
  43#include <selinux/context.h>
  44
  45#include "libbb.h"
  46
  47#define OPT_RECURSIVE           (1<<0)  /* 'R' */
  48#define OPT_CHANHES             (1<<1)  /* 'c' */
  49#define OPT_NODEREFERENCE       (1<<2)  /* 'h' */
  50#define OPT_QUIET               (1<<3)  /* 'f' */
  51#define OPT_USER                (1<<4)  /* 'u' */
  52#define OPT_ROLE                (1<<5)  /* 'r' */
  53#define OPT_TYPE                (1<<6)  /* 't' */
  54#define OPT_RANGE               (1<<7)  /* 'l' */
  55#define OPT_VERBOSE             (1<<8)  /* 'v' */
  56#define OPT_REFERENCE           ((1<<9) * ENABLE_LONG_OPTS)
  57#define OPT_COMPONENT_SPECIFIED (OPT_USER | OPT_ROLE | OPT_TYPE | OPT_RANGE)
  58
  59static char *user = NULL;
  60static char *role = NULL;
  61static char *type = NULL;
  62static char *range = NULL;
  63static char *specified_context = NULL;
  64
  65static int FAST_FUNC change_filedir_context(struct recursive_state *state UNUSED_PARAM,
  66                const char *fname,
  67                struct stat *stbuf UNUSED_PARAM)
  68{
  69        context_t context = NULL;
  70        security_context_t file_context = NULL;
  71        security_context_t context_string;
  72        int rc = FALSE;
  73        int status = 0;
  74
  75        if (option_mask32 & OPT_NODEREFERENCE) {
  76                status = lgetfilecon(fname, &file_context);
  77        } else {
  78                status = getfilecon(fname, &file_context);
  79        }
  80        if (status < 0 && errno != ENODATA) {
  81                if ((option_mask32 & OPT_QUIET) == 0)
  82                        bb_error_msg("can't obtain security context: %s", fname);
  83                goto skip;
  84        }
  85
  86        if (file_context == NULL && specified_context == NULL) {
  87                bb_error_msg("can't apply partial context to unlabeled file %s", fname);
  88                goto skip;
  89        }
  90
  91        if (specified_context == NULL) {
  92                context = set_security_context_component(file_context,
  93                                                        user, role, type, range);
  94                if (!context) {
  95                        bb_error_msg("can't compute security context from %s", file_context);
  96                        goto skip;
  97                }
  98        } else {
  99                context = context_new(specified_context);
 100                if (!context) {
 101                        bb_error_msg("invalid context: %s", specified_context);
 102                        goto skip;
 103                }
 104        }
 105
 106        context_string = context_str(context);
 107        if (!context_string) {
 108                bb_simple_error_msg("can't obtain security context in text expression");
 109                goto skip;
 110        }
 111
 112        if (file_context == NULL || strcmp(context_string, file_context) != 0) {
 113                int fail;
 114
 115                if (option_mask32 & OPT_NODEREFERENCE) {
 116                        fail = lsetfilecon(fname, context_string);
 117                } else {
 118                        fail = setfilecon(fname, context_string);
 119                }
 120                if ((option_mask32 & OPT_VERBOSE) || ((option_mask32 & OPT_CHANHES) && !fail)) {
 121                        printf(!fail
 122                                ? "context of %s changed to %s\n"
 123                                : "can't change context of %s to %s\n",
 124                                fname, context_string);
 125                }
 126                if (!fail) {
 127                        rc = TRUE;
 128                } else if ((option_mask32 & OPT_QUIET) == 0) {
 129                        bb_error_msg("can't change context of %s to %s",
 130                                        fname, context_string);
 131                }
 132        } else {
 133                if (option_mask32 & OPT_VERBOSE) {
 134                        printf("context of %s retained as %s\n", fname, context_string);
 135                }
 136                rc = TRUE;
 137        }
 138skip:
 139        context_free(context);
 140        freecon(file_context);
 141
 142        return rc;
 143}
 144
 145#if ENABLE_LONG_OPTS
 146static const char chcon_longopts[] ALIGN1 =
 147        "recursive\0"      No_argument       "R"
 148        "changes\0"        No_argument       "c"
 149        "no-dereference\0" No_argument       "h"
 150        "silent\0"         No_argument       "f"
 151        "quiet\0"          No_argument       "f"
 152        "user\0"           Required_argument "u"
 153        "role\0"           Required_argument "r"
 154        "type\0"           Required_argument "t"
 155        "range\0"          Required_argument "l"
 156        "verbose\0"        No_argument       "v"
 157        "reference\0"      Required_argument "\xff" /* no short option */
 158        ;
 159#endif
 160
 161int chcon_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 162int chcon_main(int argc UNUSED_PARAM, char **argv)
 163{
 164        char *reference_file;
 165        char *fname;
 166        int i, errors = 0;
 167
 168        getopt32long(argv, "^"
 169                "Rchfu:r:t:l:v"
 170                "\0"
 171                "-1" /* at least 1 arg */
 172                ":?" /* error if exclusivity constraints are violated */
 173#if ENABLE_LONG_OPTS
 174                ":\xff--urtl:u--\xff:r--\xff:t--\xff:l--\xff"
 175#endif
 176                ":f--v:v--f"  /* 'verbose' and 'quiet' are exclusive */
 177                , chcon_longopts,
 178                &user, &role, &type, &range, &reference_file
 179        );
 180        argv += optind;
 181
 182#if ENABLE_LONG_OPTS
 183        if (option_mask32 & OPT_REFERENCE) {
 184                /* FIXME: lgetfilecon() should be used when '-h' is specified.
 185                 * But current implementation follows the original one. */
 186                if (getfilecon(reference_file, &specified_context) < 0)
 187                        bb_perror_msg_and_die("getfilecon('%s') failed", reference_file);
 188        } else
 189#endif
 190        if ((option_mask32 & OPT_COMPONENT_SPECIFIED) == 0) {
 191                specified_context = *argv++;
 192                /* specified_context is never NULL -
 193                 * "-1" in opt_complementary prevents this. */
 194                if (!argv[0])
 195                        bb_simple_error_msg_and_die("too few arguments");
 196        }
 197
 198        for (i = 0; (fname = argv[i]) != NULL; i++) {
 199                int fname_len = strlen(fname);
 200                while (fname_len > 1 && fname[fname_len - 1] == '/')
 201                        fname_len--;
 202                fname[fname_len] = '\0';
 203
 204                if (recursive_action(fname,
 205                                        ((option_mask32 & OPT_RECURSIVE) ? ACTION_RECURSE : 0),
 206                                        change_filedir_context,
 207                                        change_filedir_context,
 208                                        NULL) != TRUE)
 209                        errors = 1;
 210        }
 211        return errors;
 212}
 213