Blame src/label_backends_android.c

Packit 3feee0
/*
Packit 3feee0
 * Property Service contexts backend for labeling Android
Packit 3feee0
 * property keys
Packit 3feee0
 */
Packit 3feee0
Packit 3feee0
#include <stdarg.h>
Packit 3feee0
#include <string.h>
Packit 3feee0
#include <ctype.h>
Packit 3feee0
#include <errno.h>
Packit 3feee0
#include <limits.h>
Packit 3feee0
#include <sys/types.h>
Packit 3feee0
#include <sys/stat.h>
Packit 3feee0
#include "callbacks.h"
Packit 3feee0
#include "label_internal.h"
Packit 3feee0
Packit 3feee0
/* A property security context specification. */
Packit 3feee0
typedef struct spec {
Packit 3feee0
	struct selabel_lookup_rec lr;	/* holds contexts for lookup result */
Packit 3feee0
	char *property_key;		/* property key string */
Packit 3feee0
} spec_t;
Packit 3feee0
Packit 3feee0
/* Our stored configuration */
Packit 3feee0
struct saved_data {
Packit 3feee0
	/*
Packit 3feee0
	 * The array of specifications is sorted for longest
Packit 3feee0
	 * prefix match
Packit 3feee0
	 */
Packit 3feee0
	spec_t *spec_arr;
Packit 3feee0
	unsigned int nspec;	/* total number of specifications */
Packit 3feee0
};
Packit 3feee0
Packit 3feee0
static int cmp(const void *A, const void *B)
Packit 3feee0
{
Packit 3feee0
	const struct spec *sp1 = A, *sp2 = B;
Packit 3feee0
Packit 3feee0
	if (strncmp(sp1->property_key, "*", 1) == 0)
Packit 3feee0
		return 1;
Packit 3feee0
	if (strncmp(sp2->property_key, "*", 1) == 0)
Packit 3feee0
		return -1;
Packit 3feee0
Packit 3feee0
	size_t L1 = strlen(sp1->property_key);
Packit 3feee0
	size_t L2 = strlen(sp2->property_key);
Packit 3feee0
Packit 3feee0
	return (L1 < L2) - (L1 > L2);
Packit 3feee0
}
Packit 3feee0
Packit 3feee0
/*
Packit 3feee0
 * Warn about duplicate specifications.
Packit 3feee0
 */
Packit 3feee0
static int nodups_specs(struct saved_data *data, const char *path)
Packit 3feee0
{
Packit 3feee0
	int rc = 0;
Packit 3feee0
	unsigned int ii, jj;
Packit 3feee0
	struct spec *curr_spec, *spec_arr = data->spec_arr;
Packit 3feee0
Packit 3feee0
	for (ii = 0; ii < data->nspec; ii++) {
Packit 3feee0
		curr_spec = &spec_arr[ii];
Packit 3feee0
		for (jj = ii + 1; jj < data->nspec; jj++) {
Packit 3feee0
			if (!strcmp(spec_arr[jj].property_key,
Packit 3feee0
					    curr_spec->property_key)) {
Packit 3feee0
				rc = -1;
Packit 3feee0
				errno = EINVAL;
Packit 3feee0
				if (strcmp(spec_arr[jj].lr.ctx_raw,
Packit 3feee0
						    curr_spec->lr.ctx_raw)) {
Packit 3feee0
					selinux_log
Packit 3feee0
						(SELINUX_ERROR,
Packit 3feee0
						 "%s: Multiple different specifications for %s  (%s and %s).\n",
Packit 3feee0
						 path, curr_spec->property_key,
Packit 3feee0
						 spec_arr[jj].lr.ctx_raw,
Packit 3feee0
						 curr_spec->lr.ctx_raw);
Packit 3feee0
				} else {
Packit 3feee0
					selinux_log
Packit 3feee0
						(SELINUX_ERROR,
Packit 3feee0
						 "%s: Multiple same specifications for %s.\n",
Packit 3feee0
						 path, curr_spec->property_key);
Packit 3feee0
				}
Packit 3feee0
			}
Packit 3feee0
		}
Packit 3feee0
	}
Packit 3feee0
	return rc;
Packit 3feee0
}
Packit 3feee0
Packit 3feee0
static int process_line(struct selabel_handle *rec,
Packit 3feee0
			const char *path, char *line_buf,
Packit 3feee0
			int pass, unsigned lineno)
