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, 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