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