Packit 3feee0
{
Packit 3feee0
	int items;
Packit 3feee0
	char *prop = NULL, *context = NULL;
Packit 3feee0
	struct saved_data *data = (struct saved_data *)rec->data;
Packit 3feee0
	spec_t *spec_arr = data->spec_arr;
Packit 3feee0
	unsigned int nspec = data->nspec;
Packit 3feee0
	const char *errbuf = NULL;
Packit 3feee0
Packit 3feee0
	items = read_spec_entries(line_buf, &errbuf, 2, &prop, &context);
Packit 3feee0
	if (items < 0) {
Packit 3feee0
		items = errno;
Packit 3feee0
		selinux_log(SELINUX_ERROR,
Packit 3feee0
			"%s:  line %u error due to: %s\n", path,
Packit 3feee0
			lineno, errbuf ?: strerror(errno));
Packit 3feee0
		errno = items;
Packit 3feee0
		return -1;
Packit 3feee0
	}
Packit 3feee0
Packit 3feee0
	if (items == 0)
Packit 3feee0
		return items;
Packit 3feee0
Packit 3feee0
	if (items != 2) {
Packit 3feee0
		selinux_log(SELINUX_ERROR,
Packit 3feee0
			    "%s:  line %u is missing fields\n", path,
Packit 3feee0
			    lineno);
Packit 3feee0
		free(prop);
Packit 3feee0
		errno = EINVAL;
Packit 3feee0
		return -1;
Packit 3feee0
	}
Packit 3feee0
Packit 3feee0
	if (pass == 0) {
Packit 3feee0
		free(prop);
Packit 3feee0
		free(context);
Packit 3feee0
	} else if (pass == 1) {
Packit 3feee0
		/* On the second pass, process and store the specification in spec. */
Packit 3feee0
		spec_arr[nspec].property_key = prop;
Packit 3feee0
		spec_arr[nspec].lr.ctx_raw = context;
Packit 3feee0
Packit 3feee0
		if (rec->validating) {
Packit 3feee0
			if (selabel_validate(rec, &spec_arr[nspec].lr) < 0) {
Packit 3feee0
				selinux_log(SELINUX_ERROR,
Packit 3feee0
					    "%s:  line %u has invalid context %s\n",
Packit 3feee0
					    path, lineno, spec_arr[nspec].lr.ctx_raw);
Packit 3feee0
				errno = EINVAL;
Packit 3feee0
				return -1;
Packit 3feee0
			}
Packit 3feee0
		}
Packit 3feee0
	}
Packit 3feee0
Packit 3feee0
	data->nspec = ++nspec;
Packit 3feee0
	return 0;
Packit 3feee0
}
Packit 3feee0
Packit 3feee0
static int init(struct selabel_handle *rec, const struct selinux_opt *opts,
Packit 3feee0
		unsigned n)
