| /* Copyright (C) 2005 Red Hat, Inc. */ |
| |
| #include <stdlib.h> |
| #include "policy.h" |
| #include "handle.h" |
| #include "database.h" |
| #include "modules.h" |
| #include "debug.h" |
| |
| /* Powers of two only */ |
| #define MODE_SET 1 |
| #define MODE_MODIFY 2 |
| #define MODE_SORT 4 |
| |
| static int clear_obsolete(semanage_handle_t * handle, |
| record_t ** records, |
| unsigned int nrecords, |
| dbase_config_t * src, dbase_config_t * dst) |
| { |
| |
| record_key_t *key = NULL; |
| unsigned int i; |
| |
| dbase_table_t *src_dtable = src->dtable; |
| dbase_table_t *dst_dtable = dst->dtable; |
| record_table_t *rtable = src_dtable->get_rtable(src->dbase); |
| |
| for (i = 0; i < nrecords; i++) { |
| int exists; |
| |
| if (rtable->key_extract(handle, records[i], &key) < 0) |
| goto err; |
| |
| if (dst_dtable->exists(handle, dst->dbase, key, &exists) < 0) |
| goto err; |
| |
| if (!exists) { |
| if (src_dtable->del(handle, src->dbase, key) < 0) |
| goto err; |
| |
| rtable->free(records[i]); |
| records[i] = NULL; |
| |
| /* FIXME: notice to user */ |
| /* INFO(handle, "boolean %s is obsolete, unsetting configured value..."); */ |
| } |
| |
| rtable->key_free(key); |
| } |
| |
| return STATUS_SUCCESS; |
| |
| err: |
| /* FIXME: handle error */ |
| rtable->key_free(key); |
| return STATUS_ERR; |
| } |
| |
| static int load_records(semanage_handle_t * handle, |
| dbase_config_t * dst, |
| record_t ** records, unsigned int nrecords, int mode) |
| { |
| |
| unsigned int i; |
| record_key_t *rkey = NULL; |
| |
| dbase_t *dbase = dst->dbase; |
| dbase_table_t *dtable = dst->dtable; |
| record_table_t *rtable = dtable->get_rtable(dbase); |
| |
| for (i = 0; i < nrecords; i++) { |
| |
| /* Possibly obsoleted */ |
| if (!records[i]) |
| continue; |
| |
| if (rtable->key_extract(handle, records[i], &rkey) < 0) |
| goto err; |
| |
| if (mode & MODE_SET && |
| dtable->set(handle, dbase, rkey, records[i]) < 0) |
| goto err; |
| |
| else if (mode & MODE_MODIFY && |
| dtable->modify(handle, dbase, rkey, records[i]) < 0) |
| goto err; |
| |
| rtable->key_free(rkey); |
| } |
| |
| return STATUS_SUCCESS; |
| |
| err: |
| /* FIXME: handle error */ |
| rtable->key_free(rkey); |
| return STATUS_ERR; |
| } |
| |
| typedef struct load_table { |
| dbase_config_t *src; |
| dbase_config_t *dst; |
| int mode; |
| } load_table_t; |
| |
| /* This function must be called AFTER all modules are loaded. |
| * Modules could be represented as a database, in which case |
| * they should be loaded at the beginning of this function */ |
| |
| int semanage_base_merge_components(semanage_handle_t * handle) |
| { |
| |
| unsigned int i, j; |
| int rc = STATUS_SUCCESS; |
| |
| /* Order is important here - change things carefully. |
| * System components first, local next. Verify runs with |
| * mutual dependencies are ran after everything is merged */ |
| load_table_t components[] = { |
| |
| {semanage_user_base_dbase_local(handle), |
| semanage_user_base_dbase_policy(handle), MODE_MODIFY}, |
| |
| {semanage_user_extra_dbase_local(handle), |
| semanage_user_extra_dbase_policy(handle), MODE_MODIFY}, |
| |
| {semanage_port_dbase_local(handle), |
| semanage_port_dbase_policy(handle), MODE_MODIFY}, |
| |
| {semanage_iface_dbase_local(handle), |
| semanage_iface_dbase_policy(handle), MODE_MODIFY}, |
| |
| {semanage_bool_dbase_local(handle), |
| semanage_bool_dbase_policy(handle), MODE_SET}, |
| |
| {semanage_seuser_dbase_local(handle), |
| semanage_seuser_dbase_policy(handle), MODE_MODIFY}, |
| |
| {semanage_node_dbase_local(handle), |
| semanage_node_dbase_policy(handle), MODE_MODIFY | MODE_SORT}, |
| |
| {semanage_ibpkey_dbase_local(handle), |
| semanage_ibpkey_dbase_policy(handle), MODE_MODIFY}, |
| |
| {semanage_ibendport_dbase_local(handle), |
| semanage_ibendport_dbase_policy(handle), MODE_MODIFY}, |
| }; |
| const unsigned int CCOUNT = sizeof(components) / sizeof(components[0]); |
| |
| /* Merge components into policy (and validate) */ |
| for (i = 0; i < CCOUNT; i++) { |
| record_t **records = NULL; |
| unsigned int nrecords = 0; |
| |
| dbase_config_t *src = components[i].src; |
| dbase_config_t *dst = components[i].dst; |
| int mode = components[i].mode; |
| record_table_t *rtable = src->dtable->get_rtable(src->dbase); |
| |
| /* Must invoke cache function first */ |
| if (src->dtable->cache(handle, src->dbase) < 0) |
| goto err; |
| if (dst->dtable->cache(handle, dst->dbase) < 0) |
| goto err; |
| |
| /* List all records */ |
| if (src->dtable->list(handle, src->dbase, |
| &records, &nrecords) < 0) |
| goto err; |
| |
| /* Sort records on MODE_SORT */ |
| if (mode & MODE_SORT) { |
| qsort(records, nrecords, sizeof(record_t *), |
| (int (*)(const void *, const void *))rtable-> |
| compare2_qsort); |
| } |
| |
| /* Clear obsolete ones for MODE_SET */ |
| if (mode & MODE_SET && |
| clear_obsolete(handle, records, nrecords, src, dst) < 0) { |
| rc = STATUS_ERR; |
| goto dbase_exit; |
| } |
| |
| /* Load records */ |
| if (load_records(handle, dst, records, nrecords, mode) < 0) { |
| |
| rc = STATUS_ERR; |
| goto dbase_exit; |
| } |
| |
| /* Cleanup */ |
| dbase_exit: |
| for (j = 0; j < nrecords; j++) |
| rtable->free(records[j]); |
| free(records); |
| |
| /* Abort on error */ |
| if (rc < 0) |
| goto err; |
| } |
| |
| return rc; |
| |
| err: |
| ERR(handle, "could not merge local modifications into policy"); |
| return STATUS_ERR; |
| } |
| |
| int semanage_commit_components(semanage_handle_t * handle) |
| { |
| |
| int i; |
| dbase_config_t *components[] = { |
| semanage_iface_dbase_local(handle), |
| semanage_bool_dbase_local(handle), |
| semanage_user_base_dbase_local(handle), |
| semanage_user_extra_dbase_local(handle), |
| semanage_user_extra_dbase_policy(handle), |
| semanage_port_dbase_local(handle), |
| semanage_fcontext_dbase_local(handle), |
| semanage_fcontext_dbase_policy(handle), |
| semanage_seuser_dbase_local(handle), |
| semanage_seuser_dbase_policy(handle), |
| semanage_bool_dbase_active(handle), |
| semanage_node_dbase_local(handle), |
| semanage_ibpkey_dbase_local(handle), |
| semanage_ibendport_dbase_local(handle), |
| }; |
| const int CCOUNT = sizeof(components) / sizeof(components[0]); |
| |
| for (i = 0; i < CCOUNT; i++) { |
| /* Flush to disk */ |
| if (components[i]->dtable->flush(handle, components[i]->dbase) < |
| 0) |
| goto err; |
| } |
| |
| return STATUS_SUCCESS; |
| |
| err: |
| ERR(handle, "could not commit local/active modifications"); |
| |
| for (i = 0; i < CCOUNT; i++) |
| components[i]->dtable->drop_cache(components[i]->dbase); |
| return STATUS_ERR; |
| } |