1 /* 2 * Media contexts backend for X contexts 3 * 4 * Author : Eamon Walsh <ewalsh (at) tycho.nsa.gov> 5 */ 6 7 #include <sys/stat.h> 8 #include <string.h> 9 #include <stdio.h> 10 #include <stdio_ext.h> 11 #include <ctype.h> 12 #include <errno.h> 13 #include <limits.h> 14 #include <fnmatch.h> 15 #include "callbacks.h" 16 #include "label_internal.h" 17 18 /* 19 * Internals 20 */ 21 22 /* A context specification. */ 23 typedef struct spec { 24 struct selabel_lookup_rec lr; /* holds contexts for lookup result */ 25 char *key; /* key string */ 26 int type; /* type of record (prop, ext, client) */ 27 int matches; /* number of matches made during operation */ 28 } spec_t; 29 30 struct saved_data { 31 unsigned int nspec; 32 spec_t *spec_arr; 33 }; 34 35 static int process_line(const char *path, char *line_buf, int pass, 36 unsigned lineno, struct selabel_handle *rec) 37 { 38 struct saved_data *data = (struct saved_data *)rec->data; 39 int items; 40 char *buf_p; 41 char *type, *key, *context; 42 43 buf_p = line_buf; 44 while (isspace(*buf_p)) 45 buf_p++; 46 /* Skip comment lines and empty lines. */ 47 if (*buf_p == '#' || *buf_p == 0) 48 return 0; 49 items = sscanf(line_buf, "%ms %ms %ms ", &type, &key, &context); 50 if (items < 3) { 51 selinux_log(SELINUX_WARNING, 52 "%s: line %u is missing fields, skipping\n", path, 53 lineno); 54 if (items > 0) 55 free(type); 56 if (items > 1) 57 free(key); 58 return 0; 59 } 60 61 if (pass == 1) { 62 /* Convert the type string to a mode format */ 63 if (!strcmp(type, "property")) 64 data->spec_arr[data->nspec].type = SELABEL_X_PROP; 65 else if (!strcmp(type, "extension")) 66 data->spec_arr[data->nspec].type = SELABEL_X_EXT; 67 else if (!strcmp(type, "client")) 68 data->spec_arr[data->nspec].type = SELABEL_X_CLIENT; 69 else if (!strcmp(type, "event")) 70 data->spec_arr[data->nspec].type = SELABEL_X_EVENT; 71 else if (!strcmp(type, "selection")) 72 data->spec_arr[data->nspec].type = SELABEL_X_SELN; 73 else if (!strcmp(type, "poly_property")) 74 data->spec_arr[data->nspec].type = SELABEL_X_POLYPROP; 75 else if (!strcmp(type, "poly_selection")) 76 data->spec_arr[data->nspec].type = SELABEL_X_POLYSELN; 77 else { 78 selinux_log(SELINUX_WARNING, 79 "%s: line %u has invalid object type %s\n", 80 path, lineno, type); 81 return 0; 82 } 83 data->spec_arr[data->nspec].key = key; 84 data->spec_arr[data->nspec].lr.ctx_raw = context; 85 free(type); 86 } 87 88 data->nspec++; 89 if (pass == 0) { 90 free(type); 91 free(key); 92 free(context); 93 } 94 return 0; 95 } 96 97 static int init(struct selabel_handle *rec, const struct selinux_opt *opts, 98 unsigned n) 99 { 100 FILE *fp; 101 struct saved_data *data = (struct saved_data *)rec->data; 102 const char *path = NULL; 103 char *line_buf = NULL; 104 size_t line_len = 0; 105 int status = -1; 106 unsigned int lineno, pass, maxnspec; 107 struct stat sb; 108 109 /* Process arguments */ 110 while (n--) 111 switch(opts[n].type) { 112 case SELABEL_OPT_PATH: 113 path = opts[n].value; 114 break; 115 } 116 117 /* Open the specification file. */ 118 if (!path) 119 path = selinux_x_context_path(); 120 if ((fp = fopen(path, "re")) == NULL) 121 return -1; 122 __fsetlocking(fp, FSETLOCKING_BYCALLER); 123 124 if (fstat(fileno(fp), &sb) < 0) 125 return -1; 126 if (!S_ISREG(sb.st_mode)) { 127 errno = EINVAL; 128 return -1; 129 } 130 rec->spec_file = strdup(path); 131 132 /* 133 * Perform two passes over the specification file. 134 * The first pass counts the number of specifications and 135 * performs simple validation of the input. At the end 136 * of the first pass, the spec array is allocated. 137 * The second pass performs detailed validation of the input 138 * and fills in the spec array. 139 */ 140 maxnspec = UINT_MAX / sizeof(spec_t); 141 for (pass = 0; pass < 2; pass++) { 142 lineno = 0; 143 data->nspec = 0; 144 while (getline(&line_buf, &line_len, fp) > 0 && 145 data->nspec < maxnspec) { 146 if (process_line(path, line_buf, pass, ++lineno, rec)) 147 goto finish; 148 } 149 lineno = 0; 150 151 if (pass == 0) { 152 if (data->nspec == 0) { 153 status = 0; 154 goto finish; 155 } 156 data->spec_arr = malloc(sizeof(spec_t)*data->nspec); 157 if (data->spec_arr == NULL) 158 goto finish; 159 memset(data->spec_arr, 0, sizeof(spec_t)*data->nspec); 160 maxnspec = data->nspec; 161 rewind(fp); 162 } 163 } 164 free(line_buf); 165 166 status = digest_add_specfile(rec->digest, fp, NULL, sb.st_size, path); 167 if (status) 168 goto finish; 169 170 digest_gen_hash(rec->digest); 171 172 finish: 173 fclose(fp); 174 return status; 175 } 176 177 /* 178 * Backend interface routines 179 */ 180 static void close(struct selabel_handle *rec) 181 { 182 struct saved_data *data = (struct saved_data *)rec->data; 183 struct spec *spec, *spec_arr = data->spec_arr; 184 unsigned int i; 185 186 for (i = 0; i < data->nspec; i++) { 187 spec = &spec_arr[i]; 188 free(spec->key); 189 free(spec->lr.ctx_raw); 190 free(spec->lr.ctx_trans); 191 } 192 193 if (spec_arr) 194 free(spec_arr); 195 196 free(data); 197 } 198 199 static struct selabel_lookup_rec *lookup(struct selabel_handle *rec, 200 const char *key, int type) 201 { 202 struct saved_data *data = (struct saved_data *)rec->data; 203 spec_t *spec_arr = data->spec_arr; 204 unsigned int i; 205 206 for (i = 0; i < data->nspec; i++) { 207 if (spec_arr[i].type != type) 208 continue; 209 if (!fnmatch(spec_arr[i].key, key, 0)) 210 break; 211 } 212 213 if (i >= data->nspec) { 214 /* No matching specification. */ 215 errno = ENOENT; 216 return NULL; 217 } 218 219 spec_arr[i].matches++; 220 return &spec_arr[i].lr; 221 } 222 223 static void stats(struct selabel_handle *rec) 224 { 225 struct saved_data *data = (struct saved_data *)rec->data; 226 unsigned int i, total = 0; 227 228 for (i = 0; i < data->nspec; i++) 229 total += data->spec_arr[i].matches; 230 231 selinux_log(SELINUX_INFO, "%u entries, %u matches made\n", 232 data->nspec, total); 233 } 234 235 int selabel_x_init(struct selabel_handle *rec, const struct selinux_opt *opts, 236 unsigned nopts) 237 { 238 struct saved_data *data; 239 240 data = (struct saved_data *)malloc(sizeof(*data)); 241 if (!data) 242 return -1; 243 memset(data, 0, sizeof(*data)); 244 245 rec->data = data; 246 rec->func_close = &close; 247 rec->func_lookup = &lookup; 248 rec->func_stats = &stats; 249 250 return init(rec, opts, nopts); 251 } 252