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