Packit 3feee0
{
Packit 3feee0
	struct saved_data *data = (struct saved_data *)rec->data;
Packit 3feee0
	const char *path = NULL;
Packit 3feee0
	FILE *fp;
Packit 3feee0
	char line_buf[BUFSIZ];
Packit 3feee0
	unsigned int lineno, maxnspec, pass;
Packit 3feee0
	int status = -1;
Packit 3feee0
	struct stat sb;
Packit 3feee0
Packit 3feee0
	/* Process arguments */
Packit 3feee0
	while (n--)
Packit 3feee0
		switch (opts[n].type) {
Packit 3feee0
		case SELABEL_OPT_PATH:
Packit 3feee0
			path = opts[n].value;
Packit 3feee0
			break;
Packit 3feee0
		}
Packit 3feee0
Packit 3feee0
	if (!path)
Packit 3feee0
		return -1;
Packit 3feee0
Packit 3feee0
	/* Open the specification file. */
Packit 3feee0
	if ((fp = fopen(path, "re")) == NULL)
Packit 3feee0
		return -1;
Packit 3feee0
Packit 3feee0
	if (fstat(fileno(fp), &sb) < 0)
Packit 3feee0
		goto finish;
Packit 3feee0
	errno = EINVAL;
Packit 3feee0
	if (!S_ISREG(sb.st_mode))
Packit 3feee0
		goto finish;
Packit 3feee0
Packit 3feee0
	/*
Packit 3feee0
	 * Two passes of the specification file. First is to get the size.
Packit 3feee0
	 * After the first pass, the spec array is malloced to the appropriate
Packit 3feee0
	 * size. Second pass is to populate the spec array and check for
Packit 3feee0
	 * dups.
Packit 3feee0
	 */
Packit 3feee0
	maxnspec = UINT_MAX / sizeof(spec_t);
Packit 3feee0
	for (pass = 0; pass < 2; pass++) {
Packit 3feee0
		data->nspec = 0;
Packit 3feee0
		lineno = 0;
Packit 3feee0
Packit 3feee0
		while (fgets(line_buf, sizeof(line_buf) - 1, fp)
Packit 3feee0
		       && data->nspec < maxnspec) {
Packit 3feee0
			if (process_line(rec, path, line_buf, pass, ++lineno)
Packit 3feee0
									  != 0)
Packit 3feee0
				goto finish;
Packit 3feee0
		}
Packit 3feee0
Packit 3feee0
		if (pass == 1) {
Packit 3feee0
			status = nodups_specs(data, path);
Packit 3feee0
Packit 3feee0
			if (status)
Packit 3feee0
				goto finish;
Packit 3feee0
		}
Packit 3feee0
Packit 3feee0
		if (pass == 0) {
Packit 3feee0
			if (data->nspec == 0) {
Packit 3feee0
				status = 0;
Packit 3feee0
				goto finish;
Packit 3feee0
			}
Packit 3feee0
Packit 3feee0
			if (NULL == (data->spec_arr =
Packit 3feee0
				     calloc(data->nspec, sizeof(spec_t))))
Packit 3feee0
				goto finish;
Packit 3feee0
Packit 3feee0
			maxnspec = data->nspec;
Packit 3feee0
			rewind(fp);
Packit 3feee0
		}
Packit 3feee0
	}
Packit 3feee0
Packit 3feee0
	qsort(data->spec_arr, data->nspec, sizeof(struct spec), cmp);
Packit 3feee0
Packit 3feee0
	status = digest_add_specfile(rec->digest, fp, NULL, sb.st_size, path);
Packit 3feee0
	if (status)
Packit 3feee0
		goto finish;
Packit 3feee0
Packit 3feee0
	digest_gen_hash(rec->digest);
Packit 3feee0
Packit 3feee0
finish:
Packit 3feee0
	fclose(fp);
Packit 3feee0
	return status;
Packit 3feee0
}
Packit 3feee0
Packit 3feee0
/*
Packit 3feee0
 * Backend interface routines
Packit 3feee0
 */
Packit 3feee0
static void closef(struct selabel_handle *rec)
Packit 3feee0
{
Packit 3feee0
	struct saved_data *data = (struct saved_data *)rec->data;
Packit 3feee0
	struct spec *spec;
Packit 3feee0
	unsigned int i;
Packit 3feee0
Packit 3feee0
	for (i = 0; i < data->nspec; i++) {
Packit 3feee0
		spec = &data->spec_arr[i];
Packit 3feee0
		free(spec->property_key);
Packit 3feee0
		free(spec->lr.ctx_raw);
Packit 3feee0
		free(spec->lr.ctx_trans);
Packit 3feee0
	}
Packit 3feee0
Packit 3feee0
	if (data->spec_arr)
Packit 3feee0
		free(data->spec_arr);
Packit 3feee0
Packit 3feee0
	free(data);
Packit 3feee0
}
Packit 3feee0
Packit 3feee0
static struct selabel_lookup_rec *property_lookup(struct selabel_handle *rec,
Packit 3feee0
					 const char *key,
Packit 3feee0
					 int __attribute__((unused)) type)
