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