domain-trans-analysis.c

Go to the documentation of this file.
00001 /**
00002  * @file
00003  *
00004  * Routines to perform a domain transition analysis.
00005  *
00006  * @author Jeremy A. Mowery jmowery@tresys.com
00007  * @author Jason Tang  jtang@tresys.com
00008  *
00009  * Copyright (C) 2005-2007 Tresys Technology, LLC
00010  *
00011  *  This library is free software; you can redistribute it and/or
00012  *  modify it under the terms of the GNU Lesser General Public
00013  *  License as published by the Free Software Foundation; either
00014  *  version 2.1 of the License, or (at your option) any later version.
00015  *
00016  *  This library is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  *  Lesser General Public License for more details.
00020  *
00021  *  You should have received a copy of the GNU Lesser General Public
00022  *  License along with this library; if not, write to the Free Software
00023  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00024  */
00025 
00026 #include "policy-query-internal.h"
00027 #include "domain-trans-analysis-internal.h"
00028 #include <apol/domain-trans-analysis.h>
00029 #include <apol/bst.h>
00030 
00031 #include <stdio.h>
00032 #include <stdlib.h>
00033 #include <errno.h>
00034 #include <string.h>
00035 #include <stdbool.h>
00036 
00037 /* private data structure definitions */
00038 struct apol_domain_trans_table
00039 {
00040         apol_bst_t *domain_table;
00041         apol_bst_t *entrypoint_table;
00042 };
00043 
00044 typedef struct dom_node
00045 {
00046         const qpol_type_t *type;
00047         apol_bst_t *process_transition_tree;
00048         apol_bst_t *entrypoint_tree;
00049         apol_vector_t *setexec_rules;
00050 } dom_node_t;
00051 
00052 typedef struct ep_node
00053 {
00054         const qpol_type_t *type;
00055         apol_bst_t *execute_tree;
00056         apol_bst_t *type_transition_tree;
00057 } ep_node_t;
00058 
00059 typedef struct avrule_node
00060 {
00061         const qpol_type_t *type;
00062         const qpol_avrule_t *rule;
00063         bool used;
00064 } avrule_node_t;
00065 
00066 typedef struct terule_node
00067 {
00068         const qpol_type_t *src;
00069         const qpol_type_t *dflt;
00070         const qpol_terule_t *rule;
00071         bool used;
00072 } terule_node_t;
00073 
00074 /* public data structure definitions */
00075 struct apol_domain_trans_analysis
00076 {
00077         unsigned char direction;
00078         unsigned char valid;
00079         char *start_type;
00080         char *result;
00081         apol_vector_t *access_types;
00082         apol_vector_t *access_classes;
00083         apol_vector_t *access_perms;
00084         regex_t *result_regex;
00085 };
00086 
00087 struct apol_domain_trans_result
00088 {
00089         const qpol_type_t *start_type;
00090         const qpol_type_t *ep_type;
00091         const qpol_type_t *end_type;
00092         apol_vector_t *proc_trans_rules;
00093         apol_vector_t *ep_rules;
00094         apol_vector_t *exec_rules;
00095         apol_vector_t *setexec_rules;
00096         apol_vector_t *type_trans_rules;
00097         bool valid;
00098         /** if access filters used list of rules that satisfy
00099          * the filter criteria (of type qpol_avrule_t) */
00100         apol_vector_t *access_rules;
00101 };
00102 
00103 /* private functions */
00104 /* avrule_node */
00105 static int avrule_node_cmp(const void *a, const void *b, void *data __attribute__ ((unused)))
00106 {
00107         const avrule_node_t *an = a;
00108         const avrule_node_t *bn = b;
00109         ssize_t retv = (const char *)an->type - (const char *)bn->type;
00110         if (retv > 0)
00111                 return 1;
00112         else if (retv < 0)
00113                 return -1;
00114         retv = (const char *)an->rule - (const char *)bn->rule;
00115         if (retv > 0)
00116                 return 1;
00117         else if (retv < 0)
00118                 return -1;
00119         return 0;
00120 }
00121 
00122 static int avrule_node_reset(void *a, void *b __attribute__ ((unused)))
00123 {
00124         avrule_node_t *an = a;
00125         if (!a)
00126                 return -1;
00127         an->used = false;
00128         return 0;
00129 }
00130 
00131 static avrule_node_t *avrule_node_create(const qpol_type_t * type, const qpol_avrule_t * rule)
00132 {
00133         avrule_node_t *n = calloc(1, sizeof(*n));
00134         if (!n)
00135                 return NULL;
00136 
00137         n->type = type;
00138         n->rule = rule;
00139 
00140         return n;
00141 }
00142 
00143 /* terule_node */
00144 static int terule_node_cmp(const void *a, const void *b, void *data __attribute__ ((unused)))
00145 {
00146         const terule_node_t *an = a;
00147         const terule_node_t *bn = b;
00148         ssize_t retv = (const char *)an->src - (const char *)bn->src;
00149         if (retv > 0)
00150                 return 1;
00151         else if (retv < 0)
00152                 return -1;
00153         retv = (const char *)an->dflt - (const char *)bn->dflt;
00154         if (retv > 0)
00155                 return 1;
00156         else if (retv < 0)
00157                 return -1;
00158         retv = (const char *)an->rule - (const char *)bn->rule;
00159         if (retv > 0)
00160                 return 1;
00161         else if (retv < 0)
00162                 return -1;
00163         return 0;
00164 }
00165 
00166 static int terule_node_reset(void *a, void *b __attribute__ ((unused)))
00167 {
00168         terule_node_t *an = a;
00169         if (!a)
00170                 return -1;
00171         an->used = false;
00172         return 0;
00173 }
00174 
00175 static terule_node_t *terule_node_create(const qpol_type_t * src, const qpol_type_t * dflt, const qpol_terule_t * rule)
00176 {
00177         terule_node_t *n = calloc(1, sizeof(*n));
00178         if (!n)
00179                 return NULL;
00180 
00181         n->src = src;
00182         n->dflt = dflt;
00183         n->rule = rule;
00184 
00185         return n;
00186 }
00187 
00188 /* dom_node */
00189 static int dom_node_cmp(const void *a, const void *b, void *data __attribute__ ((unused)))
00190 {
00191         const dom_node_t *an = a;
00192         const dom_node_t *bn = b;
00193 
00194         if ((const char *)(an->type) < (const char *)(bn->type))
00195                 return -1;
00196         else if ((const char *)(an->type) > (const char *)(bn->type))
00197                 return 1;
00198         return 0;
00199 }
00200 
00201 static void dom_node_free(void *x)
00202 {
00203         if (!x)
00204                 return;
00205         apol_bst_destroy(&(((dom_node_t *) x)->process_transition_tree));
00206         apol_bst_destroy(&(((dom_node_t *) x)->entrypoint_tree));
00207         apol_vector_destroy(&(((dom_node_t *) x)->setexec_rules));
00208         free(x);
00209 }
00210 
00211 static int dom_node_reset(void *a, void *b __attribute__ ((unused)))
00212 {
00213         dom_node_t *an = a;
00214         if (!a)
00215                 return -1;
00216 
00217         if (apol_bst_inorder_map(an->process_transition_tree, avrule_node_reset, NULL) < 0)
00218                 return -1;
00219         if (apol_bst_inorder_map(an->entrypoint_tree, avrule_node_reset, NULL) < 0)
00220                 return -1;
00221 
00222         return 0;
00223 }
00224 
00225 static dom_node_t *dom_node_create(const qpol_type_t * type)
00226 {
00227         dom_node_t *n = calloc(1, sizeof(*n));
00228         if (!n)
00229                 return NULL;
00230 
00231         n->type = type;
00232         if (!(n->process_transition_tree = apol_bst_create(avrule_node_cmp, free)) ||
00233             !(n->entrypoint_tree = apol_bst_create(avrule_node_cmp, free)) || !(n->setexec_rules = apol_vector_create(NULL))) {
00234                 apol_bst_destroy(&n->process_transition_tree);
00235                 apol_bst_destroy(&n->entrypoint_tree);
00236                 apol_vector_destroy(&n->setexec_rules);
00237                 free(n);
00238                 return NULL;
00239         }
00240 
00241         return n;
00242 }
00243 
00244 /* ep_node */
00245 static int ep_node_cmp(const void *a, const void *b, void *data __attribute__ ((unused)))
00246 {
00247         const ep_node_t *an = a;
00248         const ep_node_t *bn = b;
00249 
00250         if ((const char *)(an->type) < (const char *)(bn->type))
00251                 return -1;
00252         else if ((const char *)(an->type) > (const char *)(bn->type))
00253                 return 1;
00254         return 0;
00255 }
00256 
00257 static void ep_node_free(void *x)
00258 {
00259         if (!x)
00260                 return;
00261         apol_bst_destroy(&(((ep_node_t *) x)->type_transition_tree));
00262         apol_bst_destroy(&(((ep_node_t *) x)->execute_tree));
00263         free(x);
00264 }
00265 
00266 static int ep_node_reset(void *a, void *b __attribute__ ((unused)))
00267 {
00268         ep_node_t *an = a;
00269         if (!a)
00270                 return -1;
00271 
00272         if (apol_bst_inorder_map(an->execute_tree, avrule_node_reset, NULL) < 0)
00273                 return -1;
00274         if (apol_bst_inorder_map(an->type_transition_tree, terule_node_reset, NULL) < 0)
00275                 return -1;
00276         return 0;
00277 }
00278 
00279 static ep_node_t *ep_node_create(const qpol_type_t * type)
00280 {
00281         ep_node_t *n = calloc(1, sizeof(*n));
00282         if (!n)
00283                 return NULL;
00284 
00285         n->type = type;
00286         if (!(n->execute_tree = apol_bst_create(avrule_node_cmp, free)) ||
00287             !(n->type_transition_tree = apol_bst_create(terule_node_cmp, free))) {
00288                 apol_bst_destroy(&n->execute_tree);
00289                 apol_bst_destroy(&n->type_transition_tree);
00290                 free(n);
00291                 return NULL;
00292         }
00293 
00294         return n;
00295 }
00296 
00297 /* table */
00298 static apol_domain_trans_table_t *apol_domain_trans_table_new(apol_policy_t * policy)
00299 {
00300         apol_domain_trans_table_t *new_table = NULL;
00301         int error;
00302 
00303         if (!policy) {
00304                 ERR(policy, "%s", strerror(EINVAL));
00305                 errno = EINVAL;
00306                 return NULL;
00307         }
00308 
00309         new_table = (apol_domain_trans_table_t *) calloc(1, sizeof(apol_domain_trans_table_t));
00310         if (!new_table) {
00311                 ERR(policy, "%s", strerror(ENOMEM));
00312                 error = ENOMEM;
00313                 goto cleanup;
00314         }
00315 
00316         if (!(new_table->domain_table = apol_bst_create(dom_node_cmp, dom_node_free))) {
00317                 ERR(policy, "%s", strerror(ENOMEM));
00318                 error = ENOMEM;
00319                 goto cleanup;
00320         }
00321         if (!(new_table->entrypoint_table = apol_bst_create(ep_node_cmp, ep_node_free))) {
00322                 ERR(policy, "%s", strerror(ENOMEM));
00323                 error = ENOMEM;
00324                 goto cleanup;
00325         }
00326 
00327         return new_table;
00328       cleanup:
00329         domain_trans_table_destroy(&new_table);
00330         errno = error;
00331         return NULL;
00332 }
00333 
00334 static int table_add_avrule(apol_policy_t * policy, apol_domain_trans_table_t * dta_table, const qpol_avrule_t * rule)
00335 {
00336         qpol_policy_t *qp = apol_policy_get_qpol(policy);
00337         const qpol_type_t *src;
00338         const qpol_type_t *tgt;
00339         qpol_avrule_get_source_type(qp, rule, &src);
00340         qpol_avrule_get_target_type(qp, rule, &tgt);
00341         apol_vector_t *sources = apol_query_expand_type(policy, src);
00342         apol_vector_t *targets = apol_query_expand_type(policy, tgt);
00343         bool exec = false, ep = false, proc_trans = false, setexec = false;
00344         qpol_iterator_t *iter = NULL;
00345         int error = 0;
00346         qpol_avrule_get_perm_iter(qp, rule, &iter);
00347         if (!iter || !sources || !targets) {
00348                 error = errno;
00349                 goto err;
00350         }
00351 
00352         for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
00353                 void *x;
00354                 qpol_iterator_get_item(iter, &x);
00355                 char *perm = x;
00356                 if (!strcmp("execute", perm))
00357                         exec = true;
00358                 if (!strcmp("entrypoint", perm))
00359                         ep = true;
00360                 if (!strcmp("transition", perm))
00361                         proc_trans = true;
00362                 if (!strcmp("setexec", perm))
00363                         setexec = true;
00364                 free(x);
00365         }
00366         qpol_iterator_destroy(&iter);
00367 
00368         if (proc_trans || ep || setexec) {
00369                 for (size_t i = 0; i < apol_vector_get_size(sources); i++) {
00370                         dom_node_t *dnode = NULL;
00371                         dom_node_t dummy = { apol_vector_get_element(sources, i), NULL, NULL, NULL };
00372                         if (apol_bst_get_element(dta_table->domain_table, &dummy, NULL, (void **)&dnode)) {
00373                                 dom_node_t *new_dnode = NULL;
00374                                 if (!(new_dnode = dom_node_create(dummy.type)) ||
00375                                     apol_bst_insert(dta_table->domain_table, (void *)new_dnode, NULL)) {
00376                                         error = errno;
00377                                         dom_node_free(new_dnode);
00378                                         goto err;
00379                                 }
00380                                 dnode = new_dnode;
00381                         }
00382                         if (setexec) {
00383                                 if (apol_vector_append_unique(dnode->setexec_rules, (void *)rule, NULL, NULL)) {
00384                                         error = errno;
00385                                         goto err;
00386                                 }
00387                         }
00388                         for (size_t j = 0; j < apol_vector_get_size(targets); j++) {
00389                                 if (proc_trans) {
00390                                         avrule_node_t *new_node =
00391                                                 avrule_node_create((const qpol_type_t *)apol_vector_get_element(targets, j), rule);
00392                                         if (!new_node ||
00393                                             apol_bst_insert_and_get(dnode->process_transition_tree, (void **)&new_node, NULL) < 0) {
00394                                                 error = errno;
00395                                                 free(new_node);
00396                                                 goto err;
00397                                         }
00398                                 }
00399                                 if (ep) {
00400                                         avrule_node_t *new_node =
00401                                                 avrule_node_create((const qpol_type_t *)apol_vector_get_element(targets, j), rule);
00402                                         if (!new_node ||
00403                                             apol_bst_insert_and_get(dnode->entrypoint_tree, (void **)&new_node, NULL) < 0) {
00404                                                 error = errno;
00405                                                 free(new_node);
00406                                                 goto err;
00407                                         }
00408                                 }
00409                         }
00410                 }
00411         }
00412         if (exec) {
00413                 for (size_t i = 0; i < apol_vector_get_size(targets); i++) {
00414                         ep_node_t *enode = NULL;
00415                         ep_node_t dummy = { apol_vector_get_element(targets, i), NULL, NULL };
00416                         if (apol_bst_get_element(dta_table->entrypoint_table, &dummy, NULL, (void **)&enode)) {
00417                                 ep_node_t *new_enode = NULL;
00418                                 if (!(new_enode = ep_node_create(dummy.type)) ||
00419                                     apol_bst_insert(dta_table->entrypoint_table, (void *)new_enode, NULL)) {
00420                                         error = errno;
00421                                         ep_node_free(new_enode);
00422                                         goto err;
00423                                 }
00424                                 enode = new_enode;
00425                         }
00426                         for (size_t j = 0; j < apol_vector_get_size(sources); j++) {
00427                                 avrule_node_t *new_node =
00428                                         avrule_node_create((const qpol_type_t *)apol_vector_get_element(sources, j), rule);
00429                                 if (!new_node || apol_bst_insert_and_get(enode->execute_tree, (void **)&new_node, NULL) < 0) {
00430                                         error = errno;
00431                                         free(new_node);
00432                                         goto err;
00433                                 }
00434                         }
00435                 }
00436         }
00437 
00438         apol_vector_destroy(&sources);
00439         apol_vector_destroy(&targets);
00440         return 0;
00441 
00442       err:
00443         qpol_iterator_destroy(&iter);
00444         apol_vector_destroy(&sources);
00445         apol_vector_destroy(&targets);
00446         errno = error;
00447         return -1;
00448 }
00449 
00450 static int table_add_terule(apol_policy_t * policy, apol_domain_trans_table_t * dta_table, const qpol_terule_t * rule)
00451 {
00452         qpol_policy_t *qp = apol_policy_get_qpol(policy);
00453         const qpol_type_t *src;
00454         const qpol_type_t *tgt;
00455         const qpol_type_t *dflt;
00456         qpol_terule_get_source_type(qp, rule, &src);
00457         qpol_terule_get_target_type(qp, rule, &tgt);
00458         qpol_terule_get_default_type(qp, rule, &dflt);
00459         apol_vector_t *sources = apol_query_expand_type(policy, src);
00460         apol_vector_t *targets = apol_query_expand_type(policy, tgt);
00461         int error = 0;
00462         for (size_t i = 0; i < apol_vector_get_size(targets); i++) {
00463                 ep_node_t *enode = NULL;
00464                 ep_node_t dummy = { apol_vector_get_element(targets, i), NULL, NULL };
00465                 if (apol_bst_get_element(dta_table->entrypoint_table, &dummy, NULL, (void **)&enode)) {
00466                         ep_node_t *new_enode = NULL;
00467                         if (!(new_enode = ep_node_create(dummy.type)) ||
00468                             apol_bst_insert(dta_table->entrypoint_table, (void *)new_enode, NULL)) {
00469                                 error = errno;
00470                                 ep_node_free(new_enode);
00471                                 goto err;
00472                         }
00473                         enode = new_enode;
00474                 }
00475                 for (size_t j = 0; j < apol_vector_get_size(sources); j++) {
00476                         terule_node_t *new_node =
00477                                 terule_node_create((const qpol_type_t *)apol_vector_get_element(sources, j), dflt, rule);
00478                         if (apol_bst_insert_and_get(enode->type_transition_tree, (void **)&new_node, NULL) < 0) {
00479                                 error = errno;
00480                                 free(new_node);
00481                                 goto err;
00482                         }
00483                 }
00484         }
00485 
00486         apol_vector_destroy(&sources);
00487         apol_vector_destroy(&targets);
00488         return 0;
00489       err:
00490         apol_vector_destroy(&sources);
00491         apol_vector_destroy(&targets);
00492         errno = error;
00493         return -1;
00494 }
00495 
00496 /* result */
00497 apol_domain_trans_result_t *domain_trans_result_create()
00498 {
00499         apol_domain_trans_result_t *res = calloc(1, sizeof(*res));
00500         if (!res)
00501                 return NULL;
00502 
00503         int error = 0;
00504         if (!(res->proc_trans_rules = apol_vector_create(NULL)) || !(res->ep_rules = apol_vector_create(NULL)) ||
00505             !(res->exec_rules = apol_vector_create(NULL)) || !(res->setexec_rules = apol_vector_create(NULL)) ||
00506             !(res->type_trans_rules = apol_vector_create(NULL))) {
00507                 error = errno;
00508                 goto err;
00509         }
00510 
00511         return res;
00512       err:
00513         apol_domain_trans_result_destroy(&res);
00514         errno = error;
00515         return NULL;
00516 }
00517 
00518 /* public functions */
00519 /* table */
00520 int apol_policy_build_domain_trans_table(apol_policy_t * policy)
00521 {
00522         int error = 0;
00523         apol_avrule_query_t *avq = NULL;
00524         apol_terule_query_t *teq = NULL;
00525         apol_vector_t *avrules = NULL;
00526         apol_vector_t *terules = NULL;
00527 
00528         if (!policy) {
00529                 ERR(policy, "%s", strerror(EINVAL));
00530                 errno = EINVAL;
00531                 return -1;
00532         }
00533 
00534         if (policy->domain_trans_table) {
00535                 return 0;              /* already built */
00536         }
00537 
00538         apol_domain_trans_table_t *dta_table = policy->domain_trans_table = apol_domain_trans_table_new(policy);
00539         if (!policy->domain_trans_table) {
00540                 error = errno;
00541                 goto err;
00542         }
00543 
00544         avq = apol_avrule_query_create();
00545         apol_avrule_query_set_rules(policy, avq, QPOL_RULE_ALLOW);
00546         apol_avrule_query_append_class(policy, avq, "file");
00547         apol_avrule_query_append_class(policy, avq, "process");
00548         apol_avrule_query_append_perm(policy, avq, "execute");
00549         apol_avrule_query_append_perm(policy, avq, "entrypoint");
00550         apol_avrule_query_append_perm(policy, avq, "transition");
00551         apol_avrule_query_append_perm(policy, avq, "setexec");
00552         if (apol_avrule_get_by_query(policy, avq, &avrules)) {
00553                 error = errno;
00554                 goto err;
00555         }
00556         apol_avrule_query_destroy(&avq);
00557         for (size_t i = 0; i < apol_vector_get_size(avrules); i++) {
00558                 if (table_add_avrule(policy, dta_table, (const qpol_avrule_t *)apol_vector_get_element(avrules, i))) {
00559                         error = errno;
00560                         goto err;
00561                 }
00562         }
00563         apol_vector_destroy(&avrules);
00564 
00565         teq = apol_terule_query_create();
00566         apol_terule_query_set_rules(policy, teq, QPOL_RULE_TYPE_TRANS);
00567         apol_terule_query_append_class(policy, teq, "process");
00568         if (apol_terule_get_by_query(policy, teq, &terules)) {
00569                 error = errno;
00570                 goto err;
00571         }
00572         apol_terule_query_destroy(&teq);
00573         for (size_t i = 0; i < apol_vector_get_size(terules); i++) {
00574                 if (table_add_terule(policy, dta_table, (const qpol_terule_t *)apol_vector_get_element(terules, i))) {
00575                         error = errno;
00576                         goto err;
00577                 }
00578         }
00579         apol_vector_destroy(&terules);
00580 
00581         return 0;
00582 
00583       err:
00584         apol_avrule_query_destroy(&avq);
00585         apol_vector_destroy(&avrules);
00586         apol_terule_query_destroy(&teq);
00587         apol_vector_destroy(&terules);
00588         domain_trans_table_destroy(&dta_table);
00589         policy->domain_trans_table = NULL;
00590         errno = error;
00591         return -1;
00592 }
00593 
00594 int apol_policy_domain_trans_table_build(apol_policy_t * policy)
00595 {
00596         return apol_policy_build_domain_trans_table(policy);
00597 }
00598 
00599 void domain_trans_table_destroy(apol_domain_trans_table_t ** table)
00600 {
00601         if (!table || !(*table))
00602                 return;
00603 
00604         apol_bst_destroy(&(*table)->domain_table);
00605         apol_bst_destroy(&(*table)->entrypoint_table);
00606         free(*table);
00607         *table = NULL;
00608 }
00609 
00610 void apol_policy_reset_domain_trans_table(apol_policy_t * policy)
00611 {
00612         if (!policy || !policy->domain_trans_table)
00613                 return;
00614         apol_bst_inorder_map(policy->domain_trans_table->domain_table, dom_node_reset, NULL);
00615         apol_bst_inorder_map(policy->domain_trans_table->entrypoint_table, ep_node_reset, NULL);
00616         return;
00617 }
00618 
00619 void apol_domain_trans_table_reset(apol_policy_t * policy)
00620 {
00621         apol_policy_reset_domain_trans_table(policy);
00622 }
00623 
00624 /* analysis */
00625 apol_domain_trans_analysis_t *apol_domain_trans_analysis_create(void)
00626 {
00627         apol_domain_trans_analysis_t *new_dta = NULL;
00628         int error = 0;
00629 
00630         if (!(new_dta = calloc(1, sizeof(apol_domain_trans_analysis_t)))) {
00631                 error = errno;
00632                 goto err;
00633         }
00634 
00635         new_dta->valid = APOL_DOMAIN_TRANS_SEARCH_VALID;        /* by default search only valid transitions */
00636 
00637         return new_dta;
00638 
00639       err:
00640         apol_domain_trans_analysis_destroy(&new_dta);
00641         errno = error;
00642         return NULL;
00643 }
00644 
00645 void apol_domain_trans_analysis_destroy(apol_domain_trans_analysis_t ** dta)
00646 {
00647         if (!dta || !(*dta))
00648                 return;
00649 
00650         free((*dta)->start_type);
00651         free((*dta)->result);
00652         apol_vector_destroy(&((*dta)->access_types));
00653         apol_vector_destroy(&((*dta)->access_classes));
00654         apol_vector_destroy(&((*dta)->access_perms));
00655         apol_regex_destroy(&((*dta)->result_regex));
00656         free(*dta);
00657         *dta = NULL;
00658 }
00659 
00660 int apol_domain_trans_analysis_set_direction(const apol_policy_t * policy, apol_domain_trans_analysis_t * dta,
00661                                              unsigned char direction)
00662 {
00663         if (!dta || (direction != APOL_DOMAIN_TRANS_DIRECTION_FORWARD && direction != APOL_DOMAIN_TRANS_DIRECTION_REVERSE)) {
00664                 ERR(policy, "Error setting analysis direction: %s", strerror(EINVAL));
00665                 errno = EINVAL;
00666                 return -1;
00667         }
00668 
00669         dta->direction = direction;
00670 
00671         return 0;
00672 }
00673 
00674 int apol_domain_trans_analysis_set_valid(const apol_policy_t * policy, apol_domain_trans_analysis_t * dta, unsigned char valid)
00675 {
00676         if (!dta || valid & ~(APOL_DOMAIN_TRANS_SEARCH_BOTH)) {
00677                 ERR(policy, "Error setting analysis validity flag: %s", strerror(EINVAL));
00678                 errno = EINVAL;
00679                 return -1;
00680         }
00681 
00682         dta->valid = valid;
00683 
00684         return 0;
00685 }
00686 
00687 int apol_domain_trans_analysis_set_start_type(const apol_policy_t * policy, apol_domain_trans_analysis_t * dta,
00688                                               const char *type_name)
00689 {
00690         char *tmp = NULL;
00691         int error = 0;
00692 
00693         if (!dta || !type_name) {
00694                 ERR(policy, "%s", strerror(EINVAL));
00695                 errno = EINVAL;
00696                 return -1;
00697         }
00698 
00699         if (!(tmp = strdup(type_name))) {
00700                 error = errno;
00701                 ERR(policy, "%s", strerror(error));
00702                 errno = error;
00703                 return -1;
00704         }
00705 
00706         free(dta->start_type);
00707         dta->start_type = tmp;
00708 
00709         return 0;
00710 }
00711 
00712 int apol_domain_trans_analysis_set_result_regex(const apol_policy_t * policy, apol_domain_trans_analysis_t * dta, const char *regex)
00713 {
00714         if (!dta) {
00715                 ERR(policy, "%s", strerror(EINVAL));
00716                 errno = EINVAL;
00717                 return -1;
00718         }
00719 
00720         if (!regex) {
00721                 apol_regex_destroy(&dta->result_regex);
00722                 return 0;
00723         }
00724 
00725         return apol_query_set(policy, &dta->result, &dta->result_regex, regex);
00726 }
00727 
00728 int apol_domain_trans_analysis_append_access_type(const apol_policy_t * policy, apol_domain_trans_analysis_t * dta,
00729                                                   const char *type_name)
00730 {
00731         char *tmp = NULL;
00732         int error = 0;
00733 
00734         if (!dta) {
00735                 ERR(policy, "Error appending type to analysis: %s", strerror(EINVAL));
00736                 errno = EINVAL;
00737                 return -1;
00738         }
00739 
00740         if (!type_name) {
00741                 apol_vector_destroy(&dta->access_types);
00742                 return 0;
00743         }
00744 
00745         if (!dta->access_types) {
00746                 if (!(dta->access_types = apol_vector_create(free))) {
00747                         error = errno;
00748                         ERR(policy, "%s", strerror(error));
00749                         errno = error;
00750                         return -1;
00751                 }
00752         }
00753 
00754         if (!(tmp = strdup(type_name))) {
00755                 error = errno;
00756                 ERR(policy, "%s", strerror(error));
00757                 errno = error;
00758                 return -1;
00759         }
00760 
00761         if (apol_vector_append(dta->access_types, tmp)) {
00762                 error = errno;
00763                 free(tmp);
00764                 ERR(policy, "%s", strerror(error));
00765                 errno = error;
00766                 return -1;
00767         }
00768 
00769         return 0;
00770 }
00771 
00772 int apol_domain_trans_analysis_append_class_perm(const apol_policy_t * policy, apol_domain_trans_analysis_t * dta,
00773                                                  const char *class_name, const char *perm_name)
00774 {
00775         if (apol_domain_trans_analysis_append_class(policy, dta, class_name))
00776                 return -1;
00777         return apol_domain_trans_analysis_append_perm(policy, dta, perm_name);
00778 }
00779 
00780 int apol_domain_trans_analysis_append_class(const apol_policy_t * policy, apol_domain_trans_analysis_t * dta,
00781                                             const char *class_name)
00782 {
00783         char *tmp = NULL;
00784         int error = 0;
00785 
00786         if (!dta) {
00787                 ERR(policy, "Error appending class to analysis: %s", strerror(EINVAL));
00788                 errno = EINVAL;
00789                 return -1;
00790         }
00791 
00792         if (!class_name) {
00793                 apol_vector_destroy(&dta->access_classes);
00794                 return 0;
00795         }
00796 
00797         if (!dta->access_classes) {
00798                 if (!(dta->access_classes = apol_vector_create(free))) {
00799                         error = errno;
00800                         ERR(policy, "%s", strerror(error));
00801                         errno = error;
00802                         return -1;
00803                 }
00804         }
00805 
00806         if (!(tmp = strdup(class_name))) {
00807                 error = errno;
00808                 ERR(policy, "%s", strerror(error));
00809                 errno = error;
00810                 return -1;
00811         }
00812 
00813         if (apol_vector_append(dta->access_classes, tmp)) {
00814                 error = errno;
00815                 free(tmp);
00816                 ERR(policy, "%s", strerror(error));
00817                 errno = error;
00818                 return -1;
00819         }
00820 
00821         return 0;
00822 }
00823 
00824 int apol_domain_trans_analysis_append_perm(const apol_policy_t * policy, apol_domain_trans_analysis_t * dta, const char *perm_name)
00825 {
00826         char *tmp = NULL;
00827         int error = 0;
00828 
00829         if (!dta) {
00830                 ERR(policy, "Error appending perm to analysis: %s", strerror(EINVAL));
00831                 errno = EINVAL;
00832                 return -1;
00833         }
00834 
00835         if (!perm_name) {
00836                 apol_vector_destroy(&dta->access_perms);
00837                 return 0;
00838         }
00839 
00840         if (!dta->access_perms) {
00841                 if (!(dta->access_perms = apol_vector_create(free))) {
00842                         error = errno;
00843                         ERR(policy, "%s", strerror(error));
00844                         errno = error;
00845                         return -1;
00846                 }
00847         }
00848 
00849         if (!(tmp = strdup(perm_name))) {
00850                 error = errno;
00851                 ERR(policy, "%s", strerror(error));
00852                 errno = error;
00853                 return -1;
00854         }
00855 
00856         if (apol_vector_append(dta->access_perms, tmp)) {
00857                 error = errno;
00858                 free(tmp);
00859                 ERR(policy, "%s", strerror(error));
00860                 errno = error;
00861                 return -1;
00862         }
00863 
00864         return 0;
00865 }
00866 
00867 static bool requires_setexec_or_type_trans(apol_policy_t * policy)
00868 {
00869         const qpol_policy_t *qp = apol_policy_get_qpol(policy);
00870         unsigned int policy_version = 0;
00871         qpol_policy_get_policy_version(qp, &policy_version);
00872         int is_modular = qpol_policy_has_capability(policy->p, QPOL_CAP_MODULES);
00873         return (policy_version >= 15 || is_modular);
00874 }
00875 
00876 struct rule_map_data
00877 {
00878         const qpol_type_t *search;
00879         const qpol_type_t *dflt;
00880         apol_vector_t *node_list;
00881         bool is_avnode;
00882 };
00883 
00884 static int node_list_map_fn(void *node, void *data)
00885 {
00886         struct rule_map_data *rm = data;
00887         if (rm->is_avnode) {
00888                 avrule_node_t *anode = node;
00889                 if (anode->type == rm->search && !anode->used)
00890                         if (apol_vector_append(rm->node_list, node))
00891                                 return -1;
00892                 return 0;
00893         } else {
00894                 terule_node_t *tnode = node;
00895                 if ((!rm->search || (rm->search == tnode->src)) && (!rm->dflt || (rm->dflt == tnode->dflt)) &&
00896                     rm->search != rm->dflt && !tnode->used)
00897                         if (apol_vector_append(rm->node_list, node))
00898                                 return -1;
00899                 return 0;
00900         }
00901 }
00902 
00903 static apol_vector_t *find_avrules_in_node(void *node, unsigned int rule_type, const qpol_type_t * search)
00904 {
00905         int error = 0;
00906         apol_vector_t *rule_nodes = apol_vector_create(NULL);   //shallow copies only
00907         struct rule_map_data data = { search, NULL, rule_nodes, true };
00908         switch (rule_type) {
00909         case APOL_DOMAIN_TRANS_RULE_PROC_TRANS:
00910         {
00911                 dom_node_t *dnode = node;
00912                 if (apol_bst_inorder_map(dnode->process_transition_tree, node_list_map_fn, (void *)&data) < 0) {
00913                         error = errno;
00914                         goto err;
00915                 }
00916                 break;
00917         }
00918         case APOL_DOMAIN_TRANS_RULE_ENTRYPOINT:
00919         {
00920                 dom_node_t *dnode = node;
00921                 if (apol_bst_inorder_map(dnode->entrypoint_tree, node_list_map_fn, (void *)&data) < 0) {
00922                         error = errno;
00923                         goto err;
00924                 }
00925                 break;
00926         }
00927         case APOL_DOMAIN_TRANS_RULE_EXEC:
00928         {
00929                 ep_node_t *enode = node;
00930                 if (apol_bst_inorder_map(enode->execute_tree, node_list_map_fn, (void *)&data) < 0) {
00931                         error = errno;
00932                         goto err;
00933                 }
00934                 break;
00935         }
00936         default:
00937         {
00938                 error = EINVAL;
00939                 goto err;
00940         }
00941         }
00942 
00943         return rule_nodes;
00944 
00945       err:
00946         apol_vector_destroy(&rule_nodes);
00947         errno = error;
00948         return NULL;
00949 }
00950 
00951 static apol_vector_t *find_terules_in_node(ep_node_t * node, const qpol_type_t * search, const qpol_type_t * dflt)
00952 {
00953         int error = 0;
00954         apol_vector_t *rule_nodes = apol_vector_create(NULL);   //shallow copies only
00955         struct rule_map_data data = { search, dflt, rule_nodes, false };
00956         if (apol_bst_inorder_map(node->type_transition_tree, node_list_map_fn, (void *)&data) < 0) {
00957                 error = errno;
00958                 goto err;
00959         }
00960 
00961         return rule_nodes;
00962 
00963       err:
00964         apol_vector_destroy(&rule_nodes);
00965         errno = error;
00966         return NULL;
00967 }
00968 
00969 static apol_domain_trans_result_t *find_result(apol_vector_t * local_results, const qpol_type_t * src, const qpol_type_t * tgt,
00970                                                const qpol_type_t * dflt)
00971 {
00972         for (size_t i = 0; i < apol_vector_get_size(local_results); i++) {
00973                 apol_domain_trans_result_t *res = apol_vector_get_element(local_results, i);
00974                 if (res->start_type == src && res->end_type == dflt && res->ep_type == tgt)
00975                         return res;
00976         }
00977         return NULL;
00978 }
00979 
00980 static int domain_trans_table_find_orphan_type_transitions(apol_policy_t * policy, apol_domain_trans_analysis_t * dta,
00981                                                            apol_vector_t * local_results)
00982 {
00983         int error = 0;
00984         const qpol_type_t *search = NULL;
00985         qpol_policy_get_type_by_name(apol_policy_get_qpol(policy), dta->start_type, &search);
00986         apol_domain_trans_result_t *tmp_result = NULL;
00987         //walk ep table
00988         apol_vector_t *epnodes = apol_bst_get_vector(policy->domain_trans_table->entrypoint_table, 0);
00989         if (!epnodes)
00990                 return -1;
00991         for (size_t i = 0; i < apol_vector_get_size(epnodes); i++) {
00992                 ep_node_t *node = apol_vector_get_element(epnodes, i);
00993                 //find any unused type transitions
00994                 apol_vector_t *ttnodes = NULL;
00995                 if (dta->direction == APOL_DOMAIN_TRANS_DIRECTION_FORWARD)
00996                         ttnodes = find_terules_in_node(node, search, NULL);
00997                 else
00998                         ttnodes = find_terules_in_node(node, NULL, search);
00999                 for (size_t j = 0; j < apol_vector_get_size(ttnodes); j++) {
01000                         bool add = false;
01001                         terule_node_t *tn = apol_vector_get_element(ttnodes, j);
01002                         tn->used = true;
01003                         //if missing an entrypoint rule this transition may have already been added to the results
01004                         tmp_result = find_result(local_results, tn->src, node->type, tn->dflt);
01005                         if (!tmp_result) {
01006                                 add = true;
01007                                 tmp_result = domain_trans_result_create();
01008                         }
01009                         if (!tmp_result) {
01010                                 error = errno;
01011                                 apol_vector_destroy(&ttnodes);
01012                                 goto err;
01013                         }
01014                         tmp_result->start_type = tn->src;
01015                         tmp_result->end_type = tn->dflt;
01016                         tmp_result->ep_type = node->type;
01017                         //check for exec
01018                         apol_vector_t *execrules =
01019                                 find_avrules_in_node((void *)node, APOL_DOMAIN_TRANS_RULE_EXEC, tmp_result->start_type);
01020                         for (size_t k = 0; k < apol_vector_get_size(execrules); k++) {
01021                                 avrule_node_t *n = apol_vector_get_element(execrules, k);
01022                                 if (apol_vector_append(tmp_result->exec_rules, (void *)n->rule)) {
01023                                         error = errno;
01024                                         apol_vector_destroy(&execrules);
01025                                         if (!add)
01026                                                 tmp_result = NULL;
01027                                         goto err;
01028                                 }
01029                         }
01030                         apol_vector_destroy(&execrules);
01031                         //check for proc_trans and setexec
01032                         dom_node_t dummy = { tmp_result->start_type, NULL, NULL, NULL };
01033                         dom_node_t *start_node = NULL;
01034                         apol_bst_get_element(policy->domain_trans_table->domain_table, (void *)&dummy, NULL, (void **)&start_node);
01035                         if (start_node) {
01036                                 //only copy setexec_rules if a new result will be added
01037                                 if (add && apol_vector_get_size(start_node->setexec_rules)) {
01038                                         if (apol_vector_cat(tmp_result->setexec_rules, start_node->setexec_rules)) {
01039                                                 error = errno;
01040                                                 goto err;
01041                                         }
01042                                 }
01043                                 //add any unused proc_trans rules
01044                                 apol_vector_t *proc_trans_rules =
01045                                         find_avrules_in_node((void *)start_node, APOL_DOMAIN_TRANS_RULE_PROC_TRANS,
01046                                                              tmp_result->end_type);
01047                                 for (size_t k = 0; k < apol_vector_get_size(proc_trans_rules); k++) {
01048                                         avrule_node_t *avr = apol_vector_get_element(proc_trans_rules, k);
01049                                         if (apol_vector_append(tmp_result->proc_trans_rules, (void *)avr->rule)) {
01050                                                 error = errno;
01051                                                 if (!add)
01052                                                         tmp_result = NULL;
01053                                                 apol_vector_destroy(&proc_trans_rules);
01054                                                 goto err;
01055                                         }
01056                                 }
01057                                 apol_vector_destroy(&proc_trans_rules);
01058                                 apol_vector_sort_uniquify(tmp_result->proc_trans_rules, NULL, NULL);
01059                         }
01060                         if (add) {
01061                                 if (apol_vector_append(local_results, (void *)tmp_result)) {
01062                                         error = errno;
01063                                         goto err;
01064                                 }
01065                         }
01066                         tmp_result = NULL;
01067                 }
01068                 apol_vector_destroy(&ttnodes);
01069         }
01070         apol_vector_destroy(&epnodes);
01071 
01072         return 0;
01073 
01074       err:
01075         apol_vector_destroy(&epnodes);
01076         apol_domain_trans_result_destroy(&tmp_result);
01077         errno = error;
01078         return -1;
01079 }
01080 
01081 static int domain_trans_table_get_all_forward_trans(apol_policy_t * policy, apol_domain_trans_analysis_t * dta,
01082                                                     apol_vector_t * local_results, const qpol_type_t * start_type)
01083 {
01084         int error = 0;
01085         //create template result this will hold common data for each step and be copied as needed
01086         apol_domain_trans_result_t *tmpl_result = domain_trans_result_create();
01087         if (!tmpl_result) {
01088                 error = errno;
01089                 goto err;
01090         }
01091         //find start node
01092         dom_node_t dummy = { start_type, NULL, NULL, NULL };
01093         dom_node_t *start_node = NULL;
01094         apol_bst_get_element(policy->domain_trans_table->domain_table, (void *)&dummy, NULL, (void **)&start_node);
01095         if (start_node) {
01096                 tmpl_result->start_type = start_type;
01097                 //if needed and present record setexec
01098                 if (requires_setexec_or_type_trans(policy) && apol_vector_get_size(start_node->setexec_rules)) {
01099                         if (apol_vector_cat(tmpl_result->setexec_rules, start_node->setexec_rules)) {
01100                                 error = errno;
01101                                 goto err;
01102                         }
01103                 }
01104                 //check all proc trans to build list of end types
01105                 apol_vector_t *proc_trans_rules = apol_bst_get_vector(start_node->process_transition_tree, 0);
01106                 apol_vector_t *potential_end_types = apol_vector_create(NULL);
01107                 for (size_t i = 0; i < apol_vector_get_size(proc_trans_rules); i++) {
01108                         avrule_node_t *ptnode = apol_vector_get_element(proc_trans_rules, i);
01109                         apol_vector_append(potential_end_types, (void *)ptnode->type);
01110                 }
01111                 apol_vector_destroy(&proc_trans_rules);
01112                 apol_vector_sort_uniquify(potential_end_types, NULL, NULL);
01113                 //for each end check ep
01114                 for (size_t i = 0; i < apol_vector_get_size(potential_end_types); i++) {
01115                         dummy.type = tmpl_result->end_type = apol_vector_get_element(potential_end_types, i);
01116                         dom_node_t *end_node = NULL;
01117                         apol_bst_get_element(policy->domain_trans_table->domain_table, (void *)&dummy, NULL, (void **)&end_node);
01118                         const qpol_type_t *end_type = dummy.type;
01119                         if (end_type == start_type)
01120                                 continue;
01121                         //get all proc trans rules for ths end (may be multiple due to attributes)
01122                         apol_vector_t *ptrules =
01123                                 find_avrules_in_node((void *)start_node, APOL_DOMAIN_TRANS_RULE_PROC_TRANS, end_type);
01124                         apol_vector_destroy(&tmpl_result->proc_trans_rules);
01125                         tmpl_result->proc_trans_rules = apol_vector_create(NULL);
01126                         for (size_t j = 0; j < apol_vector_get_size(ptrules); j++) {
01127                                 avrule_node_t *pt_ent = apol_vector_get_element(ptrules, j);
01128                                 pt_ent->used = true;
01129                                 if (apol_vector_append(tmpl_result->proc_trans_rules, (void *)pt_ent->rule)) {
01130                                         error = errno;
01131                                         apol_vector_destroy(&ptrules);
01132                                         apol_vector_destroy(&potential_end_types);
01133                                         goto err;
01134                                 }
01135                         }
01136                         apol_vector_destroy(&ptrules);
01137                         apol_vector_sort_uniquify(tmpl_result->proc_trans_rules, NULL, NULL);
01138                         if (end_node) {
01139                                 //collect potential entrypoint types
01140                                 apol_vector_t *eprules = apol_bst_get_vector(end_node->entrypoint_tree, 0);
01141                                 apol_vector_t *potential_ep_types = apol_vector_create(NULL);
01142                                 if (!eprules || !potential_ep_types) {
01143                                         error = errno;
01144                                         apol_vector_destroy(&eprules);
01145                                         apol_vector_destroy(&potential_end_types);
01146                                         goto err;
01147                                 }
01148                                 for (size_t j = 0; j < apol_vector_get_size(eprules); j++) {
01149                                         avrule_node_t *epr = apol_vector_get_element(eprules, j);
01150                                         if (apol_vector_append(potential_ep_types, (void *)epr->type)) {
01151                                                 error = errno;
01152                                                 apol_vector_destroy(&eprules);
01153                                                 apol_vector_destroy(&potential_end_types);
01154                                                 apol_vector_destroy(&potential_ep_types);
01155                                                 goto err;
01156                                         }
01157                                 }
01158                                 apol_vector_destroy(&eprules);
01159                                 apol_vector_sort_uniquify(potential_ep_types, NULL, NULL);
01160                                 //for each ep find exec by start
01161                                 for (size_t j = 0; j < apol_vector_get_size(potential_ep_types); j++) {
01162                                         tmpl_result->ep_type = apol_vector_get_element(potential_ep_types, j);
01163                                         ep_node_t edummy =
01164                                                 { (const qpol_type_t *)apol_vector_get_element(potential_ep_types, j), NULL, NULL };
01165                                         ep_node_t *epnode = NULL;
01166                                         apol_bst_get_element(policy->domain_trans_table->entrypoint_table, (void *)&edummy, NULL,
01167                                                              (void **)&epnode);
01168                                         //get all entrypoint rules for ths end (may be multiple due to attributes)
01169                                         apol_vector_destroy(&tmpl_result->ep_rules);
01170                                         tmpl_result->ep_rules = apol_vector_create(NULL);
01171                                         if (!tmpl_result->ep_rules) {
01172                                                 error = errno;
01173                                                 apol_vector_destroy(&potential_end_types);
01174                                                 apol_vector_destroy(&potential_ep_types);
01175                                                 goto err;
01176                                         }
01177                                         eprules = find_avrules_in_node((void *)end_node, APOL_DOMAIN_TRANS_RULE_ENTRYPOINT,
01178                                                                        tmpl_result->ep_type);
01179                                         for (size_t k = 0; k < apol_vector_get_size(eprules); k++) {
01180                                                 avrule_node_t *ep_ent = apol_vector_get_element(eprules, k);
01181                                                 ep_ent->used = true;
01182                                                 if (apol_vector_append(tmpl_result->ep_rules, (void *)ep_ent->rule)) {
01183                                                         error = errno;
01184                                                         apol_vector_destroy(&eprules);
01185                                                         apol_vector_destroy(&potential_end_types);
01186                                                         apol_vector_destroy(&potential_ep_types);
01187                                                         goto err;
01188                                                 }
01189                                         }
01190                                         apol_vector_destroy(&eprules);
01191                                         apol_vector_sort_uniquify(tmpl_result->ep_rules, NULL, NULL);
01192                                         if (epnode) {
01193                                                 //if present find tt
01194                                                 apol_vector_destroy(&tmpl_result->type_trans_rules);
01195                                                 tmpl_result->type_trans_rules = apol_vector_create(NULL);
01196                                                 if (!tmpl_result->type_trans_rules) {
01197                                                         error = errno;
01198                                                         apol_vector_destroy(&potential_end_types);
01199                                                         apol_vector_destroy(&potential_ep_types);
01200                                                         goto err;
01201                                                 }
01202                                                 apol_vector_t *ttrules = find_terules_in_node(epnode, start_type, end_type);
01203                                                 for (size_t l = 0; l < apol_vector_get_size(ttrules); l++) {
01204                                                         terule_node_t *tn = apol_vector_get_element(ttrules, l);
01205                                                         if (apol_vector_append(tmpl_result->type_trans_rules, (void *)tn->rule)) {
01206                                                                 error = errno;
01207                                                                 apol_vector_destroy(&ttrules);
01208                                                                 apol_vector_destroy(&potential_end_types);
01209                                                                 apol_vector_destroy(&potential_ep_types);
01210                                                                 goto err;
01211                                                         }
01212                                                 }
01213                                                 apol_vector_destroy(&ttrules);
01214                                                 apol_vector_sort_uniquify(tmpl_result->type_trans_rules, NULL, NULL);
01215                                                 //find execute rules
01216                                                 apol_vector_destroy(&tmpl_result->exec_rules);
01217                                                 tmpl_result->exec_rules = apol_vector_create(NULL);
01218                                                 if (!tmpl_result->exec_rules) {
01219                                                         error = errno;
01220                                                         apol_vector_destroy(&potential_end_types);
01221                                                         apol_vector_destroy(&potential_ep_types);
01222                                                         goto err;
01223                                                 }
01224                                                 apol_vector_t *execrules =
01225                                                         find_avrules_in_node(epnode, APOL_DOMAIN_TRANS_RULE_EXEC, start_type);
01226                                                 if (apol_vector_get_size(execrules)) {
01227                                                         for (size_t l = 0; l < apol_vector_get_size(execrules); l++) {
01228                                                                 avrule_node_t *xnode = apol_vector_get_element(execrules, l);
01229                                                                 //do not mark xnode as used here; it is valid to re-use it.
01230                                                                 if (apol_vector_append
01231                                                                     (tmpl_result->exec_rules, (void *)xnode->rule)) {
01232                                                                         error = errno;
01233                                                                         apol_vector_destroy(&execrules);
01234                                                                         apol_vector_destroy(&potential_end_types);
01235                                                                         apol_vector_destroy(&potential_ep_types);
01236                                                                         goto err;
01237                                                                 }
01238                                                         }
01239                                                         apol_vector_destroy(&execrules);
01240                                                         apol_vector_sort_uniquify(tmpl_result->exec_rules, NULL, NULL);
01241                                                         //found everything possible add a result
01242                                                         apol_domain_trans_result_t *tmp =
01243                                                                 apol_domain_trans_result_create_from_domain_trans_result
01244                                                                 (tmpl_result);
01245                                                         if (!tmp || apol_vector_append(local_results, (void *)tmp)) {
01246                                                                 error = errno;
01247                                                                 apol_domain_trans_result_destroy(&tmp);
01248                                                                 apol_vector_destroy(&potential_end_types);
01249                                                                 apol_vector_destroy(&potential_ep_types);
01250                                                                 goto err;
01251                                                         }
01252                                                         //reset execute rules
01253                                                         apol_vector_destroy(&tmpl_result->exec_rules);
01254                                                         tmpl_result->exec_rules = apol_vector_create(NULL);
01255                                                         if (!tmpl_result->exec_rules) {
01256                                                                 error = errno;
01257                                                                 apol_vector_destroy(&potential_end_types);
01258                                                                 apol_vector_destroy(&potential_ep_types);
01259                                                                 goto err;
01260                                                         }
01261                                                         //reset type transition rules
01262                                                         apol_vector_destroy(&tmpl_result->type_trans_rules);
01263                                                         tmpl_result->type_trans_rules = apol_vector_create(NULL);
01264                                                         if (!tmpl_result->type_trans_rules) {
01265                                                                 error = errno;
01266                                                                 apol_vector_destroy(&potential_end_types);
01267                                                                 apol_vector_destroy(&potential_ep_types);
01268                                                                 goto err;
01269                                                         }
01270                                                 } else {
01271                                                         //have proc_trans and entrypoint but no execute
01272                                                         apol_domain_trans_result_t *tmp =
01273                                                                 apol_domain_trans_result_create_from_domain_trans_result
01274                                                                 (tmpl_result);
01275                                                         if (!tmp || apol_vector_append(local_results, (void *)tmp)) {
01276                                                                 error = errno;
01277                                                                 apol_domain_trans_result_destroy(&tmp);
01278                                                                 apol_vector_destroy(&potential_end_types);
01279                                                                 apol_vector_destroy(&potential_ep_types);
01280                                                                 goto err;
01281                                                         }
01282                                                 }
01283                                                 apol_vector_destroy(&execrules);
01284                                         } else {
01285                                                 //have proc_trans and entrypoint but no execute
01286                                                 apol_domain_trans_result_t *tmp =
01287                                                         apol_domain_trans_result_create_from_domain_trans_result(tmpl_result);
01288                                                 if (!tmp || apol_vector_append(local_results, (void *)tmp)) {
01289                                                         error = errno;
01290                                                         apol_domain_trans_result_destroy(&tmp);
01291                                                         apol_vector_destroy(&potential_end_types);
01292                                                         apol_vector_destroy(&potential_ep_types);
01293                                                         goto err;
01294                                                 }
01295                                         }
01296                                         //reset entrypoint rules
01297                                         apol_vector_destroy(&tmpl_result->ep_rules);
01298                                         tmpl_result->ep_rules = apol_vector_create(NULL);
01299                                         if (!tmpl_result->ep_rules) {
01300                                                 error = errno;
01301                                                 apol_vector_destroy(&potential_end_types);
01302                                                 apol_vector_destroy(&potential_ep_types);
01303                                                 goto err;
01304                                         }
01305                                 }
01306                                 apol_vector_destroy(&potential_ep_types);
01307                         } else {
01308                                 //have proc_trans but end has no ep
01309                                 apol_domain_trans_result_t *tmp =
01310                                         apol_domain_trans_result_create_from_domain_trans_result(tmpl_result);
01311                                 if (!tmp || apol_vector_append(local_results, (void *)tmp)) {
01312                                         error = errno;
01313                                         apol_domain_trans_result_destroy(&tmp);
01314                                         goto err;
01315                                 }
01316                         }
01317                 }
01318                 apol_vector_destroy(&potential_end_types);
01319                 //validate all
01320                 for (size_t i = 0; i < apol_vector_get_size(local_results); i++) {
01321                         apol_domain_trans_result_t *res = apol_vector_get_element(local_results, i);
01322                         if (res->start_type && res->ep_type && res->end_type && apol_vector_get_size(res->proc_trans_rules) &&
01323                             apol_vector_get_size(res->ep_rules) && apol_vector_get_size(res->exec_rules) &&
01324                             (requires_setexec_or_type_trans(policy)
01325                              ? (apol_vector_get_size(res->setexec_rules) || apol_vector_get_size(res->type_trans_rules)) : true)) {
01326                                 res->valid = true;
01327                         }
01328                 }
01329         }
01330         //iff looking for invalid find orphan type_transition rules
01331         if (dta->valid & APOL_DOMAIN_TRANS_SEARCH_INVALID) {
01332                 if (domain_trans_table_find_orphan_type_transitions(policy, dta, local_results)) {
01333                         error = errno;
01334                         goto err;
01335                 }
01336         }
01337         apol_domain_trans_result_destroy(&tmpl_result);
01338 
01339         return 0;
01340       err:
01341         apol_domain_trans_result_destroy(&tmpl_result);
01342         errno = error;
01343         return -1;
01344 }
01345 
01346 static int domain_trans_table_get_all_reverse_trans(apol_policy_t * policy, apol_domain_trans_analysis_t * dta,
01347                                                     apol_vector_t * local_results, const qpol_type_t * end_type)
01348 {
01349         int error = 0;
01350         //create template result this will hold common data for each step and be copied as needed
01351         apol_domain_trans_result_t *tmpl_result = domain_trans_result_create();
01352         if (!tmpl_result) {
01353                 error = errno;
01354                 goto err;
01355         }
01356         //find end node
01357         dom_node_t dummy = { end_type, NULL, NULL, NULL };
01358         dom_node_t *end_node = NULL;
01359         apol_bst_get_element(policy->domain_trans_table->domain_table, (void *)&dummy, NULL, (void **)&end_node);
01360         if (end_node) {
01361                 tmpl_result->end_type = end_type;
01362                 //collect potential entrypoint types
01363                 apol_vector_t *eprules = apol_bst_get_vector(end_node->entrypoint_tree, 0);
01364                 apol_vector_t *potential_ep_types = apol_vector_create(NULL);
01365                 if (!eprules || !potential_ep_types) {
01366                         error = errno;
01367                         apol_vector_destroy(&eprules);
01368                         goto err;
01369                 }
01370                 for (size_t j = 0; j < apol_vector_get_size(eprules); j++) {
01371                         avrule_node_t *epr = apol_vector_get_element(eprules, j);
01372                         if (apol_vector_append(potential_ep_types, (void *)epr->type)) {
01373                                 error = errno;
01374                                 apol_vector_destroy(&eprules);
01375                                 apol_vector_destroy(&potential_ep_types);
01376                                 goto err;
01377                         }
01378                 }
01379                 apol_vector_destroy(&eprules);
01380                 apol_vector_sort_uniquify(potential_ep_types, NULL, NULL);
01381                 for (size_t i = 0; i < apol_vector_get_size(potential_ep_types); i++) {
01382                         tmpl_result->ep_type = apol_vector_get_element(potential_ep_types, i);
01383                         //get all ep rules for this end (may be multiple due to attributes)
01384                         eprules = find_avrules_in_node((void *)end_node, APOL_DOMAIN_TRANS_RULE_ENTRYPOINT, tmpl_result->ep_type);
01385                         apol_vector_destroy(&tmpl_result->ep_rules);
01386                         tmpl_result->ep_rules = apol_vector_create(NULL);
01387                         for (size_t j = 0; j < apol_vector_get_size(eprules); j++) {
01388                                 avrule_node_t *ep_ent = apol_vector_get_element(eprules, j);
01389                                 ep_ent->used = true;
01390                                 if (apol_vector_append(tmpl_result->ep_rules, (void *)ep_ent->rule)) {
01391                                         error = errno;
01392                                         apol_vector_destroy(&eprules);
01393                                         apol_vector_destroy(&potential_ep_types);
01394                                         goto err;
01395                                 }
01396                         }
01397                         apol_vector_destroy(&eprules);
01398                         apol_vector_sort_uniquify(tmpl_result->ep_rules, NULL, NULL);
01399                         ep_node_t edummy = { tmpl_result->ep_type, NULL, NULL };
01400                         ep_node_t *epnode = NULL;
01401                         apol_bst_get_element(policy->domain_trans_table->entrypoint_table, (void *)&edummy, NULL, (void **)&epnode);
01402                         //for each ep find exec rules to generate list of potential start types
01403                         if (epnode) {
01404                                 apol_vector_t *execrules = apol_bst_get_vector(epnode->execute_tree, 0);
01405                                 apol_vector_t *potential_start_types = apol_vector_create(NULL);
01406                                 if (!execrules || !potential_start_types) {
01407                                         error = errno;
01408                                         apol_vector_destroy(&execrules);
01409                                         goto err;
01410                                 }
01411                                 for (size_t k = 0; k < apol_vector_get_size(execrules); k++) {
01412                                         avrule_node_t *n = apol_vector_get_element(execrules, k);
01413                                         if (apol_vector_append(potential_start_types, (void *)n->type)) {
01414                                                 error = errno;
01415                                                 apol_vector_destroy(&execrules);
01416                                                 apol_vector_destroy(&potential_start_types);
01417                                                 apol_vector_destroy(&potential_ep_types);
01418                                                 goto err;
01419                                         }
01420                                 }
01421                                 apol_vector_destroy(&execrules);
01422                                 apol_vector_sort_uniquify(potential_start_types, NULL, NULL);
01423                                 for (size_t k = 0; k < apol_vector_get_size(potential_start_types); k++) {
01424                                         tmpl_result->start_type = apol_vector_get_element(potential_start_types, k);
01425                                         //no transition to self
01426                                         if (tmpl_result->end_type == tmpl_result->start_type)
01427                                                 continue;
01428                                         //get all execute rule for this start type
01429                                         apol_vector_t *exec_rules =
01430                                                 find_avrules_in_node((void *)epnode, APOL_DOMAIN_TRANS_RULE_EXEC,
01431                                                                      tmpl_result->start_type);
01432                                         apol_vector_destroy(&tmpl_result->exec_rules);
01433                                         tmpl_result->exec_rules = apol_vector_create(NULL);
01434                                         for (size_t l = 0; l < apol_vector_get_size(exec_rules); l++) {
01435                                                 avrule_node_t *n = apol_vector_get_element(exec_rules, l);
01436                                                 n->used = true;
01437                                                 if (apol_vector_append(tmpl_result->exec_rules, (void *)n->rule)) {
01438                                                         error = errno;
01439                                                         apol_vector_destroy(&exec_rules);
01440                                                         apol_vector_destroy(&potential_start_types);
01441                                                         apol_vector_destroy(&potential_ep_types);
01442                                                         goto err;
01443                                                 }
01444                                         }
01445                                         apol_vector_destroy(&exec_rules);
01446                                         apol_vector_sort_uniquify(tmpl_result->exec_rules, NULL, NULL);
01447                                         //check for type transition rules
01448                                         apol_vector_t *ttrules =
01449                                                 find_terules_in_node(epnode, tmpl_result->start_type, tmpl_result->end_type);
01450                                         apol_vector_destroy(&tmpl_result->type_trans_rules);
01451                                         tmpl_result->type_trans_rules = apol_vector_create(NULL);
01452                                         if (!tmpl_result->type_trans_rules) {
01453                                                 error = errno;
01454                                                 apol_vector_destroy(&ttrules);
01455                                                 apol_vector_destroy(&potential_start_types);
01456                                                 apol_vector_destroy(&potential_ep_types);
01457                                                 goto err;
01458                                         }
01459                                         for (size_t l = 0; l < apol_vector_get_size(ttrules); l++) {
01460                                                 terule_node_t *n = apol_vector_get_element(ttrules, l);
01461                                                 n->used = true;
01462                                                 if (apol_vector_append(tmpl_result->type_trans_rules, (void *)n->rule)) {
01463                                                         error = errno;
01464                                                         apol_vector_destroy(&ttrules);
01465                                                         apol_vector_destroy(&potential_start_types);
01466                                                         apol_vector_destroy(&potential_ep_types);
01467                                                         goto err;
01468                                                 }
01469                                         }
01470                                         apol_vector_destroy(&ttrules);
01471                                         apol_vector_sort_uniquify(tmpl_result->type_trans_rules, NULL, NULL);
01472                                         dummy.type = tmpl_result->start_type;
01473                                         dom_node_t *start_node = NULL;
01474                                         apol_bst_get_element(policy->domain_trans_table->domain_table, (void *)&dummy, NULL,
01475                                                              (void **)&start_node);
01476                                         if (start_node) {
01477                                                 //for each start check setexec if needed
01478                                                 if (requires_setexec_or_type_trans(policy)) {
01479                                                         apol_vector_destroy(&tmpl_result->setexec_rules);
01480                                                         tmpl_result->setexec_rules = apol_vector_create(NULL);
01481                                                         if (!tmpl_result->setexec_rules ||
01482                                                             apol_vector_cat(tmpl_result->setexec_rules,
01483                                                                             start_node->setexec_rules)) {
01484                                                                 error = errno;
01485                                                                 apol_vector_destroy(&potential_start_types);
01486                                                                 apol_vector_destroy(&potential_ep_types);
01487                                                                 goto err;
01488                                                         }
01489                                                 }
01490                                                 //for each start find pt
01491                                                 apol_vector_destroy(&tmpl_result->proc_trans_rules);
01492                                                 tmpl_result->proc_trans_rules = apol_vector_create(NULL);
01493                                                 if (!tmpl_result->proc_trans_rules) {
01494                                                         error = errno;
01495                                                         apol_vector_destroy(&potential_start_types);
01496                                                         apol_vector_destroy(&potential_ep_types);
01497                                                         goto err;
01498                                                 }
01499                                                 apol_vector_t *pt_rules = NULL;
01500                                                 pt_rules =
01501                                                         find_avrules_in_node(start_node, APOL_DOMAIN_TRANS_RULE_PROC_TRANS,
01502                                                                              tmpl_result->end_type);
01503                                                 if (apol_vector_get_size(pt_rules)) {
01504                                                         for (size_t l = 0; l < apol_vector_get_size(pt_rules); l++) {
01505                                                                 avrule_node_t *n = apol_vector_get_element(pt_rules, l);
01506                                                                 apol_vector_append(tmpl_result->proc_trans_rules, (void *)n->rule);
01507                                                         }
01508                                                         apol_vector_destroy(&pt_rules);
01509                                                         apol_vector_sort_uniquify(tmpl_result->proc_trans_rules, NULL, NULL);
01510                                                         // have all possible rules add this entry
01511                                                         apol_domain_trans_result_t *tmp =
01512                                                                 apol_domain_trans_result_create_from_domain_trans_result
01513                                                                 (tmpl_result);
01514                                                         if (!tmp || apol_vector_append(local_results, (void *)tmp)) {
01515                                                                 error = errno;
01516                                                                 apol_domain_trans_result_destroy(&tmp);
01517                                                                 apol_vector_destroy(&potential_start_types);
01518                                                                 apol_vector_destroy(&potential_ep_types);
01519                                                                 goto err;
01520                                                         }
01521                                                         //reset process transition rules
01522                                                         apol_vector_destroy(&tmpl_result->proc_trans_rules);
01523                                                         tmpl_result->proc_trans_rules = apol_vector_create(NULL);
01524                                                         if (!tmpl_result->proc_trans_rules) {
01525                                                                 error = errno;
01526                                                                 apol_vector_destroy(&potential_start_types);
01527                                                                 apol_vector_destroy(&potential_ep_types);
01528                                                                 goto err;
01529                                                         }
01530                                                         //reset setexec rules
01531                                                         apol_vector_destroy(&tmpl_result->setexec_rules);
01532                                                         tmpl_result->setexec_rules = apol_vector_create(NULL);
01533                                                         if (!tmpl_result->setexec_rules) {
01534                                                                 error = errno;
01535                                                                 apol_vector_destroy(&potential_start_types);
01536                                                                 apol_vector_destroy(&potential_ep_types);
01537                                                                 goto err;
01538                                                         }
01539                                                 } else {
01540                                                         //have entrypoint and execute rules but no process transition rule
01541                                                         apol_domain_trans_result_t *tmp =
01542                                                                 apol_domain_trans_result_create_from_domain_trans_result
01543                                                                 (tmpl_result);
01544                                                         if (!tmp || apol_vector_append(local_results, (void *)tmp)) {
01545                                                                 error = errno;
01546                                                                 apol_domain_trans_result_destroy(&tmp);
01547                                                                 apol_vector_destroy(&potential_start_types);
01548                                                                 apol_vector_destroy(&potential_ep_types);
01549                                                                 apol_vector_destroy(&pt_rules);
01550                                                                 goto err;
01551                                                         }
01552                                                 }
01553                                                 apol_vector_destroy(&pt_rules);
01554                                         } else {
01555                                                 //have entrypoint and execute rules but no process transition rule
01556                                                 apol_domain_trans_result_t *tmp =
01557                                                         apol_domain_trans_result_create_from_domain_trans_result(tmpl_result);
01558                                                 if (!tmp || apol_vector_append(local_results, (void *)tmp)) {
01559                                                         error = errno;
01560                                                         apol_domain_trans_result_destroy(&tmp);
01561                                                         apol_vector_destroy(&potential_start_types);
01562                                                         apol_vector_destroy(&potential_ep_types);
01563                                                         goto err;
01564                                                 }
01565                                         }
01566                                         //reset execute rules
01567                                         apol_vector_destroy(&tmpl_result->exec_rules);
01568                                         tmpl_result->exec_rules = apol_vector_create(NULL);
01569                                         if (!tmpl_result->exec_rules) {
01570                                                 error = errno;
01571                                                 apol_vector_destroy(&potential_start_types);
01572                                                 apol_vector_destroy(&potential_ep_types);
01573                                                 goto err;
01574                                         }
01575                                         //reset type transition rules
01576                                         apol_vector_destroy(&tmpl_result->type_trans_rules);
01577                                         tmpl_result->type_trans_rules = apol_vector_create(NULL);
01578                                         if (!tmpl_result->type_trans_rules) {
01579                                                 error = errno;
01580                                                 apol_vector_destroy(&potential_start_types);
01581                                                 apol_vector_destroy(&potential_ep_types);
01582                                                 goto err;
01583                                         }
01584                                 }
01585                                 apol_vector_destroy(&potential_start_types);
01586                         } else {
01587                                 //have entrypoint but no exec
01588                                 apol_domain_trans_result_t *tmp =
01589                                         apol_domain_trans_result_create_from_domain_trans_result(tmpl_result);
01590                                 if (!tmp || apol_vector_append(local_results, (void *)tmp)) {
01591                                         error = errno;
01592                                         apol_domain_trans_result_destroy(&tmp);
01593                                         goto err;
01594                                 }
01595                         }
01596                 }
01597                 apol_vector_destroy(&potential_ep_types);
01598 
01599                 //validate all
01600                 for (size_t i = 0; i < apol_vector_get_size(local_results); i++) {
01601                         apol_domain_trans_result_t *res = apol_vector_get_element(local_results, i);
01602                         if (res->start_type && res->ep_type && res->end_type && apol_vector_get_size(res->proc_trans_rules) &&
01603                             apol_vector_get_size(res->ep_rules) && apol_vector_get_size(res->exec_rules) &&
01604                             (requires_setexec_or_type_trans(policy)
01605                              ? (apol_vector_get_size(res->setexec_rules) || apol_vector_get_size(res->type_trans_rules)) : true)) {
01606                                 res->valid = true;
01607                         }
01608                 }
01609         }
01610         //iff looking for invalid find orphan type_transition rules
01611         if (dta->valid & APOL_DOMAIN_TRANS_SEARCH_INVALID) {
01612                 if (domain_trans_table_find_orphan_type_transitions(policy, dta, local_results)) {
01613                         error = errno;
01614                         goto err;
01615                 }
01616         }
01617 
01618         apol_domain_trans_result_destroy(&tmpl_result);
01619         return 0;
01620 
01621       err:
01622         apol_domain_trans_result_destroy(&tmpl_result);
01623         errno = error;
01624         return -1;
01625 }
01626 
01627 int apol_domain_trans_analysis_do(apol_policy_t * policy, apol_domain_trans_analysis_t * dta, apol_vector_t ** results)
01628 {
01629         apol_vector_t *local_results = NULL;
01630         apol_avrule_query_t *accessq = NULL;
01631         int error = 0;
01632         if (!results)
01633                 *results = NULL;
01634         if (!policy || !dta || !results) {
01635                 ERR(policy, "%s", strerror(EINVAL));
01636                 errno = EINVAL;
01637                 return -1;
01638         }
01639 
01640         /* build table if not already present */
01641         if (!(policy->domain_trans_table)) {
01642                 if (apol_policy_build_domain_trans_table(policy))
01643                         return -1;     /* errors already reported by build function */
01644         }
01645 
01646         /* validate analysis options */
01647         if (dta->direction == 0 || dta->valid & ~(APOL_DOMAIN_TRANS_SEARCH_BOTH) || !(dta->start_type)) {
01648                 error = EINVAL;
01649                 ERR(policy, "%s", strerror(EINVAL));
01650                 goto err;
01651         }
01652         size_t num_atypes = apol_vector_get_size(dta->access_types);
01653         size_t num_aclasses = apol_vector_get_size(dta->access_classes);
01654         size_t num_aprems = apol_vector_get_size(dta->access_perms);
01655         if ((num_atypes == 0 && (num_aclasses != 0 || num_aprems != 0)) ||
01656             (num_aclasses == 0 && (num_atypes != 0 || num_aprems != 0)) ||
01657             (num_aprems == 0 && (num_aclasses != 0 || num_atypes != 0))) {
01658                 error = EINVAL;
01659                 ERR(policy, "%s", strerror(EINVAL));
01660                 goto err;
01661         }
01662 
01663         /* get starting type */
01664         const qpol_type_t *start_type = NULL;
01665         if (qpol_policy_get_type_by_name(policy->p, dta->start_type, &start_type)) {
01666                 error = errno;
01667                 ERR(policy, "Unable to perform analysis: Invalid starting type %s", dta->start_type);
01668                 goto err;
01669         }
01670         unsigned char isattr = 0;
01671         qpol_type_get_isattr(policy->p, start_type, &isattr);
01672         if (isattr) {
01673                 ERR(policy, "%s", "Attributes are not valid here.");
01674                 error = EINVAL;
01675                 goto err;
01676         }
01677 
01678         local_results = apol_vector_create(domain_trans_result_free);
01679         /* get all transitions for the requested direction */
01680         if (dta->direction == APOL_DOMAIN_TRANS_DIRECTION_REVERSE) {
01681                 if (domain_trans_table_get_all_reverse_trans(policy, dta, local_results, start_type)) {
01682                         error = errno;
01683                         goto err;
01684                 }
01685         } else {
01686                 if (domain_trans_table_get_all_forward_trans(policy, dta, local_results, start_type)) {
01687                         error = errno;
01688                         goto err;
01689                 }
01690         }
01691 
01692         /* if requested, filter by validity */
01693         if (dta->valid != APOL_DOMAIN_TRANS_SEARCH_BOTH) {
01694                 for (size_t i = 0; i < apol_vector_get_size(local_results); /* increment later */ ) {
01695                         apol_domain_trans_result_t *res = apol_vector_get_element(local_results, i);
01696                         if (res->valid != (dta->valid == APOL_DOMAIN_TRANS_SEARCH_VALID)) {
01697                                 apol_vector_remove(local_results, i);
01698                                 domain_trans_result_free(res);
01699                         } else {
01700                                 i++;
01701                         }
01702                 }
01703         }
01704 
01705         /* if filtering by result type, do that now */
01706         if (dta->result) {
01707                 for (size_t i = 0; i < apol_vector_get_size(local_results); /* increment later */ ) {
01708                         apol_domain_trans_result_t *res = apol_vector_get_element(local_results, i);
01709                         const qpol_type_t *type = NULL;
01710                         if (dta->direction == APOL_DOMAIN_TRANS_DIRECTION_REVERSE) {
01711                                 type = res->start_type;
01712                         } else {
01713                                 type = res->end_type;
01714                         }
01715                         int compval = apol_compare_type(policy, type, dta->result, APOL_QUERY_REGEX, &dta->result_regex);
01716                         if (compval < 0) {
01717                                 error = errno;
01718                                 goto err;
01719                         } else if (compval > 0) {
01720                                 i++;
01721                         } else {
01722                                 apol_vector_remove(local_results, i);
01723                                 domain_trans_result_free(res);
01724                         }
01725                 }
01726         }
01727 
01728         /* finally do access filtering */
01729         if (dta->direction == APOL_DOMAIN_TRANS_DIRECTION_FORWARD && num_atypes && num_aclasses && num_aprems) {
01730                 accessq = apol_avrule_query_create();
01731                 apol_avrule_query_set_rules(policy, accessq, QPOL_RULE_ALLOW);
01732                 for (size_t i = 0; i < num_aclasses; i++) {
01733                         if (apol_avrule_query_append_class
01734                             (policy, accessq, (char *)apol_vector_get_element(dta->access_classes, i))) {
01735                                 error = errno;
01736                                 goto err;
01737                         }
01738                 }
01739                 for (size_t i = 0; i < num_aprems; i++) {
01740                         if (apol_avrule_query_append_perm(policy, accessq, (char *)apol_vector_get_element(dta->access_perms, i))) {
01741                                 error = errno;
01742                                 goto err;
01743                         }
01744                 }
01745                 for (size_t i = 0; i < apol_vector_get_size(local_results); /* increment later */ ) {
01746                         const char *end_name = NULL;
01747                         apol_domain_trans_result_t *res = apol_vector_get_element(local_results, i);
01748                         if (qpol_type_get_name(apol_policy_get_qpol(policy), res->end_type, &end_name) ||
01749                             apol_avrule_query_set_source(policy, accessq, end_name, 1)) {
01750                                 error = errno;
01751                                 goto err;
01752                         }
01753                         apol_vector_t *tmp_access = apol_vector_create(NULL);
01754                         for (size_t j = 0; j < num_atypes; j++) {
01755                                 if (apol_avrule_query_set_target
01756                                     (policy, accessq, (char *)apol_vector_get_element(dta->access_types, j), 1)) {
01757                                         error = errno;
01758                                         apol_vector_destroy(&tmp_access);
01759                                         goto err;
01760                                 }
01761                                 apol_vector_t *cur_tgt_v = NULL;
01762                                 apol_avrule_get_by_query(policy, accessq, &cur_tgt_v);
01763                                 apol_vector_cat(tmp_access, cur_tgt_v);
01764                                 apol_vector_destroy(&cur_tgt_v);
01765                         }
01766                         if (apol_vector_get_size(tmp_access)) {
01767                                 res->access_rules = tmp_access;
01768                                 tmp_access = NULL;
01769                                 i++;
01770                         } else {
01771                                 apol_vector_remove(local_results, i);
01772                                 domain_trans_result_free(res);
01773                         }
01774                         apol_vector_destroy(&tmp_access);
01775                 }
01776                 apol_avrule_query_destroy(&accessq);
01777         }
01778 
01779         *results = apol_vector_create(domain_trans_result_free);
01780         if (!(*results)) {
01781                 error = errno;
01782                 goto err;
01783         }
01784         for (size_t i = 0; i < apol_vector_get_size(local_results); i++) {
01785                 apol_domain_trans_result_t *res =
01786                         apol_domain_trans_result_create_from_domain_trans_result((apol_domain_trans_result_t *)
01787                                                                                  apol_vector_get_element(local_results, i));
01788                 if (!res || apol_vector_append(*results, (void *)res)) {
01789                         error = errno;
01790                         domain_trans_result_free(res);
01791                         goto err;
01792                 }
01793         }
01794         apol_vector_destroy(&local_results);
01795 
01796         return 0;
01797       err:
01798         apol_vector_destroy(&local_results);
01799         apol_vector_destroy(results);
01800         apol_avrule_query_destroy(&accessq);
01801         errno = error;
01802         return -1;
01803 }
01804 
01805 /* result */
01806 
01807 const qpol_type_t *apol_domain_trans_result_get_start_type(const apol_domain_trans_result_t * dtr)
01808 {
01809         if (dtr) {
01810                 return dtr->start_type;
01811         } else {
01812                 errno = EINVAL;
01813                 return NULL;
01814         }
01815 }
01816 
01817 const qpol_type_t *apol_domain_trans_result_get_entrypoint_type(const apol_domain_trans_result_t * dtr)
01818 {
01819         if (dtr) {
01820                 return dtr->ep_type;
01821         } else {
01822                 errno = EINVAL;
01823                 return NULL;
01824         }
01825 }
01826 
01827 const qpol_type_t *apol_domain_trans_result_get_end_type(const apol_domain_trans_result_t * dtr)
01828 {
01829         if (dtr) {
01830                 return dtr->end_type;
01831         } else {
01832                 errno = EINVAL;
01833                 return NULL;
01834         }
01835 }
01836 
01837 const apol_vector_t *apol_domain_trans_result_get_proc_trans_rules(const apol_domain_trans_result_t * dtr)
01838 {
01839         if (dtr) {
01840                 return dtr->proc_trans_rules;
01841         } else {
01842                 errno = EINVAL;
01843                 return NULL;
01844         }
01845 }
01846 
01847 const apol_vector_t *apol_domain_trans_result_get_entrypoint_rules(const apol_domain_trans_result_t * dtr)
01848 {
01849         if (dtr) {
01850                 return dtr->ep_rules;
01851         } else {
01852                 errno = EINVAL;
01853                 return NULL;
01854         }
01855 }
01856 
01857 const apol_vector_t *apol_domain_trans_result_get_exec_rules(const apol_domain_trans_result_t * dtr)
01858 {
01859         if (dtr) {
01860                 return dtr->exec_rules;
01861         } else {
01862                 errno = EINVAL;
01863                 return NULL;
01864         }
01865 }
01866 
01867 const apol_vector_t *apol_domain_trans_result_get_setexec_rules(const apol_domain_trans_result_t * dtr)
01868 {
01869         if (dtr) {
01870                 return dtr->setexec_rules;
01871         } else {
01872                 errno = EINVAL;
01873                 return NULL;
01874         }
01875 }
01876 
01877 const apol_vector_t *apol_domain_trans_result_get_type_trans_rules(const apol_domain_trans_result_t * dtr)
01878 {
01879         if (dtr) {
01880                 return dtr->type_trans_rules;
01881         } else {
01882                 errno = EINVAL;
01883                 return NULL;
01884         }
01885 }
01886 
01887 int apol_domain_trans_result_is_trans_valid(const apol_domain_trans_result_t * dtr)
01888 {
01889         if (dtr) {
01890                 return dtr->valid;
01891         } else {
01892                 errno = EINVAL;
01893                 return 0;
01894         }
01895 }
01896 
01897 const apol_vector_t *apol_domain_trans_result_get_access_rules(const apol_domain_trans_result_t * dtr)
01898 {
01899         if (dtr) {
01900                 return dtr->access_rules;
01901         } else {
01902                 errno = EINVAL;
01903                 return NULL;
01904         }
01905 }
01906 
01907 int apol_domain_trans_table_verify_trans(apol_policy_t * policy, const qpol_type_t * start_dom, const qpol_type_t * ep_type,
01908                                          const qpol_type_t * end_dom)
01909 {
01910         int missing_rules = 0;
01911 
01912         if (!policy || !policy->domain_trans_table) {
01913                 errno = EINVAL;
01914                 return -1;
01915         }
01916         //reset the table
01917         apol_policy_reset_domain_trans_table(policy);
01918         //find nodes for each type
01919         dom_node_t start_dummy = { start_dom, NULL, NULL, NULL };
01920         dom_node_t *start_node = NULL;
01921         if (start_dom)
01922                 apol_bst_get_element(policy->domain_trans_table->domain_table, (void *)&start_dummy, NULL, (void **)&start_node);
01923         ep_node_t ep_dummy = { ep_type, NULL, NULL };
01924         ep_node_t *ep_node = NULL;
01925         if (ep_type)
01926                 apol_bst_get_element(policy->domain_trans_table->entrypoint_table, (void *)&ep_dummy, NULL, (void **)&ep_node);
01927         dom_node_t end_dummy = { end_dom, NULL, NULL, NULL };
01928         dom_node_t *end_node = NULL;
01929         if (end_dom)
01930                 apol_bst_get_element(policy->domain_trans_table->domain_table, (void *)&end_dummy, NULL, (void **)&end_node);
01931 
01932         bool tt = false, sx = false, ex = false, pt = false, ep = false;
01933 
01934         //find process transition rule
01935         if (start_node && end_dom) {
01936                 apol_vector_t *v = find_avrules_in_node(start_node, APOL_DOMAIN_TRANS_RULE_PROC_TRANS, end_dom);
01937                 if (apol_vector_get_size(v))
01938                         pt = true;
01939                 apol_vector_destroy(&v);
01940         }
01941         //find execute rule
01942         if (start_dom && ep_node) {
01943                 apol_vector_t *v = find_avrules_in_node(ep_node, APOL_DOMAIN_TRANS_RULE_EXEC, start_dom);
01944                 if (apol_vector_get_size(v))
01945                         ex = true;
01946                 apol_vector_destroy(&v);
01947         }
01948         //find entrypoint rules
01949         if (end_node && ep_type) {
01950                 apol_vector_t *v = find_avrules_in_node(end_node, APOL_DOMAIN_TRANS_RULE_ENTRYPOINT, ep_type);
01951                 if (apol_vector_get_size(v))
01952                         ep = true;
01953                 apol_vector_destroy(&v);
01954         }
01955         if (requires_setexec_or_type_trans(policy)) {
01956                 //find setexec rule
01957                 if (start_node)
01958                         if (apol_vector_get_size(start_node->setexec_rules))
01959                                 sx = true;
01960                 //find type_transition rule
01961                 if (ep_node && start_dom && end_dom) {
01962                         apol_vector_t *v = find_terules_in_node(ep_node, start_dom, end_dom);
01963                         if (apol_vector_get_size(v)) {
01964                                 tt = true;
01965                         }
01966                         apol_vector_destroy(&v);
01967                 }
01968         } else {
01969                 //old policy version - pretend these exist
01970                 tt = sx = true;
01971         }
01972 
01973         if (!(pt && ep && ex && (tt || sx))) {
01974                 if (!pt)
01975                         missing_rules |= APOL_DOMAIN_TRANS_RULE_PROC_TRANS;
01976                 if (!ep)
01977                         missing_rules |= APOL_DOMAIN_TRANS_RULE_ENTRYPOINT;
01978                 if (!ex)
01979                         missing_rules |= APOL_DOMAIN_TRANS_RULE_EXEC;
01980                 if (!tt && !sx) {
01981                         missing_rules |= APOL_DOMAIN_TRANS_RULE_SETEXEC;
01982                         //do not report type_transition as missing if there is one for another entrypoint as this would be invalid
01983                         const char *start_name = NULL, *end_name = NULL;
01984                         qpol_type_get_name(apol_policy_get_qpol(policy), start_dom, &start_name);
01985                         qpol_type_get_name(apol_policy_get_qpol(policy), end_dom, &end_name);
01986                         apol_terule_query_t *tq = NULL;
01987                         if (!start_name || !end_name || !(tq = apol_terule_query_create())) {
01988                                 return -1;
01989                         }
01990                         apol_terule_query_set_rules(policy, tq, QPOL_RULE_TYPE_TRANS);
01991                         apol_terule_query_set_source(policy, tq, start_name, 1);
01992                         apol_terule_query_set_default(policy, tq, end_name);
01993                         apol_vector_t *v = NULL;
01994                         if (apol_terule_get_by_query(policy, tq, &v)) {
01995                                 apol_terule_query_destroy(&tq);
01996                                 return -1;
01997                         }
01998                         apol_terule_query_destroy(&tq);
01999                         if (!apol_vector_get_size(v))
02000                                 missing_rules |= APOL_DOMAIN_TRANS_RULE_TYPE_TRANS;
02001                         apol_vector_destroy(&v);
02002                 }
02003         }
02004 
02005         return missing_rules;
02006 }
02007 
02008 apol_domain_trans_result_t *apol_domain_trans_result_create_from_domain_trans_result(const apol_domain_trans_result_t * result)
02009 {
02010         apol_domain_trans_result_t *new_r = NULL;
02011         int retval = -1;
02012         if ((new_r = calloc(1, sizeof(*new_r))) == NULL) {
02013                 goto cleanup;
02014         }
02015         if (result->proc_trans_rules != NULL &&
02016             (new_r->proc_trans_rules = apol_vector_create_from_vector(result->proc_trans_rules, NULL, NULL, NULL)) == NULL) {
02017                 goto cleanup;
02018         }
02019         if (result->ep_rules != NULL
02020             && (new_r->ep_rules = apol_vector_create_from_vector(result->ep_rules, NULL, NULL, NULL)) == NULL) {
02021                 goto cleanup;
02022         }
02023         if (result->exec_rules != NULL
02024             && (new_r->exec_rules = apol_vector_create_from_vector(result->exec_rules, NULL, NULL, NULL)) == NULL) {
02025                 goto cleanup;
02026         }
02027         if (result->setexec_rules != NULL
02028             && (new_r->setexec_rules = apol_vector_create_from_vector(result->setexec_rules, NULL, NULL, NULL)) == NULL) {
02029                 goto cleanup;
02030         }
02031         if (result->type_trans_rules != NULL &&
02032             (new_r->type_trans_rules = apol_vector_create_from_vector(result->type_trans_rules, NULL, NULL, NULL)) == NULL) {
02033                 goto cleanup;
02034         }
02035         if (result->access_rules != NULL
02036             && (new_r->access_rules = apol_vector_create_from_vector(result->access_rules, NULL, NULL, NULL)) == NULL) {
02037                 goto cleanup;
02038         }
02039         new_r->start_type = result->start_type;
02040         new_r->ep_type = result->ep_type;
02041         new_r->end_type = result->end_type;
02042         new_r->valid = result->valid;
02043         retval = 0;
02044       cleanup:
02045         if (retval != 0) {
02046                 domain_trans_result_free(new_r);
02047                 return NULL;
02048         }
02049         return new_r;
02050 }
02051 
02052 /******************** protected functions ********************/
02053 
02054 void domain_trans_result_free(void *dtr)
02055 {
02056         apol_domain_trans_result_t *res = (apol_domain_trans_result_t *) dtr;
02057 
02058         if (!res)
02059                 return;
02060 
02061         apol_vector_destroy(&res->proc_trans_rules);
02062         apol_vector_destroy(&res->ep_rules);
02063         apol_vector_destroy(&res->exec_rules);
02064         apol_vector_destroy(&res->setexec_rules);
02065         apol_vector_destroy(&res->type_trans_rules);
02066         apol_vector_destroy(&res->access_rules);
02067         free(res);
02068 }
02069 
02070 void apol_domain_trans_result_destroy(apol_domain_trans_result_t ** res)
02071 {
02072         if (!res || !(*res))
02073                 return;
02074         domain_trans_result_free((void *)*res);
02075         *res = NULL;
02076 }