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