Home | History | Annotate | Download | only in src
      1 /*
      2  * Media contexts backend for DB objects
      3  *
      4  * Author: KaiGai Kohei <kaigai (at) ak.jp.nec.com>
      5  */
      6 
      7 #include <sys/stat.h>
      8 #include <string.h>
      9 #include <stdio.h>
     10 #include <stdio_ext.h>
     11 #include <ctype.h>
     12 #include <errno.h>
     13 #include <limits.h>
     14 #include <fnmatch.h>
     15 #include "callbacks.h"
     16 #include "label_internal.h"
     17 
     18 /*
     19  * Regular database object's security context interface
     20  *
     21  * It provides applications a regular security context for the given
     22  * database objects. The pair of object's name and a security context
     23  * are described in the specfile. In the default, it shall be stored
     24  * in the /etc/selinux/$POLICYTYPE/contexts/sepgsql_contexts .
     25  * (It assumes SE-PostgreSQL in the default. For other RDBMS, use the
     26  * SELABEL_OPT_PATH option to specify different specfile.)
     27  *
     28  * Each line has the following format:
     29  *   <object class> <object name/identifier> <security context>
     30  *
     31  * For example:
     32  * ----------------------------------------
     33  * #
     34  * # It is an example specfile for database obejcts
     35  * #
     36  * db_database  template1           system_u:object_r:sepgsql_db_t:s0
     37  *
     38  * db_schema    *.pg_catalog        system_u:object_r:sepgsql_sys_schema_t:s0
     39  *
     40  * db_table     *.pg_catalog.*	    system_u:object_r:sepgsql_sysobj_t:s0
     41  * db_column    *.pg_catalog.*.*    system_u:object_r:sepgsql_sysobj_t:s0
     42  * ----------------------------------------
     43  *
     44  * All the characters after the '#' are dealt as comments.
     45  *
     46  * The first token is object class. SELABEL_DB_* declared in label.h are
     47  * corresponding to a certain database object.
     48  *
     49  * The object name/identifier is compared to the given key.
     50  * A database object can have its own namespace hierarchy.
     51  * In the case of SE-PgSQL, database is the top level object, and schema
     52  * is deployed just under a database. A schema can contains various kind
     53  * of objects, such as tables, procedures and so on.
     54  * Thus, when we lookup an expected security context for a table of
     55  * "pg_class", it is necessary to assume selabel_lookup() is called with
     56  * "postgres.pg_catalog.pg_class", not just a "pg_class".
     57  *
     58  * Wildcards ('*' or '?') are available on the patterns, so if you want
     59  * to match a table within any schema, you should set '*' on the upper
     60  * namespaces of the table.
     61  *
     62  * The structure of namespace depends on RDBMS.
     63  * For example, Trusted-RUBIX has an idea of "catalog" which performs
     64  * as a namespace between a database and individual schemas. In this
     65  * case, a table has upper three layers.
     66  */
     67 
     68 /*
     69  * spec_t : It holds a pair of a key and an expected security context
     70  */
     71 typedef struct spec {
     72 	struct selabel_lookup_rec lr;
     73 	char	       *key;
     74 	int		type;
     75 	int		matches;
     76 } spec_t;
     77 
     78 /*
     79  * catalog_t : An array of spec_t
     80  */
     81 typedef struct catalog {
     82 	unsigned int	nspec;	/* number of specs in use */
     83 	unsigned int	limit;	/* physical limitation of specs[] */
     84 	spec_t		specs[0];
     85 } catalog_t;
     86 
     87 /*
     88  * Helper function to parse a line read from the specfile
     89  */
     90 static int
     91 process_line(const char *path, char *line_buf, unsigned int line_num,
     92 	     catalog_t *catalog)
     93 {
     94 	spec_t	       *spec = &catalog->specs[catalog->nspec];
     95 	char	       *type, *key, *context, *temp;
     96 	int		items;
     97 
     98 	/* Cut off comments */
     99 	temp = strchr(line_buf, '#');
    100 	if (temp)
    101 		*temp = '\0';
    102 
    103 	/*
    104 	 * Every entry must have the following format
    105 	 *   <object class> <object name> <security context>
    106 	 */
    107 	type = key = context = temp = NULL;
    108 	items = sscanf(line_buf, "%ms %ms %ms %ms",
    109 		       &type, &key, &context, &temp);
    110 	if (items != 3) {
    111 		if (items > 0)
    112 			selinux_log(SELINUX_WARNING,
    113 				    "%s:  line %u has invalid format, skipped",
    114 				    path, line_num);
    115 		goto skip;
    116 	}
    117 
    118 	/*
    119 	 * Set up individual spec entry
    120 	 */
    121 	memset(spec, 0, sizeof(spec_t));
    122 
    123 	if (!strcmp(type, "db_database"))
    124 		spec->type = SELABEL_DB_DATABASE;
    125 	else if (!strcmp(type, "db_schema"))
    126 		spec->type = SELABEL_DB_SCHEMA;
    127 	else if (!strcmp(type, "db_table"))
    128 		spec->type = SELABEL_DB_TABLE;
    129 	else if (!strcmp(type, "db_column"))
    130 		spec->type = SELABEL_DB_COLUMN;
    131 	else if (!strcmp(type, "db_sequence"))
    132 		spec->type = SELABEL_DB_SEQUENCE;
    133 	else if (!strcmp(type, "db_view"))
    134 		spec->type = SELABEL_DB_VIEW;
    135 	else if (!strcmp(type, "db_procedure"))
    136 		spec->type = SELABEL_DB_PROCEDURE;
    137 	else if (!strcmp(type, "db_blob"))
    138 		spec->type = SELABEL_DB_BLOB;
    139 	else if (!strcmp(type, "db_tuple"))
    140 		spec->type = SELABEL_DB_TUPLE;
    141 	else if (!strcmp(type, "db_language"))
    142 		spec->type = SELABEL_DB_LANGUAGE;
    143 	else if (!strcmp(type, "db_exception"))
    144 		spec->type = SELABEL_DB_EXCEPTION;
    145 	else if (!strcmp(type, "db_datatype"))
    146 		spec->type = SELABEL_DB_DATATYPE;
    147 	else {
    148 		selinux_log(SELINUX_WARNING,
    149 			    "%s:  line %u has invalid object type %s\n",
    150 			    path, line_num, type);
    151 		goto skip;
    152 	}
    153 
    154 	free(type);
    155 	spec->key = key;
    156 	spec->lr.ctx_raw = context;
    157 
    158 	catalog->nspec++;
    159 
    160 	return 0;
    161 
    162 skip:
    163 	free(type);
    164 	free(key);
    165 	free(context);
    166 	free(temp);
    167 
    168 	return 0;
    169 }
    170 
    171 /*
    172  * selabel_close() handler
    173  */
    174 static void
    175 db_close(struct selabel_handle *rec)
    176 {
    177 	catalog_t      *catalog = (catalog_t *)rec->data;
    178 	spec_t	       *spec;
    179 	unsigned int	i;
    180 
    181 	for (i = 0; i < catalog->nspec; i++) {
    182 		spec = &catalog->specs[i];
    183 		free(spec->key);
    184 		free(spec->lr.ctx_raw);
    185 		free(spec->lr.ctx_trans);
    186 	}
    187 	free(catalog);
    188 }
    189 
    190 /*
    191  * selabel_lookup() handler
    192  */
    193 static struct selabel_lookup_rec *
    194 db_lookup(struct selabel_handle *rec, const char *key, int type)
    195 {
    196 	catalog_t      *catalog = (catalog_t *)rec->data;
    197 	spec_t	       *spec;
    198 	unsigned int	i;
    199 
    200 	for (i = 0; i < catalog->nspec; i++) {
    201 		spec = &catalog->specs[i];
    202 
    203 		if (spec->type != type)
    204 			continue;
    205 		if (!fnmatch(spec->key, key, 0)) {
    206 			spec->matches++;
    207 
    208 			return &spec->lr;
    209 		}
    210 	}
    211 
    212 	/* No found */
    213 	errno = ENOENT;
    214 	return NULL;
    215 }
    216 
    217 /*
    218  * selabel_stats() handler
    219  */
    220 static void
    221 db_stats(struct selabel_handle *rec)
    222 {
    223 	catalog_t      *catalog = (catalog_t *)rec->data;
    224 	unsigned int	i, total = 0;
    225 
    226 	for (i = 0; i < catalog->nspec; i++)
    227 		total += catalog->specs[i].matches;
    228 
    229 	selinux_log(SELINUX_INFO, "%u entries, %u matches made\n",
    230 		    catalog->nspec, total);
    231 }
    232 
    233 /*
    234  * selabel_open() handler
    235  */
    236 static catalog_t *
    237 db_init(const struct selinux_opt *opts, unsigned nopts,
    238 			    struct selabel_handle *rec)
    239 {
    240 	catalog_t      *catalog;
    241 	FILE	       *filp;
    242 	const char     *path = NULL;
    243 	char	       *line_buf = NULL;
    244 	size_t		line_len = 0;
    245 	unsigned int	line_num = 0;
    246 	unsigned int	i;
    247 	struct stat sb;
    248 
    249 	/*
    250 	 * Initialize catalog data structure
    251 	 */
    252 	catalog = malloc(sizeof(catalog_t) + 32 * sizeof(spec_t));
    253 	if (!catalog)
    254 		return NULL;
    255 	catalog->limit = 32;
    256 	catalog->nspec = 0;
    257 
    258 	/*
    259 	 * Process arguments
    260 	 *
    261 	 * SELABEL_OPT_PATH:
    262 	 *   It allows to specify an alternative specification file instead of
    263 	 *   the default one. If RDBMS is not SE-PostgreSQL, it may need to
    264 	 *   specify an explicit specfile for database objects.
    265 	 */
    266 	while (nopts--) {
    267 		switch (opts[nopts].type) {
    268 		case SELABEL_OPT_PATH:
    269 			path = opts[nopts].value;
    270 			break;
    271 		}
    272 	}
    273 
    274 	/*
    275 	 * Open the specification file
    276 	 */
    277 	if (!path)
    278 		path = selinux_sepgsql_context_path();
    279 
    280 	if ((filp = fopen(path, "rb")) == NULL) {
    281 		free(catalog);
    282 		return NULL;
    283 	}
    284 	if (fstat(fileno(filp), &sb) < 0)
    285 		return NULL;
    286 	if (!S_ISREG(sb.st_mode)) {
    287 		errno = EINVAL;
    288 		return NULL;
    289 	}
    290 	rec->spec_file = strdup(path);
    291 
    292 	/*
    293 	 * Parse for each lines
    294 	 */
    295 	while (getline(&line_buf, &line_len, filp) > 0) {
    296 		/*
    297 		 * Expand catalog array, if necessary
    298 		 */
    299 		if (catalog->limit == catalog->nspec) {
    300 			size_t		length;
    301 			unsigned int	new_limit = 2 * catalog->limit;
    302 			catalog_t      *new_catalog;
    303 
    304 			length = sizeof(catalog_t)
    305 				+ new_limit * sizeof(spec_t);
    306 			new_catalog = realloc(catalog, length);
    307 			if (!new_catalog)
    308 				goto out_error;
    309 
    310 			catalog = new_catalog;
    311 			catalog->limit = new_limit;
    312 		}
    313 
    314 		/*
    315 		 * Parse a line
    316 		 */
    317 		if (process_line(path, line_buf, ++line_num, catalog) < 0)
    318 			goto out_error;
    319 	}
    320 	free(line_buf);
    321 
    322 	if (digest_add_specfile(rec->digest, filp, NULL, sb.st_size, path) < 0)
    323 		goto out_error;
    324 
    325 	digest_gen_hash(rec->digest);
    326 
    327 	fclose(filp);
    328 
    329 	return catalog;
    330 
    331 out_error:
    332 	for (i = 0; i < catalog->nspec; i++) {
    333 		spec_t	       *spec = &catalog->specs[i];
    334 
    335 		free(spec->key);
    336 		free(spec->lr.ctx_raw);
    337 		free(spec->lr.ctx_trans);
    338 	}
    339 	free(catalog);
    340 
    341 	return NULL;
    342 }
    343 
    344 /*
    345  * Initialize selabel_handle and load the entries of specfile
    346  */
    347 int selabel_db_init(struct selabel_handle *rec,
    348 		    const struct selinux_opt *opts, unsigned nopts)
    349 {
    350 	rec->func_close = &db_close;
    351 	rec->func_lookup = &db_lookup;
    352 	rec->func_stats = &db_stats;
    353 	rec->data = db_init(opts, nopts, rec);
    354 
    355 	return !rec->data ? -1 : 0;
    356 }
    357