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 		{semanage_ibpkey_dbase_local(handle),
    142 		 semanage_ibpkey_dbase_policy(handle), MODE_MODIFY},
    143 
    144 		{semanage_ibendport_dbase_local(handle),
    145 		 semanage_ibendport_dbase_policy(handle), MODE_MODIFY},
    146 	};
    147 	const unsigned int CCOUNT = sizeof(components) / sizeof(components[0]);
    148 
    149 	/* Merge components into policy (and validate) */
    150 	for (i = 0; i < CCOUNT; i++) {
    151 		record_t **records = NULL;
    152 		unsigned int nrecords = 0;
    153 
    154 		dbase_config_t *src = components[i].src;
    155 		dbase_config_t *dst = components[i].dst;
    156 		int mode = components[i].mode;
    157 		record_table_t *rtable = src->dtable->get_rtable(src->dbase);
    158 
    159 		/* Must invoke cache function first */
    160 		if (src->dtable->cache(handle, src->dbase) < 0)
    161 			goto err;
    162 		if (dst->dtable->cache(handle, dst->dbase) < 0)
    163 			goto err;
    164 
    165 		/* List all records */
    166 		if (src->dtable->list(handle, src->dbase,
    167 				      &records, &nrecords) < 0)
    168 			goto err;
    169 
    170 		/* Sort records on MODE_SORT */
    171 		if (mode & MODE_SORT) {
    172 			qsort(records, nrecords, sizeof(record_t *),
    173 			      (int (*)(const void *, const void *))rtable->
    174 			      compare2_qsort);
    175 		}
    176 
    177 		/* Clear obsolete ones for MODE_SET */
    178 		if (mode & MODE_SET &&
    179 		    clear_obsolete(handle, records, nrecords, src, dst) < 0) {
    180 			rc = STATUS_ERR;
    181 			goto dbase_exit;
    182 		}
    183 
    184 		/* Load records */
    185 		if (load_records(handle, dst, records, nrecords, mode) < 0) {
    186 
    187 			rc = STATUS_ERR;
    188 			goto dbase_exit;
    189 		}
    190 
    191 		/* Cleanup */
    192 	      dbase_exit:
    193 		for (j = 0; j < nrecords; j++)
    194 			rtable->free(records[j]);
    195 		free(records);
    196 
    197 		/* Abort on error */
    198 		if (rc < 0)
    199 			goto err;
    200 	}
    201 
    202 	return rc;
    203 
    204       err:
    205 	ERR(handle, "could not merge local modifications into policy");
    206 	return STATUS_ERR;
    207 }
    208 
    209 int semanage_commit_components(semanage_handle_t * handle)
    210 {
    211 
    212 	int i;
    213 	dbase_config_t *components[] = {
    214 		semanage_iface_dbase_local(handle),
    215 		semanage_bool_dbase_local(handle),
    216 		semanage_user_base_dbase_local(handle),
    217 		semanage_user_extra_dbase_local(handle),
    218 		semanage_user_extra_dbase_policy(handle),
    219 		semanage_port_dbase_local(handle),
    220 		semanage_fcontext_dbase_local(handle),
    221 		semanage_fcontext_dbase_policy(handle),
    222 		semanage_seuser_dbase_local(handle),
    223 		semanage_seuser_dbase_policy(handle),
    224 		semanage_bool_dbase_active(handle),
    225 		semanage_node_dbase_local(handle),
    226 		semanage_ibpkey_dbase_local(handle),
    227 		semanage_ibendport_dbase_local(handle),
    228 	};
    229 	const int CCOUNT = sizeof(components) / sizeof(components[0]);
    230 
    231 	for (i = 0; i < CCOUNT; i++) {
    232 		/* Flush to disk */
    233 		if (components[i]->dtable->flush(handle, components[i]->dbase) <
    234 		    0)
    235 			goto err;
    236 	}
    237 
    238 	return STATUS_SUCCESS;
    239 
    240       err:
    241 	ERR(handle, "could not commit local/active modifications");
    242 
    243 	for (i = 0; i < CCOUNT; i++)
    244 		components[i]->dtable->drop_cache(components[i]->dbase);
    245 	return STATUS_ERR;
    246 }
    247