Packit 3feee0
{
Packit 3feee0
	struct saved_data *data = (struct saved_data *)rec->data;
Packit 3feee0
	spec_t *spec_arr = data->spec_arr;
Packit 3feee0
	unsigned int i;
Packit 3feee0
	struct selabel_lookup_rec *ret = NULL;
Packit 3feee0
Packit 3feee0
	if (!data->nspec) {
Packit 3feee0
		errno = ENOENT;
Packit 3feee0
		goto finish;
Packit 3feee0
	}
Packit 3feee0
Packit 3feee0
	for (i = 0; i < data->nspec; i++) {
Packit 3feee0
		if (strncmp(spec_arr[i].property_key, key,
Packit 3feee0
			    strlen(spec_arr[i].property_key)) == 0) {
Packit 3feee0
			break;
Packit 3feee0
		}
Packit 3feee0
		if (strncmp(spec_arr[i].property_key, "*", 1) == 0)
Packit 3feee0
			break;
Packit 3feee0
	}
Packit 3feee0
Packit 3feee0
	if (i >= data->nspec) {
Packit 3feee0
		/* No matching specification. */
Packit 3feee0
		errno = ENOENT;
Packit 3feee0
		goto finish;
Packit 3feee0
	}
Packit 3feee0
Packit 3feee0
	ret = &spec_arr[i].lr;
Packit 3feee0
Packit 3feee0
finish:
Packit 3feee0
	return ret;
Packit 3feee0
}
Packit 3feee0
Packit 3feee0
static struct selabel_lookup_rec *service_lookup(struct selabel_handle *rec,
Packit 3feee0
		const char *key, int __attribute__((unused)) type)
Packit 3feee0
{
Packit 3feee0
	struct saved_data *data = (struct saved_data *)rec->data;
Packit 3feee0
	spec_t *spec_arr = data->spec_arr;
Packit 3feee0
	unsigned int i;
Packit 3feee0
	struct selabel_lookup_rec *ret = NULL;
Packit 3feee0
Packit 3feee0
	if (!data->nspec) {
Packit 3feee0
		errno = ENOENT;
Packit 3feee0
		goto finish;
Packit 3feee0
	}
Packit 3feee0
Packit 3feee0
	for (i = 0; i < data->nspec; i++) {
Packit 3feee0
		if (strcmp(spec_arr[i].property_key, key) == 0)
Packit 3feee0
			break;
Packit 3feee0
		if (strcmp(spec_arr[i].property_key, "*") == 0)
Packit 3feee0
			break;
Packit 3feee0
	}
Packit 3feee0
Packit 3feee0
	if (i >= data->nspec) {
Packit 3feee0
		/* No matching specification. */
Packit 3feee0
		errno = ENOENT;
Packit 3feee0
		goto finish;
Packit 3feee0
	}
Packit 3feee0
Packit 3feee0
	ret = &spec_arr[i].lr;
Packit 3feee0
Packit 3feee0
finish:
Packit 3feee0
	return ret;
Packit 3feee0
}
Packit 3feee0
Packit 3feee0
static void stats(struct selabel_handle __attribute__((unused)) *rec)
Packit 3feee0
{
Packit 3feee0
	selinux_log(SELINUX_WARNING, "'stats' functionality not implemented.\n");
Packit 3feee0
}
Packit 3feee0
Packit 3feee0
int selabel_property_init(struct selabel_handle *rec,
Packit 3feee0
			  const struct selinux_opt *opts,
Packit 3feee0
			  unsigned nopts)
Packit 3feee0
{
Packit 3feee0
	struct saved_data *data;
Packit 3feee0
Packit 3feee0
	data = (struct saved_data *)calloc(1, sizeof(*data));
Packit 3feee0
	if (!data)
Packit 3feee0
		return -1;
Packit 3feee0
Packit 3feee0
	rec->data = data;
Packit 3feee0
	rec->func_close = &closef;
Packit 3feee0
	rec->func_stats = &stat;;
Packit 3feee0
	rec->func_lookup = &property_lookup;
Packit 3feee0
Packit 3feee0
	return init(rec, opts, nopts);
Packit 3feee0
}
Packit 3feee0
Packit 3feee0
int selabel_service_init(struct selabel_handle *rec,
Packit 3feee0
		const struct selinux_opt *opts, unsigned nopts)
Packit 3feee0
{
Packit 3feee0
	struct saved_data *data;
Packit 3feee0
Packit 3feee0
	data = (struct saved_data *)calloc(1, sizeof(*data));
Packit 3feee0
	if (!data)
Packit 3feee0
		return -1;
Packit 3feee0
Packit 3feee0
	rec->data = data;
Packit 3feee0
	rec->func_close = &closef;
Packit 3feee0
	rec->func_stats = &stat;;
Packit 3feee0
	rec->func_lookup = &service_lookup;
Packit 3feee0
Packit 3feee0
	return init(rec, opts, nopts);
Packit 3feee0
}