Home | History | Annotate | Download | only in src
      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