16cd6a6acSopenharmony_ci/* 26cd6a6acSopenharmony_ci * Media contexts backend for labeling system 36cd6a6acSopenharmony_ci * 46cd6a6acSopenharmony_ci * Author : Eamon Walsh <ewalsh@tycho.nsa.gov> 56cd6a6acSopenharmony_ci */ 66cd6a6acSopenharmony_ci 76cd6a6acSopenharmony_ci#include <sys/stat.h> 86cd6a6acSopenharmony_ci#include <string.h> 96cd6a6acSopenharmony_ci#include <stdio.h> 106cd6a6acSopenharmony_ci#include <stdio_ext.h> 116cd6a6acSopenharmony_ci#include <ctype.h> 126cd6a6acSopenharmony_ci#include <errno.h> 136cd6a6acSopenharmony_ci#include <limits.h> 146cd6a6acSopenharmony_ci#include "callbacks.h" 156cd6a6acSopenharmony_ci#include "label_internal.h" 166cd6a6acSopenharmony_ci 176cd6a6acSopenharmony_ci/* 186cd6a6acSopenharmony_ci * Internals 196cd6a6acSopenharmony_ci */ 206cd6a6acSopenharmony_ci 216cd6a6acSopenharmony_ci/* A context specification. */ 226cd6a6acSopenharmony_citypedef struct spec { 236cd6a6acSopenharmony_ci struct selabel_lookup_rec lr; /* holds contexts for lookup result */ 246cd6a6acSopenharmony_ci char *key; /* key string */ 256cd6a6acSopenharmony_ci int matches; /* number of matches made during operation */ 266cd6a6acSopenharmony_ci} spec_t; 276cd6a6acSopenharmony_ci 286cd6a6acSopenharmony_cistruct saved_data { 296cd6a6acSopenharmony_ci unsigned int nspec; 306cd6a6acSopenharmony_ci spec_t *spec_arr; 316cd6a6acSopenharmony_ci}; 326cd6a6acSopenharmony_ci 336cd6a6acSopenharmony_cistatic int process_line(const char *path, char *line_buf, int pass, 346cd6a6acSopenharmony_ci unsigned lineno, struct selabel_handle *rec) 356cd6a6acSopenharmony_ci{ 366cd6a6acSopenharmony_ci struct saved_data *data = (struct saved_data *)rec->data; 376cd6a6acSopenharmony_ci int items; 386cd6a6acSopenharmony_ci char *buf_p; 396cd6a6acSopenharmony_ci char *key, *context; 406cd6a6acSopenharmony_ci 416cd6a6acSopenharmony_ci buf_p = line_buf; 426cd6a6acSopenharmony_ci while (isspace(*buf_p)) 436cd6a6acSopenharmony_ci buf_p++; 446cd6a6acSopenharmony_ci /* Skip comment lines and empty lines. */ 456cd6a6acSopenharmony_ci if (*buf_p == '#' || *buf_p == 0) 466cd6a6acSopenharmony_ci return 0; 476cd6a6acSopenharmony_ci items = sscanf(line_buf, "%ms %ms ", &key, &context); 486cd6a6acSopenharmony_ci if (items < 2) { 496cd6a6acSopenharmony_ci selinux_log(SELINUX_WARNING, 506cd6a6acSopenharmony_ci "%s: line %u is missing fields, skipping\n", path, 516cd6a6acSopenharmony_ci lineno); 526cd6a6acSopenharmony_ci if (items == 1) 536cd6a6acSopenharmony_ci free(key); 546cd6a6acSopenharmony_ci return 0; 556cd6a6acSopenharmony_ci } 566cd6a6acSopenharmony_ci 576cd6a6acSopenharmony_ci if (pass == 1) { 586cd6a6acSopenharmony_ci data->spec_arr[data->nspec].key = key; 596cd6a6acSopenharmony_ci data->spec_arr[data->nspec].lr.ctx_raw = context; 606cd6a6acSopenharmony_ci } 616cd6a6acSopenharmony_ci 626cd6a6acSopenharmony_ci data->nspec++; 636cd6a6acSopenharmony_ci if (pass == 0) { 646cd6a6acSopenharmony_ci free(key); 656cd6a6acSopenharmony_ci free(context); 666cd6a6acSopenharmony_ci } 676cd6a6acSopenharmony_ci return 0; 686cd6a6acSopenharmony_ci} 696cd6a6acSopenharmony_ci 706cd6a6acSopenharmony_cistatic int init(struct selabel_handle *rec, const struct selinux_opt *opts, 716cd6a6acSopenharmony_ci unsigned n) 726cd6a6acSopenharmony_ci{ 736cd6a6acSopenharmony_ci FILE *fp; 746cd6a6acSopenharmony_ci struct saved_data *data = (struct saved_data *)rec->data; 756cd6a6acSopenharmony_ci const char *path = NULL; 766cd6a6acSopenharmony_ci char *line_buf = NULL; 776cd6a6acSopenharmony_ci size_t line_len = 0; 786cd6a6acSopenharmony_ci int status = -1; 796cd6a6acSopenharmony_ci unsigned int lineno, pass, maxnspec; 806cd6a6acSopenharmony_ci struct stat sb; 816cd6a6acSopenharmony_ci 826cd6a6acSopenharmony_ci /* Process arguments */ 836cd6a6acSopenharmony_ci while (n--) 846cd6a6acSopenharmony_ci switch(opts[n].type) { 856cd6a6acSopenharmony_ci case SELABEL_OPT_PATH: 866cd6a6acSopenharmony_ci path = opts[n].value; 876cd6a6acSopenharmony_ci break; 886cd6a6acSopenharmony_ci } 896cd6a6acSopenharmony_ci 906cd6a6acSopenharmony_ci /* Open the specification file. */ 916cd6a6acSopenharmony_ci if (!path) 926cd6a6acSopenharmony_ci path = selinux_media_context_path(); 936cd6a6acSopenharmony_ci if ((fp = fopen(path, "re")) == NULL) 946cd6a6acSopenharmony_ci return -1; 956cd6a6acSopenharmony_ci __fsetlocking(fp, FSETLOCKING_BYCALLER); 966cd6a6acSopenharmony_ci 976cd6a6acSopenharmony_ci if (fstat(fileno(fp), &sb) < 0) 986cd6a6acSopenharmony_ci goto finish; 996cd6a6acSopenharmony_ci if (!S_ISREG(sb.st_mode)) { 1006cd6a6acSopenharmony_ci errno = EINVAL; 1016cd6a6acSopenharmony_ci goto finish; 1026cd6a6acSopenharmony_ci } 1036cd6a6acSopenharmony_ci rec->spec_file = strdup(path); 1046cd6a6acSopenharmony_ci 1056cd6a6acSopenharmony_ci /* 1066cd6a6acSopenharmony_ci * Perform two passes over the specification file. 1076cd6a6acSopenharmony_ci * The first pass counts the number of specifications and 1086cd6a6acSopenharmony_ci * performs simple validation of the input. At the end 1096cd6a6acSopenharmony_ci * of the first pass, the spec array is allocated. 1106cd6a6acSopenharmony_ci * The second pass performs detailed validation of the input 1116cd6a6acSopenharmony_ci * and fills in the spec array. 1126cd6a6acSopenharmony_ci */ 1136cd6a6acSopenharmony_ci maxnspec = UINT_MAX / sizeof(spec_t); 1146cd6a6acSopenharmony_ci for (pass = 0; pass < 2; pass++) { 1156cd6a6acSopenharmony_ci lineno = 0; 1166cd6a6acSopenharmony_ci data->nspec = 0; 1176cd6a6acSopenharmony_ci while (getline(&line_buf, &line_len, fp) > 0 && 1186cd6a6acSopenharmony_ci data->nspec < maxnspec) { 1196cd6a6acSopenharmony_ci if (process_line(path, line_buf, pass, ++lineno, rec)) 1206cd6a6acSopenharmony_ci goto finish; 1216cd6a6acSopenharmony_ci } 1226cd6a6acSopenharmony_ci 1236cd6a6acSopenharmony_ci if (pass == 0) { 1246cd6a6acSopenharmony_ci if (data->nspec == 0) { 1256cd6a6acSopenharmony_ci status = 0; 1266cd6a6acSopenharmony_ci goto finish; 1276cd6a6acSopenharmony_ci } 1286cd6a6acSopenharmony_ci data->spec_arr = malloc(sizeof(spec_t)*data->nspec); 1296cd6a6acSopenharmony_ci if (data->spec_arr == NULL) 1306cd6a6acSopenharmony_ci goto finish; 1316cd6a6acSopenharmony_ci memset(data->spec_arr, 0, sizeof(spec_t)*data->nspec); 1326cd6a6acSopenharmony_ci maxnspec = data->nspec; 1336cd6a6acSopenharmony_ci rewind(fp); 1346cd6a6acSopenharmony_ci } 1356cd6a6acSopenharmony_ci } 1366cd6a6acSopenharmony_ci free(line_buf); 1376cd6a6acSopenharmony_ci 1386cd6a6acSopenharmony_ci status = digest_add_specfile(rec->digest, fp, NULL, sb.st_size, path); 1396cd6a6acSopenharmony_ci if (status) 1406cd6a6acSopenharmony_ci goto finish; 1416cd6a6acSopenharmony_ci 1426cd6a6acSopenharmony_ci digest_gen_hash(rec->digest); 1436cd6a6acSopenharmony_ci 1446cd6a6acSopenharmony_cifinish: 1456cd6a6acSopenharmony_ci fclose(fp); 1466cd6a6acSopenharmony_ci return status; 1476cd6a6acSopenharmony_ci} 1486cd6a6acSopenharmony_ci 1496cd6a6acSopenharmony_ci/* 1506cd6a6acSopenharmony_ci * Backend interface routines 1516cd6a6acSopenharmony_ci */ 1526cd6a6acSopenharmony_cistatic void close(struct selabel_handle *rec) 1536cd6a6acSopenharmony_ci{ 1546cd6a6acSopenharmony_ci struct saved_data *data = (struct saved_data *)rec->data; 1556cd6a6acSopenharmony_ci struct spec *spec, *spec_arr = data->spec_arr; 1566cd6a6acSopenharmony_ci unsigned int i; 1576cd6a6acSopenharmony_ci 1586cd6a6acSopenharmony_ci for (i = 0; i < data->nspec; i++) { 1596cd6a6acSopenharmony_ci spec = &spec_arr[i]; 1606cd6a6acSopenharmony_ci free(spec->key); 1616cd6a6acSopenharmony_ci free(spec->lr.ctx_raw); 1626cd6a6acSopenharmony_ci free(spec->lr.ctx_trans); 1636cd6a6acSopenharmony_ci } 1646cd6a6acSopenharmony_ci 1656cd6a6acSopenharmony_ci if (spec_arr) 1666cd6a6acSopenharmony_ci free(spec_arr); 1676cd6a6acSopenharmony_ci 1686cd6a6acSopenharmony_ci free(data); 1696cd6a6acSopenharmony_ci} 1706cd6a6acSopenharmony_ci 1716cd6a6acSopenharmony_cistatic struct selabel_lookup_rec *lookup(struct selabel_handle *rec, 1726cd6a6acSopenharmony_ci const char *key, 1736cd6a6acSopenharmony_ci int type __attribute__((unused))) 1746cd6a6acSopenharmony_ci{ 1756cd6a6acSopenharmony_ci struct saved_data *data = (struct saved_data *)rec->data; 1766cd6a6acSopenharmony_ci spec_t *spec_arr = data->spec_arr; 1776cd6a6acSopenharmony_ci unsigned int i; 1786cd6a6acSopenharmony_ci 1796cd6a6acSopenharmony_ci for (i = 0; i < data->nspec; i++) { 1806cd6a6acSopenharmony_ci if (!strncmp(spec_arr[i].key, key, strlen(key) + 1)) 1816cd6a6acSopenharmony_ci break; 1826cd6a6acSopenharmony_ci if (!strncmp(spec_arr[i].key, "*", 2)) 1836cd6a6acSopenharmony_ci break; 1846cd6a6acSopenharmony_ci } 1856cd6a6acSopenharmony_ci 1866cd6a6acSopenharmony_ci if (i >= data->nspec) { 1876cd6a6acSopenharmony_ci /* No matching specification. */ 1886cd6a6acSopenharmony_ci errno = ENOENT; 1896cd6a6acSopenharmony_ci return NULL; 1906cd6a6acSopenharmony_ci } 1916cd6a6acSopenharmony_ci 1926cd6a6acSopenharmony_ci spec_arr[i].matches++; 1936cd6a6acSopenharmony_ci return &spec_arr[i].lr; 1946cd6a6acSopenharmony_ci} 1956cd6a6acSopenharmony_ci 1966cd6a6acSopenharmony_cistatic void stats(struct selabel_handle *rec) 1976cd6a6acSopenharmony_ci{ 1986cd6a6acSopenharmony_ci struct saved_data *data = (struct saved_data *)rec->data; 1996cd6a6acSopenharmony_ci unsigned int i, total = 0; 2006cd6a6acSopenharmony_ci 2016cd6a6acSopenharmony_ci for (i = 0; i < data->nspec; i++) 2026cd6a6acSopenharmony_ci total += data->spec_arr[i].matches; 2036cd6a6acSopenharmony_ci 2046cd6a6acSopenharmony_ci selinux_log(SELINUX_INFO, "%u entries, %u matches made\n", 2056cd6a6acSopenharmony_ci data->nspec, total); 2066cd6a6acSopenharmony_ci} 2076cd6a6acSopenharmony_ci 2086cd6a6acSopenharmony_ciint selabel_media_init(struct selabel_handle *rec, 2096cd6a6acSopenharmony_ci const struct selinux_opt *opts, 2106cd6a6acSopenharmony_ci unsigned nopts) 2116cd6a6acSopenharmony_ci{ 2126cd6a6acSopenharmony_ci struct saved_data *data; 2136cd6a6acSopenharmony_ci 2146cd6a6acSopenharmony_ci data = (struct saved_data *)malloc(sizeof(*data)); 2156cd6a6acSopenharmony_ci if (!data) 2166cd6a6acSopenharmony_ci return -1; 2176cd6a6acSopenharmony_ci memset(data, 0, sizeof(*data)); 2186cd6a6acSopenharmony_ci 2196cd6a6acSopenharmony_ci rec->data = data; 2206cd6a6acSopenharmony_ci rec->func_close = &close; 2216cd6a6acSopenharmony_ci rec->func_lookup = &lookup; 2226cd6a6acSopenharmony_ci rec->func_stats = &stats; 2236cd6a6acSopenharmony_ci 2246cd6a6acSopenharmony_ci return init(rec, opts, nopts); 2256cd6a6acSopenharmony_ci} 226