Blame src/label_media.c

Packit Service 10cefc
/*
Packit Service 10cefc
 * Media contexts backend for labeling system
Packit Service 10cefc
 *
Packit Service 10cefc
 * Author : Eamon Walsh <ewalsh@tycho.nsa.gov>
Packit Service 10cefc
 */
Packit Service 10cefc
Packit Service 10cefc
#include <sys/stat.h>
Packit Service 10cefc
#include <string.h>
Packit Service 10cefc
#include <stdio.h>
Packit Service 10cefc
#include <stdio_ext.h>
Packit Service 10cefc
#include <ctype.h>
Packit Service 10cefc
#include <errno.h>
Packit Service 10cefc
#include <limits.h>
Packit Service 10cefc
#include "callbacks.h"
Packit Service 10cefc
#include "label_internal.h"
Packit Service 10cefc
Packit Service 10cefc
/*
Packit Service 10cefc
 * Internals
Packit Service 10cefc
 */
Packit Service 10cefc
Packit Service 10cefc
/* A context specification. */
Packit Service 10cefc
typedef struct spec {
Packit Service 10cefc
	struct selabel_lookup_rec lr;	/* holds contexts for lookup result */
Packit Service 10cefc
	char *key;		/* key string */
Packit Service 10cefc
	int matches;		/* number of matches made during operation */
Packit Service 10cefc
} spec_t;
Packit Service 10cefc
Packit Service 10cefc
struct saved_data {
Packit Service 10cefc
	unsigned int nspec;
Packit Service 10cefc
	spec_t *spec_arr;
Packit Service 10cefc
};
Packit Service 10cefc
Packit Service 10cefc
static int process_line(const char *path, char *line_buf, int pass,
Packit Service 10cefc
			unsigned lineno, struct selabel_handle *rec)
Packit Service 10cefc
{
Packit Service 10cefc
	struct saved_data *data = (struct saved_data *)rec->data;
Packit Service 10cefc
	int items;
Packit Service 10cefc
	char *buf_p;
Packit Service 10cefc
	char *key, *context;
Packit Service 10cefc
Packit Service 10cefc
	buf_p = line_buf;
Packit Service 10cefc
	while (isspace(*buf_p))
Packit Service 10cefc
		buf_p++;
Packit Service 10cefc
	/* Skip comment lines and empty lines. */
Packit Service 10cefc
	if (*buf_p == '#' || *buf_p == 0)
Packit Service 10cefc
		return 0;
Packit Service 10cefc
	items = sscanf(line_buf, "%ms %ms ", &key, &context);
Packit Service 10cefc
	if (items < 2) {
Packit Service 10cefc
		selinux_log(SELINUX_WARNING,
Packit Service 10cefc
			  "%s:  line %u is missing fields, skipping\n", path,
Packit Service 10cefc
			  lineno);
Packit Service 10cefc
		if (items == 1)
Packit Service 10cefc
			free(key);
Packit Service 10cefc
		return 0;
Packit Service 10cefc
	}
Packit Service 10cefc
Packit Service 10cefc
	if (pass == 1) {
Packit Service 10cefc
		data->spec_arr[data->nspec].key = key;
Packit Service 10cefc
		data->spec_arr[data->nspec].lr.ctx_raw = context;
Packit Service 10cefc
	}
Packit Service 10cefc
Packit Service 10cefc
	data->nspec++;
Packit Service 10cefc
	if (pass == 0) {
Packit Service 10cefc
		free(key);
Packit Service 10cefc
		free(context);
Packit Service 10cefc
	}
Packit Service 10cefc
	return 0;
Packit Service 10cefc
}
Packit Service 10cefc
Packit Service 10cefc
static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
Packit Service 10cefc
		unsigned n)
