Home | History | Annotate | Download | only in src
      1 /* Copyright (C) 2005 Red Hat, Inc. */
      2 
      3 #include <stdlib.h>
      4 #include "policy.h"
      5 #include "handle.h"
      6 #include "database.h"
      7 #include "modules.h"
      8 #include "debug.h"
      9 
     10 /* Powers of two only */
     11 #define MODE_SET    1
     12 #define MODE_MODIFY 2
     13 #define MODE_SORT   4
     14 
     15 static int clear_obsolete(semanage_handle_t * handle,
     16 			  record_t ** records,
     17 			  unsigned int nrecords,
     18 			  dbase_config_t * src, dbase_config_t * dst)
     19 {
     20 
     21 	record_key_t *key = NULL;
     22 	unsigned int i;
     23 
     24 	dbase_table_t *src_dtable = src->dtable;
     25 	dbase_table_t *dst_dtable = dst->dtable;
     26 	record_table_t *rtable = src_dtable->get_rtable(src->dbase);
     27 
     28 	for (i = 0; i < nrecords; i++) {
     29 		int exists;
     30 
     31 		if (rtable->key_extract(handle, records[i], &key) < 0)
     32 			goto err;
     33 
     34 		if (dst_dtable->exists(handle, dst->dbase, key, &exists) < 0)
     35 			goto err;
     36 
     37 		if (!exists) {
     38 			if (src_dtable->del(handle, src->dbase, key) < 0)
     39 				goto err;
     40 
     41 			rtable->free(records[i]);
     42 			records[i] = NULL;
     43 
     44 			/* FIXME: notice to user */
     45 			/* INFO(handle, "boolean %s is obsolete, unsetting configured value..."); */
     46 		}
     47 
     48 		rtable->key_free(key);
     49 	}
     50 
     51 	return STATUS_SUCCESS;
     52 
     53       err:
     54 	/* FIXME: handle error */
     55 	rtable->key_free(key);
     56 	return STATUS_ERR;
     57 }
     58 
     59 static int load_records(semanage_handle_t * handle,
     60 			dbase_config_t * dst,
     61 			record_t ** records, unsigned int nrecords, int mode)
     62 {
     63 
     64 	unsigned int i;
     65 	record_key_t *rkey = NULL;
     66 
     67 	dbase_t *dbase = dst->dbase;
     68 	dbase_table_t *dtable = dst->dtable;
     69 	record_table_t *rtable = dtable->get_rtable(dbase);
     70 
     71 	for (i = 0; i < nrecords; i++) {
     72 
     73 		/* Possibly obsoleted */
     74 		if (!records[i])
     75 			continue;
     76 
     77 		if (rtable->key_extract(handle, records[i], &rkey) < 0)
     78 			goto err;
     79 
     80 		if (mode & MODE_SET &&
     81 		    dtable->set(handle, dbase, rkey, records[i]) < 0)
     82 			goto err;
     83 
     84 		else if (mode & MODE_MODIFY &&
     85 			 dtable->modify(handle, dbase, rkey, records[i]) < 0)
     86 			goto err;
     87 
     88 		rtable->key_free(rkey);
     89 	}
     90 
     91 	return STATUS_SUCCESS;
     92 
     93       err:
     94 	/* FIXME: handle error */
     95 	rtable->key_free(rkey);
     96 	return STATUS_ERR;
     97 }
     98 
     99 typedef struct load_table {
    100 	dbase_config_t *src;
    101 	dbase_config_t *dst;
    102 	int mode;
    103 } load_table_t;
    104 
    105 /* This function must be called AFTER all modules are loaded.
    106  * Modules could be represented as a database, in which case
    107  * they should be loaded at the beginning of this function */
    108 
    109 int semanage_base_merge_components(semanage_handle_t * handle)
    110 {
    111 
    112 	unsigned int i, j;
    113 	int rc = STATUS_SUCCESS;
    114 
    115 	/* Order is important here - change things carefully.
    116 	 * System components first, local next. Verify runs with
    117 	 * mutual dependencies are ran after everything is merged */
    118 	load_table_t components[] = {
    119 
    120 		{semanage_user_base_dbase_local(handle),
    121 		 semanage_user_base_dbase_policy(handle), MODE_MODIFY},
    122 
    123 		{semanage_user_extra_dbase_local(handle),
    124 		 semanage_user_extra_dbase_policy(handle), MODE_MODIFY},
    125 
    126 		{semanage_port_dbase_local(handle),
    127 		 semanage_port_dbase_policy(handle), MODE_MODIFY},
    128 
    129 		{semanage_iface_dbase_local(handle),
    130 		 semanage_iface_dbase_policy(handle), MODE_MODIFY},
    131 
    132 		{semanage_bool_dbase_local(handle),
    133 		 semanage_bool_dbase_policy(handle), MODE_SET},
    134 
    135 		{semanage_seuser_dbase_local(handle),
    136 		 semanage_seuser_dbase_policy(handle), MODE_MODIFY},
    137 
    138 		{semanage_node_dbase_local(handle),
    139 		 semanage_node_dbase_policy(handle), MODE_MODIFY | MODE_SORT},
    140 	};
    141 	const unsigned int CCOUNT = sizeof(components) / sizeof(components[0]);
    142 
    143 	/* Merge components into policy (and validate) */
    144 	for (i = 0; i < CCOUNT; i++) {
    145 
    146 		record_t **records = NULL;
    147 		unsigned int nrecords = 0;
    148 
    149 		dbase_config_t *src = components[i].src;
    150 		dbase_config_t *dst = components[i].dst;
    151 		int mode = components[i].mode;
    152 		record_table_t *rtable = src->dtable->get_rtable(src->dbase);
    153 
    154 		/* Must invoke cache function first */
    155 		if (src->dtable->cache(handle, src->dbase) < 0)
    156 			goto err;
    157 		if (dst->dtable->cache(handle, dst->dbase) < 0)
    158 			goto err;
    159 
    160 		/* List all records */
    161 		if (src->dtable->list(handle, src->dbase,
    162 				      &records, &nrecords) < 0)
    163 			goto err;
    164 
    165 		/* Sort records on MODE_SORT */
    166 		if (mode & MODE_SORT) {
    167 			qsort(records, nrecords, sizeof(record_t *),
    168 			      (int (*)(const void *, const void *))rtable->
    169 			      compare2_qsort);
    170 		}
    171 
    172 		/* Clear obsolete ones for MODE_SET */
    173 		if (mode & MODE_SET &&
    174 		    clear_obsolete(handle, records, nrecords, src, dst) < 0) {
    175 			rc = STATUS_ERR;
    176 			goto dbase_exit;
    177 		}
    178 
    179 		/* Load records */
    180 		if (load_records(handle, dst, records, nrecords, mode) < 0) {
    181 
    182 			rc = STATUS_ERR;
    183 			goto dbase_exit;
    184 		}
    185 
    186 		/* Cleanup */
    187 	      dbase_exit:
    188 		for (j = 0; j < nrecords; j++)
    189 			rtable->free(records[j]);
    190 		free(records);
    191 
    192 		/* Abort on error */
    193 		if (rc < 0)
    194 			goto err;
    195 	}
    196 
    197 	return rc;
    198 
    199       err:
    200 	ERR(handle, "could not merge local modifications into policy");
    201 	return STATUS_ERR;
    202 }
    203 
    204 int semanage_commit_components(semanage_handle_t * handle)
    205 {
    206 
    207 	int i;
    208 	dbase_config_t *components[] = {
    209 		semanage_iface_dbase_local(handle),
    210 		semanage_bool_dbase_local(handle),
    211 		semanage_user_base_dbase_local(handle),
    212 		semanage_user_extra_dbase_local(handle),
    213 		semanage_user_extra_dbase_policy(handle),
    214 		semanage_port_dbase_local(handle),
    215 		semanage_fcontext_dbase_local(handle),
    216 		semanage_fcontext_dbase_policy(handle),
    217 		semanage_seuser_dbase_local(handle),
    218 		semanage_seuser_dbase_policy(handle),
    219 		semanage_bool_dbase_active(handle),
    220 		semanage_node_dbase_local(handle),
    221 	};
    222 	const int CCOUNT = sizeof(components) / sizeof(components[0]);
    223 
    224 	for (i = 0; i < CCOUNT; i++) {
    225 		/* Flush to disk */
    226 		if (components[i]->dtable->flush(handle, components[i]->dbase) <
    227 		    0)
    228 			goto err;
    229 	}
    230 
    231 	return STATUS_SUCCESS;
    232 
    233       err:
    234 	ERR(handle, "could not commit local/active modifications");
    235 
    236 	for (i = 0; i < CCOUNT; i++)
    237 		components[i]->dtable->drop_cache(components[i]->dbase);
    238 	return STATUS_ERR;
    239 }
    240