1 /* 2 * Media contexts backend for labeling system 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 "callbacks.h" 15 #include "label_internal.h" 16 17 /* 18 * Internals 19 */ 20 21 /* A context specification. */ 22 typedef 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 28 struct saved_data { 29 unsigned int nspec; 30 spec_t *spec_arr; 31 }; 32 33 static 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 70 static 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, "r")) == NULL) 94 return -1; 95 __fsetlocking(fp, FSETLOCKING_BYCALLER); 96 97 if (fstat(fileno(fp), &sb) < 0) 98 return -1; 99 if (!S_ISREG(sb.st_mode)) { 100 errno = EINVAL; 101 return -1; 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 lineno = 0; 123 124 if (pass == 0) { 125 if (data->nspec == 0) { 126 status = 0; 127 goto finish; 128 } 129 data->spec_arr = malloc(sizeof(spec_t)*data->nspec); 130 if (data->spec_arr == NULL) 131 goto finish; 132 memset(data->spec_arr, 0, sizeof(spec_t)*data->nspec); 133 maxnspec = data->nspec; 134 rewind(fp); 135 } 136 } 137 free(line_buf); 138 139 status = digest_add_specfile(rec->digest, fp, NULL, sb.st_size, path); 140 if (status) 141 goto finish; 142 143 digest_gen_hash(rec->digest); 144 145 finish: 146 fclose(fp); 147 return status; 148 } 149 150 /* 151 * Backend interface routines 152 */ 153 static void close(struct selabel_handle *rec) 154 { 155 struct saved_data *data = (struct saved_data *)rec->data; 156 struct spec *spec, *spec_arr = data->spec_arr; 157 unsigned int i; 158 159 for (i = 0; i < data->nspec; i++) { 160 spec = &spec_arr[i]; 161 free(spec->key); 162 free(spec->lr.ctx_raw); 163 free(spec->lr.ctx_trans); 164 } 165 166 if (spec_arr) 167 free(spec_arr); 168 169 free(data); 170 } 171 172 static struct selabel_lookup_rec *lookup(struct selabel_handle *rec, 173 const char *key, 174 int type __attribute__((unused))) 175 { 176 struct saved_data *data = (struct saved_data *)rec->data; 177 spec_t *spec_arr = data->spec_arr; 178 unsigned int i; 179 180 for (i = 0; i < data->nspec; i++) { 181 if (!strncmp(spec_arr[i].key, key, strlen(key) + 1)) 182 break; 183 if (!strncmp(spec_arr[i].key, "*", 2)) 184 break; 185 } 186 187 if (i >= data->nspec) { 188 /* No matching specification. */ 189 errno = ENOENT; 190 return NULL; 191 } 192 193 spec_arr[i].matches++; 194 return &spec_arr[i].lr; 195 } 196 197 static void stats(struct selabel_handle *rec) 198 { 199 struct saved_data *data = (struct saved_data *)rec->data; 200 unsigned int i, total = 0; 201 202 for (i = 0; i < data->nspec; i++) 203 total += data->spec_arr[i].matches; 204 205 selinux_log(SELINUX_INFO, "%u entries, %u matches made\n", 206 data->nspec, total); 207 } 208 209 int selabel_media_init(struct selabel_handle *rec, 210 const struct selinux_opt *opts, 211 unsigned nopts) 212 { 213 struct saved_data *data; 214 215 data = (struct saved_data *)malloc(sizeof(*data)); 216 if (!data) 217 return -1; 218 memset(data, 0, sizeof(*data)); 219 220 rec->data = data; 221 rec->func_close = &close; 222 rec->func_lookup = &lookup; 223 rec->func_stats = &stats; 224 225 return init(rec, opts, nopts); 226 } 227