Packit Service 10cefc
{
Packit Service 10cefc
	FILE *fp;
Packit Service 10cefc
	struct saved_data *data = (struct saved_data *)rec->data;
Packit Service 10cefc
	const char *path = NULL;
Packit Service 10cefc
	char *line_buf = NULL;
Packit Service 10cefc
	size_t line_len = 0;
Packit Service 10cefc
	int status = -1;
Packit Service 10cefc
	unsigned int lineno, pass, maxnspec;
Packit Service 10cefc
	struct stat sb;
Packit Service 10cefc
Packit Service 10cefc
	/* Process arguments */
Packit Service 10cefc
	while (n--)
Packit Service 10cefc
		switch(opts[n].type) {
Packit Service 10cefc
		case SELABEL_OPT_PATH:
Packit Service 10cefc
			path = opts[n].value;
Packit Service 10cefc
			break;
Packit Service 10cefc
		}
Packit Service 10cefc
Packit Service 10cefc
	/* Open the specification file. */
Packit Service 10cefc
	if (!path)
Packit Service 10cefc
		path = selinux_media_context_path();
Packit Service 10cefc
	if ((fp = fopen(path, "re")) == NULL)
Packit Service 10cefc
		return -1;
Packit Service 10cefc
	__fsetlocking(fp, FSETLOCKING_BYCALLER);
Packit Service 10cefc
Packit Service 10cefc
	if (fstat(fileno(fp), &sb) < 0)
Packit Service 10cefc
		return -1;
Packit Service 10cefc
	if (!S_ISREG(sb.st_mode)) {
Packit Service 10cefc
		errno = EINVAL;
Packit Service 10cefc
		return -1;
Packit Service 10cefc
	}
Packit Service 10cefc
	rec->spec_file = strdup(path);
Packit Service 10cefc
Packit Service 10cefc
	/* 
Packit Service 10cefc
	 * Perform two passes over the specification file.
Packit Service 10cefc
	 * The first pass counts the number of specifications and
Packit Service 10cefc
	 * performs simple validation of the input.  At the end
Packit Service 10cefc
	 * of the first pass, the spec array is allocated.
Packit Service 10cefc
	 * The second pass performs detailed validation of the input
Packit Service 10cefc
	 * and fills in the spec array.
Packit Service 10cefc
	 */
Packit Service 10cefc
	maxnspec = UINT_MAX / sizeof(spec_t);
Packit Service 10cefc
	for (pass = 0; pass < 2; pass++) {
Packit Service 10cefc
		lineno = 0;
Packit Service 10cefc
		data->nspec = 0;
Packit Service 10cefc
		while (getline(&line_buf, &line_len, fp) > 0 &&
Packit Service 10cefc
		       data->nspec < maxnspec) {
Packit Service 10cefc
			if (process_line(path, line_buf, pass, ++lineno, rec))
Packit Service 10cefc
				goto finish;
Packit Service 10cefc
		}
Packit Service 10cefc
		lineno = 0;
Packit Service 10cefc
Packit Service 10cefc
		if (pass == 0) {
Packit Service 10cefc
			if (data->nspec == 0) {
Packit Service 10cefc
				status = 0;
Packit Service 10cefc
				goto finish;
Packit Service 10cefc
			}
Packit Service 10cefc
			data->spec_arr = malloc(sizeof(spec_t)*data->nspec);
Packit Service 10cefc
			if (data->spec_arr == NULL)
Packit Service 10cefc
				goto finish;
Packit Service 10cefc
			memset(data->spec_arr, 0, sizeof(spec_t)*data->nspec);
Packit Service 10cefc
			maxnspec = data->nspec;
Packit Service 10cefc
			rewind(fp);
Packit Service 10cefc
		}
Packit Service 10cefc
	}
Packit Service 10cefc
	free(line_buf);
Packit Service 10cefc
Packit Service 10cefc
	status = digest_add_specfile(rec->digest, fp, NULL, sb.st_size, path);
Packit Service 10cefc
	if (status)
Packit Service 10cefc
		goto finish;
Packit Service 10cefc
Packit Service 10cefc
	digest_gen_hash(rec->digest);
Packit Service 10cefc
Packit Service 10cefc
finish:
Packit Service 10cefc
	fclose(fp);
Packit Service 10cefc
	return status;
Packit Service 10cefc
}
Packit Service 10cefc
Packit Service 10cefc
/*
Packit Service 10cefc
 * Backend interface routines
Packit Service 10cefc
 */
