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, 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 = 0; 140 finish: 141 fclose(fp); 142 return status; 143 } 144 145 /* 146 * Backend interface routines 147 */ 148 static void close(struct selabel_handle *rec) 149 { 150 struct saved_data *data = (struct saved_data *)rec->data; 151 struct spec *spec, *spec_arr = data->spec_arr; 152 unsigned int i; 153 154 for (i = 0; i < data->nspec; i++) { 155 spec = &spec_arr[i]; 156 free(spec->key); 157 free(spec->lr.ctx_raw); 158 free(spec->lr.ctx_trans); 159 } 160 161 if (spec_arr) 162 free(spec_arr); 163 164 memset(data, 0, sizeof(*data)); 165 } 166 167 static struct selabel_lookup_rec *lookup(struct selabel_handle *rec, 168 const char *key, 169 int type __attribute__((unused))) 170 { 171 struct saved_data *data = (struct saved_data *)rec->data; 172 spec_t *spec_arr = data->spec_arr; 173 unsigned int i; 174 175 for (i = 0; i < data->nspec; i++) { 176 if (!strncmp(spec_arr[i].key, key, strlen(key) + 1)) 177 break; 178 if (!strncmp(spec_arr[i].key, "*", 2)) 179 break; 180 } 181 182 if (i >= data->nspec) { 183 /* No matching specification. */ 184 errno = ENOENT; 185 return NULL; 186 } 187 188 spec_arr[i].matches++; 189 return &spec_arr[i].lr; 190 } 191 192 static void stats(struct selabel_handle *rec) 193 { 194 struct saved_data *data = (struct saved_data *)rec->data; 195 unsigned int i, total = 0; 196 197 for (i = 0; i < data->nspec; i++) 198 total += data->spec_arr[i].matches; 199 200 selinux_log(SELINUX_INFO, "%u entries, %u matches made\n", 201 data->nspec, total); 202 } 203 204 int selabel_media_init(struct selabel_handle *rec, struct selinux_opt *opts, 205 unsigned nopts) 206 { 207 struct saved_data *data; 208 209 data = (struct saved_data *)malloc(sizeof(*data)); 210 if (!data) 211 return -1; 212 memset(data, 0, sizeof(*data)); 213 214 rec->data = data; 215 rec->func_close = &close; 216 rec->func_lookup = &lookup; 217 rec->func_stats = &stats; 218 219 return init(rec, opts, nopts); 220 } 221