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