Packit Service 10cefc
static void close(struct selabel_handle *rec)
Packit Service 10cefc
{
Packit Service 10cefc
	struct saved_data *data = (struct saved_data *)rec->data;
Packit Service 10cefc
	struct spec *spec, *spec_arr = data->spec_arr;
Packit Service 10cefc
	unsigned int i;
Packit Service 10cefc
Packit Service 10cefc
	for (i = 0; i < data->nspec; i++) {
Packit Service 10cefc
		spec = &spec_arr[i];
Packit Service 10cefc
		free(spec->key);
Packit Service 10cefc
		free(spec->lr.ctx_raw);
Packit Service 10cefc
		free(spec->lr.ctx_trans);
Packit Service 10cefc
	}
Packit Service 10cefc
Packit Service 10cefc
	if (spec_arr)
Packit Service 10cefc
	    free(spec_arr);
Packit Service 10cefc
Packit Service 10cefc
	free(data);
Packit Service 10cefc
}
Packit Service 10cefc
Packit Service 10cefc
static struct selabel_lookup_rec *lookup(struct selabel_handle *rec,
Packit Service 10cefc
					 const char *key,
Packit Service 10cefc
					 int type __attribute__((unused)))
Packit Service 10cefc
{
Packit Service 10cefc
	struct saved_data *data = (struct saved_data *)rec->data;
Packit Service 10cefc
	spec_t *spec_arr = data->spec_arr;
Packit Service 10cefc
	unsigned int i;
Packit Service 10cefc
Packit Service 10cefc
	for (i = 0; i < data->nspec; i++) {
Packit Service 10cefc
		if (!strncmp(spec_arr[i].key, key, strlen(key) + 1))
Packit Service 10cefc
			break;
Packit Service 10cefc
		if (!strncmp(spec_arr[i].key, "*", 2))
Packit Service 10cefc
			break;
Packit Service 10cefc
	}
Packit Service 10cefc
Packit Service 10cefc
	if (i >= data->nspec) {
Packit Service 10cefc
		/* No matching specification. */
Packit Service 10cefc
		errno = ENOENT;
Packit Service 10cefc
		return NULL;
Packit Service 10cefc
	}
Packit Service 10cefc
Packit Service 10cefc
	spec_arr[i].matches++;
Packit Service 10cefc
	return &spec_arr[i].lr;
Packit Service 10cefc
}
Packit Service 10cefc
Packit Service 10cefc
static void stats(struct selabel_handle *rec)
Packit Service 10cefc
{
Packit Service 10cefc
	struct saved_data *data = (struct saved_data *)rec->data;
Packit Service 10cefc
	unsigned int i, total = 0;
Packit Service 10cefc
Packit Service 10cefc
	for (i = 0; i < data->nspec; i++)
Packit Service 10cefc
		total += data->spec_arr[i].matches;
Packit Service 10cefc
Packit Service 10cefc
	selinux_log(SELINUX_INFO, "%u entries, %u matches made\n",
Packit Service 10cefc
		  data->nspec, total);
Packit Service 10cefc
}
Packit Service 10cefc
Packit Service 10cefc
int selabel_media_init(struct selabel_handle *rec,
Packit Service 10cefc
				    const struct selinux_opt *opts,
Packit Service 10cefc
				    unsigned nopts)
Packit Service 10cefc
{
Packit Service 10cefc
	struct saved_data *data;
Packit Service 10cefc
Packit Service 10cefc
	data = (struct saved_data *)malloc(sizeof(*data));
Packit Service 10cefc
	if (!data)
Packit Service 10cefc
		return -1;
Packit Service 10cefc
	memset(data, 0, sizeof(*data));
Packit Service 10cefc
Packit Service 10cefc
	rec->data = data;
Packit Service 10cefc
	rec->func_close = &close;
Packit Service 10cefc
	rec->func_lookup = &lookup;
Packit Service 10cefc
	rec->func_stats = &stat;;
Packit Service 10cefc
Packit Service 10cefc
	return init(rec, opts, nopts);
Packit Service 10cefc
}