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 tarball for details.
   9 */
  10#include <getopt.h>
  11#include <selinux/context.h>
  12
  13#include "libbb.h"
  14
  15#define OPT_RECURSIVE           (1<<0)  /* 'R' */
  16#define OPT_CHANHES             (1<<1)  /* 'c' */
  17#define OPT_NODEREFERENCE       (1<<2)  /* 'h' */
  18#define OPT_QUIET               (1<<3)  /* 'f' */
  19#define OPT_USER                (1<<4)  /* 'u' */
  20#define OPT_ROLE                (1<<5)  /* 'r' */
  21#define OPT_TYPE                (1<<6)  /* 't' */
  22#define OPT_RANGE               (1<<7)  /* 'l' */
  23#define OPT_VERBOSE             (1<<8)  /* 'v' */
  24#define OPT_REFERENCE           ((1<<9) * ENABLE_FEATURE_CHCON_LONG_OPTIONS)
  25#define OPT_COMPONENT_SPECIFIED (OPT_USER | OPT_ROLE | OPT_TYPE | OPT_RANGE)
  26
  27static char *user = NULL;
  28static char *role = NULL;
  29static char *type = NULL;
  30static char *range = NULL;
  31static char *specified_context = NULL;
  32
  33static int FAST_FUNC change_filedir_context(
  34                const char *fname,
  35                struct stat *stbuf UNUSED_PARAM,
  36                void *userData UNUSED_PARAM,
  37                int depth UNUSED_PARAM)
  38{
  39        context_t context = NULL;
  40        security_context_t file_context = NULL;
  41        security_context_t context_string;
  42        int rc = FALSE;
  43        int status = 0;
  44
  45        if (option_mask32 & OPT_NODEREFERENCE) {
  46                status = lgetfilecon(fname, &file_context);
  47        } else {
  48                status = getfilecon(fname, &file_context);
  49        }
  50        if (status < 0 && errno != ENODATA) {
  51                if ((option_mask32 & OPT_QUIET) == 0)
  52                        bb_error_msg("cannot obtain security context: %s", fname);
  53                goto skip;
  54        }
  55
  56        if (file_context == NULL && specified_context == NULL) {
  57                bb_error_msg("cannot apply partial context to unlabeled file %s", fname);
  58                goto skip;
  59        }
  60
  61        if (specified_context == NULL) {
  62                context = set_security_context_component(file_context,
  63                                                         user, role, type, range);
  64                if (!context) {
  65                        bb_error_msg("cannot compute security context from %s", file_context);
  66                        goto skip;
  67                }
  68        } else {
  69                context = context_new(specified_context);
  70                if (!context) {
  71                        bb_error_msg("invalid context: %s", specified_context);
  72                        goto skip;
  73                }
  74        }
  75
  76        context_string = context_str(context);
  77        if (!context_string) {
  78                bb_error_msg("cannot obtain security context in text expression");
  79                goto skip;
  80        }
  81
  82        if (file_context == NULL || strcmp(context_string, file_context) != 0) {
  83                int fail;
  84
  85                if (option_mask32 & OPT_NODEREFERENCE) {
  86                        fail = lsetfilecon(fname, context_string);
  87                } else {
  88                        fail = setfilecon(fname, context_string);
  89                }
  90                if ((option_mask32 & OPT_VERBOSE) || ((option_mask32 & OPT_CHANHES) && !fail)) {
  91                        printf(!fail
  92                               ? "context of %s changed to %s\n"
  93                               : "failed to change context of %s to %s\n",
  94                               fname, context_string);
  95                }
  96                if (!fail) {
  97                        rc = TRUE;
  98                } else if ((option_mask32 & OPT_QUIET) == 0) {
  99                        bb_error_msg("failed to change context of %s to %s",
 100                                     fname, context_string);
 101                }
 102        } else if (option_mask32 & OPT_VERBOSE) {
 103                printf("context of %s retained as %s\n", fname, context_string);
 104                rc = TRUE;
 105        }
 106skip:
 107        context_free(context);
 108        freecon(file_context);
 109
 110        return rc;
 111}
 112
 113#if ENABLE_FEATURE_CHCON_LONG_OPTIONS
 114static const char chcon_longopts[] ALIGN1 =
 115        "recursive\0"      No_argument       "R"
 116        "changes\0"        No_argument       "c"
 117        "no-dereference\0" No_argument       "h"
 118        "silent\0"         No_argument       "f"
 119        "quiet\0"          No_argument       "f"
 120        "user\0"           Required_argument "u"
 121        "role\0"           Required_argument "r"
 122        "type\0"           Required_argument "t"
 123        "range\0"          Required_argument "l"
 124        "verbose\0"        No_argument       "v"
 125        "reference\0"      Required_argument "\xff" /* no short option */
 126        ;
 127#endif
 128
 129int chcon_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
 130int chcon_main(int argc UNUSED_PARAM, char **argv)
 131{
 132        char *reference_file;
 133        char *fname;
 134        int i, errors = 0;
 135
 136#if ENABLE_FEATURE_CHCON_LONG_OPTIONS
 137        applet_long_options = chcon_longopts;
 138#endif
 139        opt_complementary = "-1"  /* at least 1 param */
 140                ":?"  /* error if exclusivity constraints are violated */
 141#if ENABLE_FEATURE_CHCON_LONG_OPTIONS
 142                ":\xff--urtl:u--\xff:r--\xff:t--\xff:l--\xff"
 143#endif
 144                ":f--v:v--f";  /* 'verbose' and 'quiet' are exclusive */
 145        getopt32(argv, "Rchfu:r:t:l:v",
 146                &user, &role, &type, &range, &reference_file);
 147        argv += optind;
 148
 149#if ENABLE_FEATURE_CHCON_LONG_OPTIONS
 150        if (option_mask32 & OPT_REFERENCE) {
 151                /* FIXME: lgetfilecon() should be used when '-h' is specified.
 152                   But current implementation follows the original one. */
 153                if (getfilecon(reference_file, &specified_context) < 0)
 154                        bb_perror_msg_and_die("getfilecon('%s') failed", reference_file);
 155        } else
 156#endif
 157        if ((option_mask32 & OPT_COMPONENT_SPECIFIED) == 0) {
 158                specified_context = *argv++;
 159                /* specified_context is never NULL -
 160                 * "-1" in opt_complementary prevents this. */
 161                if (!argv[0])
 162                        bb_error_msg_and_die("too few arguments");
 163        }
 164
 165        for (i = 0; (fname = argv[i]) != NULL; i++) {
 166                int fname_len = strlen(fname);
 167                while (fname_len > 1 && fname[fname_len - 1] == '/')
 168                        fname_len--;
 169                fname[fname_len] = '\0';
 170
 171                if (recursive_action(fname,
 172                                     1<<option_mask32 & OPT_RECURSIVE,
 173                                     change_filedir_context,
 174                                     change_filedir_context,
 175                                     NULL, 0) != TRUE)
 176                        errors = 1;
 177        }
 178        return errors;
 179}
 180