terule_diff.c

Go to the documentation of this file.
00001 /**
00002  *  @file
00003  *  Implementation for computing semantic differences in AV and Type
00004  *  rules.
00005  *
00006  *  @author Jeremy A. Mowery jmowery@tresys.com
00007  *  @author Jason Tang jtang@tresys.com
00008  *
00009  *  Copyright (C) 2006-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 <config.h>
00027 
00028 #include "poldiff_internal.h"
00029 
00030 #include <apol/policy-query.h>
00031 #include <apol/util.h>
00032 #include <qpol/policy_extend.h>
00033 #include <assert.h>
00034 #include <errno.h>
00035 #include <stdio.h>
00036 #include <string.h>
00037 
00038 struct poldiff_terule_summary
00039 {
00040         size_t num_added;
00041         size_t num_removed;
00042         size_t num_modified;
00043         size_t num_added_type;
00044         size_t num_removed_type;
00045         int diffs_sorted;
00046         /** vector of poldiff_terule_t */
00047         apol_vector_t *diffs;
00048 };
00049 
00050 struct poldiff_terule
00051 {
00052         uint32_t spec;
00053         /* pointer into policy's symbol table */
00054         const char *source, *target;
00055         /** the class string is pointer into the class_bst BST */
00056         const char *cls;
00057         poldiff_form_e form;
00058         /* pointer into policy's symbol table */
00059         const char *orig_default, *mod_default;
00060         /** pointer into policy's conditional list, needed to render
00061          * conditional expressions */
00062         const qpol_cond_t *cond;
00063         uint32_t branch;
00064         /** vector of unsigned longs of line numbers from original policy */
00065         apol_vector_t *orig_linenos;
00066         /** vector of unsigned longs of line numbers from modified policy */
00067         apol_vector_t *mod_linenos;
00068         /** array of pointers for original rules */
00069         qpol_terule_t **orig_rules;
00070         size_t num_orig_rules;
00071         /** array of pointers for modified rules */
00072         qpol_terule_t **mod_rules;
00073         size_t num_mod_rules;
00074 };
00075 
00076 typedef struct pseudo_terule
00077 {
00078         uint32_t spec;
00079         /** pseudo-type values */
00080         uint32_t source, target, default_type;
00081         /** pointer into the class_bst BST */
00082         const char *cls;
00083         /** array of pointers into the bool_bst BST */
00084         const char *bools[5];
00085         uint32_t bool_val;
00086         uint32_t branch;
00087         /** pointer into policy's conditional list, needed to render
00088          * conditional expressions */
00089         const qpol_cond_t *cond;
00090         /** array of qpol_terule_t pointers, for showing line numbers */
00091         const qpol_terule_t **rules;
00092         size_t num_rules;
00093 } pseudo_terule_t;
00094 
00095 /******************** public terule functions ********************/
00096 
00097 /**
00098  *  Get an array of statistics for the number of differences of each
00099  *  form for te rules.
00100  *
00101  *  @param diff The policy difference structure from which to get the
00102  *  stats.
00103  *  @param stats Array into which to write the numbers (array must be
00104  *  pre-allocated).  The order of the values written to the array is
00105  *  as follows:  number of items of form POLDIFF_FORM_ADDED, number of
00106  *  POLDIFF_FORM_REMOVED, number of POLDIFF_FORM_MODIFIED, number of
00107  *  POLDIFF_FORM_ADD_TYPE, and number of POLDIFF_FORM_REMOVE_TYPE.
00108  *  @param idx Index into the terule diffs array indicating which rule
00109  *  type to reset, one of TERULE_OFFSET_MEMBER, etc.
00110  */
00111 static void poldiff_terule_get_stats(const poldiff_t * diff, size_t stats[5], unsigned int idx)
00112 {
00113         if (diff == NULL || stats == NULL) {
00114                 ERR(diff, "%s", strerror(EINVAL));
00115                 errno = EINVAL;
00116                 return;
00117         }
00118         stats[0] = diff->terule_diffs[idx]->num_added;
00119         stats[1] = diff->terule_diffs[idx]->num_removed;
00120         stats[2] = diff->terule_diffs[idx]->num_modified;
00121         stats[3] = diff->terule_diffs[idx]->num_added_type;
00122         stats[4] = diff->terule_diffs[idx]->num_removed_type;
00123 }
00124 
00125 void poldiff_terule_get_stats_change(const poldiff_t * diff, size_t stats[5])
00126 {
00127         poldiff_terule_get_stats(diff, stats, TERULE_OFFSET_CHANGE);
00128 }
00129 
00130 void poldiff_terule_get_stats_member(const poldiff_t * diff, size_t stats[5])
00131 {
00132         poldiff_terule_get_stats(diff, stats, TERULE_OFFSET_MEMBER);
00133 }
00134 
00135 void poldiff_terule_get_stats_trans(const poldiff_t * diff, size_t stats[5])
00136 {
00137         poldiff_terule_get_stats(diff, stats, TERULE_OFFSET_TRANS);
00138 }
00139 
00140 char *poldiff_terule_to_string(const poldiff_t * diff, const void *terule)
00141 {
00142         const poldiff_terule_t *pt = (const poldiff_terule_t *)terule;
00143         apol_policy_t *p;
00144         const char *rule_type;
00145         char *diff_char = "", *s = NULL, *cond_expr = NULL;
00146         size_t len = 0;
00147         int error;
00148         if (diff == NULL || terule == NULL) {
00149                 ERR(diff, "%s", strerror(EINVAL));
00150                 errno = EINVAL;
00151                 return NULL;
00152         }
00153         switch (pt->form) {
00154         case POLDIFF_FORM_ADDED:
00155         case POLDIFF_FORM_ADD_TYPE:
00156         {
00157                 diff_char = "+";
00158                 p = diff->mod_pol;
00159                 break;
00160         }
00161         case POLDIFF_FORM_REMOVED:
00162         case POLDIFF_FORM_REMOVE_TYPE:
00163         {
00164                 diff_char = "-";
00165                 p = diff->orig_pol;
00166                 break;
00167         }
00168         case POLDIFF_FORM_MODIFIED:
00169         {
00170                 diff_char = "*";
00171                 p = diff->orig_pol;
00172                 break;
00173         }
00174         default:
00175         {
00176                 ERR(diff, "%s", strerror(ENOTSUP));
00177                 errno = ENOTSUP;
00178                 return NULL;
00179         }
00180         }
00181         rule_type = apol_rule_type_to_str(pt->spec);
00182         if (apol_str_appendf(&s, &len, "%s %s %s %s : %s ", diff_char, rule_type, pt->source, pt->target, pt->cls) < 0) {
00183                 error = errno;
00184                 s = NULL;
00185                 goto err;
00186         }
00187         switch (pt->form) {
00188         case POLDIFF_FORM_ADDED:
00189         case POLDIFF_FORM_ADD_TYPE:
00190         {
00191                 if (apol_str_append(&s, &len, pt->mod_default) < 0) {
00192                         error = errno;
00193                         goto err;
00194                 }
00195                 break;
00196         }
00197         case POLDIFF_FORM_REMOVED:
00198         case POLDIFF_FORM_REMOVE_TYPE:
00199         {
00200                 if (apol_str_append(&s, &len, pt->orig_default) < 0) {
00201                         error = errno;
00202                         goto err;
00203                 }
00204                 break;
00205         }
00206         case POLDIFF_FORM_MODIFIED:
00207         {
00208                 if (apol_str_appendf(&s, &len, "{ -%s +%s }", pt->orig_default, pt->mod_default) < 0) {
00209                         error = errno;
00210                         goto err;
00211                 }
00212                 break;
00213         }
00214         default:
00215         {
00216                 ERR(diff, "%s", strerror(ENOTSUP));
00217                 errno = ENOTSUP;
00218                 return NULL;
00219         }
00220         }
00221         if (apol_str_append(&s, &len, ";") < 0) {
00222                 error = errno;
00223                 goto err;
00224         }
00225         if (pt->cond != NULL) {
00226                 if ((cond_expr = apol_cond_expr_render(p, pt->cond)) == NULL) {
00227                         error = errno;
00228                         goto err;
00229                 }
00230                 if (apol_str_appendf(&s, &len, "  [%s]:%s", cond_expr, (pt->branch ? "TRUE" : "FALSE")) < 0) {
00231                         error = errno;
00232                         goto err;
00233                 }
00234                 free(cond_expr);
00235         }
00236         return s;
00237       err:
00238         free(s);
00239         free(cond_expr);
00240         ERR(diff, "%s", strerror(error));
00241         errno = error;
00242         return NULL;
00243 }
00244 
00245 /**
00246  * Sort poldiff_terule diff results in a mostly alphabetical order.
00247  */
00248 static int poldiff_terule_cmp(const void *x, const void *y, void *data __attribute__ ((unused)))
00249 {
00250         const poldiff_terule_t *a = (const poldiff_terule_t *)x;
00251         const poldiff_terule_t *b = (const poldiff_terule_t *)y;
00252         int compval;
00253         if (a->spec != b->spec) {
00254                 const char *rule_type1 = apol_rule_type_to_str(a->spec);
00255                 const char *rule_type2 = apol_rule_type_to_str(b->spec);
00256                 compval = strcmp(rule_type1, rule_type2);
00257                 if (compval != 0) {
00258                         return compval;
00259                 }
00260         }
00261         if ((compval = strcmp(a->source, b->source)) != 0) {
00262                 return compval;
00263         }
00264         if ((compval = strcmp(a->target, b->target)) != 0) {
00265                 return compval;
00266         }
00267         if ((compval = strcmp(a->cls, b->cls)) != 0) {
00268                 return compval;
00269         }
00270         if (a->cond != b->cond) {
00271                 return (int)((char *)a->cond - (char *)b->cond);
00272         }
00273         /* sort true branch before false branch */
00274         return b->branch - a->branch;
00275 }
00276 
00277 /**
00278  *  Get the vector of te rule differences from the te rule difference
00279  *  summary.
00280  *
00281  *  @param diff The policy difference structure associated with the te
00282  *  rule difference summary.
00283  *  @param idx Index into the terule diffs array indicating which rule
00284  *  type to reset, one of TERULE_OFFSET_MEMBER, etc.
00285  *
00286  *  @return A vector of elements of type poldiff_terule_t, or NULL on
00287  *  error.  The caller should <b>not</b> destroy the vector returned.
00288  *  If the call fails, errno will be set.
00289  */
00290 static const apol_vector_t *poldiff_get_terule_vector(const poldiff_t * diff, terule_offset_e idx)
00291 {
00292         if (diff == NULL) {
00293                 errno = EINVAL;
00294                 return NULL;
00295         }
00296         if (diff->terule_diffs[idx]->diffs_sorted == 0) {
00297                 apol_vector_sort(diff->terule_diffs[idx]->diffs, poldiff_terule_cmp, NULL);
00298                 diff->terule_diffs[idx]->diffs_sorted = 1;
00299         }
00300         return diff->terule_diffs[idx]->diffs;
00301 }
00302 
00303 const apol_vector_t *poldiff_get_terule_vector_member(const poldiff_t * diff)
00304 {
00305         return poldiff_get_terule_vector(diff, TERULE_OFFSET_MEMBER);
00306 }
00307 
00308 const apol_vector_t *poldiff_get_terule_vector_change(const poldiff_t * diff)
00309 {
00310         return poldiff_get_terule_vector(diff, TERULE_OFFSET_CHANGE);
00311 }
00312 
00313 const apol_vector_t *poldiff_get_terule_vector_trans(const poldiff_t * diff)
00314 {
00315         return poldiff_get_terule_vector(diff, TERULE_OFFSET_TRANS);
00316 }
00317 
00318 poldiff_form_e poldiff_terule_get_form(const void *terule)
00319 {
00320         if (terule == NULL) {
00321                 errno = EINVAL;
00322                 return 0;
00323         }
00324         return ((const poldiff_terule_t *)terule)->form;
00325 }
00326 
00327 uint32_t poldiff_terule_get_rule_type(const poldiff_terule_t * terule)
00328 {
00329         if (terule == NULL) {
00330                 errno = EINVAL;
00331                 return 0;
00332         }
00333         return terule->spec;
00334 }
00335 
00336 const char *poldiff_terule_get_source_type(const poldiff_terule_t * terule)
00337 {
00338         if (terule == NULL) {
00339                 errno = EINVAL;
00340                 return 0;
00341         }
00342         return terule->source;
00343 }
00344 
00345 const char *poldiff_terule_get_target_type(const poldiff_terule_t * terule)
00346 {
00347         if (terule == NULL) {
00348                 errno = EINVAL;
00349                 return 0;
00350         }
00351         return terule->target;
00352 }
00353 
00354 const char *poldiff_terule_get_object_class(const poldiff_terule_t * terule)
00355 {
00356         if (terule == NULL) {
00357                 errno = EINVAL;
00358                 return 0;
00359         }
00360         return terule->cls;
00361 }
00362 
00363 void poldiff_terule_get_cond(const poldiff_t * diff, const poldiff_terule_t * terule,
00364                              const qpol_cond_t ** cond, uint32_t * which_list, const apol_policy_t ** p)
00365 {
00366         if (diff == NULL || terule == NULL || cond == NULL || p == NULL) {
00367                 errno = EINVAL;
00368                 return;
00369         }
00370         *cond = terule->cond;
00371         if (*cond == NULL) {
00372                 *which_list = 1;
00373                 *p = NULL;
00374         } else if (terule->form == POLDIFF_FORM_ADDED || terule->form == POLDIFF_FORM_ADD_TYPE) {
00375                 *which_list = terule->branch;
00376                 *p = diff->mod_pol;
00377         } else {
00378                 *which_list = terule->branch;
00379                 *p = diff->orig_pol;
00380         }
00381 }
00382 
00383 const char *poldiff_terule_get_original_default(const poldiff_terule_t * terule)
00384 {
00385         if (terule == NULL) {
00386                 errno = EINVAL;
00387                 return 0;
00388         }
00389         return terule->orig_default;
00390 }
00391 
00392 const char *poldiff_terule_get_modified_default(const poldiff_terule_t * terule)
00393 {
00394         if (terule == NULL) {
00395                 errno = EINVAL;
00396                 return 0;
00397         }
00398         return terule->mod_default;
00399 }
00400 
00401 apol_vector_t *poldiff_terule_get_orig_line_numbers(const poldiff_terule_t * terule)
00402 {
00403         if (terule == NULL) {
00404                 errno = EINVAL;
00405                 return NULL;
00406         }
00407         return terule->orig_linenos;
00408 }
00409 
00410 apol_vector_t *poldiff_terule_get_mod_line_numbers(const poldiff_terule_t * terule)
00411 {
00412         if (terule == NULL) {
00413                 errno = EINVAL;
00414                 return NULL;
00415         }
00416         return terule->mod_linenos;
00417 }
00418 
00419 /*************** protected functions ***************/
00420 
00421 /**
00422  * Free all space used by a poldiff_terule_t, including the pointer
00423  * itself.  Does nothing if the pointer is already NULL.
00424  *
00425  * @param elem Pointer to a poldiff_terule_t.
00426  */
00427 static void poldiff_terule_free(void *elem)
00428 {
00429         if (elem != NULL) {
00430                 poldiff_terule_t *t = elem;
00431                 apol_vector_destroy(&t->orig_linenos);
00432                 apol_vector_destroy(&t->mod_linenos);
00433                 free(t->orig_rules);
00434                 free(t->mod_rules);
00435                 free(elem);
00436         }
00437 }
00438 
00439 poldiff_terule_summary_t *terule_create(void)
00440 {
00441         poldiff_terule_summary_t *rs = calloc(1, sizeof(*rs));
00442         if (rs == NULL) {
00443                 return NULL;
00444         }
00445         if ((rs->diffs = apol_vector_create(poldiff_terule_free)) == NULL) {
00446                 terule_destroy(&rs);
00447                 return NULL;
00448         }
00449         return rs;
00450 }
00451 
00452 void terule_destroy(poldiff_terule_summary_t ** rs)
00453 {
00454         if (rs != NULL && *rs != NULL) {
00455                 apol_vector_destroy(&(*rs)->diffs);
00456                 free(*rs);
00457                 *rs = NULL;
00458         }
00459 }
00460 
00461 /**
00462  * Reset the state of all TE rule differences.
00463  * @param diff The policy difference structure containing the differences
00464  * to reset.
00465  * @param idx Index into the terule diffs array indicating which rule
00466  * type to reset, one of TERULE_OFFSET_CHANGE, etc.
00467  * @return 0 on success and < 0 on error; if the call fails,
00468  * errno will be set and the user should call poldiff_destroy() on diff.
00469  */
00470 static int terule_reset(poldiff_t * diff, terule_offset_e idx)
00471 {
00472         int error = 0;
00473         terule_destroy(&diff->terule_diffs[idx]);
00474         diff->terule_diffs[idx] = terule_create();
00475         if (diff->terule_diffs[idx] == NULL) {
00476                 error = errno;
00477                 ERR(diff, "%s", strerror(error));
00478                 errno = error;
00479                 return -1;
00480         }
00481         return 0;
00482 }
00483 
00484 int terule_reset_change(poldiff_t * diff)
00485 {
00486         return terule_reset(diff, TERULE_OFFSET_CHANGE);
00487 }
00488 
00489 int terule_reset_member(poldiff_t * diff)
00490 {
00491         return terule_reset(diff, TERULE_OFFSET_MEMBER);
00492 }
00493 
00494 int terule_reset_trans(poldiff_t * diff)
00495 {
00496         return terule_reset(diff, TERULE_OFFSET_TRANS);
00497 }
00498 
00499 static void terule_free_item(void *item)
00500 {
00501         pseudo_terule_t *t = (pseudo_terule_t *) item;
00502         if (item != NULL) {
00503                 free(t->rules);
00504                 free(t);
00505         }
00506 }
00507 
00508 /**
00509  * Apply an ordering scheme to two pseudo-te rules.
00510  *
00511  * <ul>
00512  * <li>Sort by target pseudo-type value,
00513  * <li>Then by source pseudo-type value,
00514  * <li>Then by object class's BST's pointer value,
00515  * <li>Then by rule specified (allow, neverallow, etc.),
00516  * <li>Then choose unconditional rules over conditional rules,
00517  * <li>Then by conditional expression's BST's boolean pointer value.
00518  * </ul>
00519  *
00520  * If this function is being used for sorting (via terule_get_items())
00521  * then sort by truth value, and then by branch (true branch, then
00522  * false branch).  Otherwise, when comparing rules (via terule_comp())
00523  * then by truth value, inverting rule2's value if in the other
00524  * branch.
00525  */
00526 static int pseudo_terule_comp(const pseudo_terule_t * rule1, const pseudo_terule_t * rule2, int is_sorting)
00527 {
00528         size_t i;
00529         uint32_t bool_val;
00530         if (rule1->target != rule2->target) {
00531                 return rule1->target - rule2->target;
00532         }
00533         if (rule1->source != rule2->source) {
00534                 return rule1->source - rule2->source;
00535         }
00536         if (rule1->cls != rule2->cls) {
00537                 return (int)(rule1->cls - rule2->cls);
00538         }
00539         if (rule1->spec != rule2->spec) {
00540                 return rule1->spec - rule2->spec;
00541         }
00542         if (rule1->bools[0] == NULL && rule2->bools[0] == NULL) {
00543                 /* both rules are unconditional */
00544                 return 0;
00545         } else if (rule1->bools[0] == NULL && rule2->bools[0] != NULL) {
00546                 /* unconditional rules come before conditional */
00547                 return -1;
00548         } else if (rule1->bools[0] != NULL && rule2->bools[0] == NULL) {
00549                 /* unconditional rules come before conditional */
00550                 return 1;
00551         }
00552         for (i = 0; i < (sizeof(rule1->bools) / sizeof(rule1->bools[0])); i++) {
00553                 if (rule1->bools[i] != rule2->bools[i]) {
00554                         return (int)(rule1->bools[i] - rule2->bools[i]);
00555                 }
00556         }
00557         if (is_sorting) {
00558                 if (rule1->branch != rule2->branch) {
00559                         return rule1->branch - rule2->branch;
00560                 }
00561                 return (int)rule1->bool_val - (int)rule2->bool_val;
00562         } else {
00563                 if (rule1->branch == rule2->branch) {
00564                         bool_val = rule2->bool_val;
00565                 } else {
00566                         bool_val = ~rule2->bool_val;
00567                 }
00568                 if (rule1->bool_val < bool_val) {
00569                         return -1;
00570                 } else if (rule1->bool_val > bool_val) {
00571                         return 1;
00572                 }
00573                 return 0;
00574         }
00575 }
00576 
00577 static int terule_bst_comp(const void *x, const void *y, void *data)
00578 {
00579         const pseudo_terule_t *r1 = (const pseudo_terule_t *)x;
00580         const pseudo_terule_t *r2 = (const pseudo_terule_t *)y;
00581         poldiff_t *diff = data;
00582         int retv;
00583         retv = pseudo_terule_comp(r1, r2, 1);
00584         if (!retv && r1->default_type != r2->default_type)
00585                 WARN(diff, "Multiple %s rules for %s %s %s with different default types", apol_rule_type_to_str(r1->spec),
00586                      type_map_get_name(diff, r1->source, POLDIFF_POLICY_ORIG), type_map_get_name(diff, r1->target,
00587                                                                                                  POLDIFF_POLICY_ORIG), r1->cls);
00588         return retv;
00589 }
00590 
00591 /**
00592  * Given a conditional expression, convert its booleans to a sorted
00593  * array of pseudo-boolean values, assign that array to the
00594  * pseudo-terule key, and then derive the truth table.
00595  *
00596  * @param diff Policy difference structure.
00597  * @param p Policy containing conditional.
00598  * @param cond Conditional expression to convert.
00599  * @param key Location to write converted expression.
00600  */
00601 static int terule_build_cond(const poldiff_t * diff, const apol_policy_t * p, const qpol_cond_t * cond, pseudo_terule_t * key)
00602 {
00603         qpol_iterator_t *iter = NULL;
00604         qpol_cond_expr_node_t *node;
00605         uint32_t expr_type, truthiness;
00606         qpol_bool_t *bools[5] = { NULL, NULL, NULL, NULL, NULL }, *qbool;
00607         size_t i, j;
00608         size_t num_bools = 0;
00609         const char *bool_name, *pseudo_bool, *t;
00610         qpol_policy_t *q = apol_policy_get_qpol(p);
00611         int retval = -1, error = 0, compval;
00612         if (qpol_cond_get_expr_node_iter(q, cond, &iter) < 0) {
00613                 error = errno;
00614                 goto cleanup;
00615         }
00616         for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
00617                 if (qpol_iterator_get_item(iter, (void **)&node) < 0 || qpol_cond_expr_node_get_expr_type(q, node, &expr_type) < 0) {
00618                         error = errno;
00619                         goto cleanup;
00620                 }
00621                 if (expr_type != QPOL_COND_EXPR_BOOL) {
00622                         continue;
00623                 }
00624                 if (qpol_cond_expr_node_get_bool(q, node, &qbool) < 0) {
00625                         error = errno;
00626                         goto cleanup;
00627                 }
00628                 for (i = 0; i < num_bools; i++) {
00629                         if (bools[i] == qbool) {
00630                                 break;
00631                         }
00632                 }
00633                 if (i >= num_bools) {
00634                         assert(i < 5);
00635                         bools[i] = qbool;
00636                         num_bools++;
00637                 }
00638         }
00639         for (i = 0; i < num_bools; i++) {
00640                 if (qpol_bool_get_name(q, bools[i], &bool_name) < 0) {
00641                         error = errno;
00642                         goto cleanup;
00643                 }
00644                 if (apol_bst_get_element(diff->bool_bst, (void *)bool_name, NULL, (void **)&pseudo_bool) < 0) {
00645                         error = EBADRQC;        /* should never get here */
00646                         ERR(diff, "%s", strerror(error));
00647                         assert(0);
00648                         goto cleanup;
00649                 }
00650                 key->bools[i] = pseudo_bool;
00651         }
00652 
00653         /* bubble sorth the pseudo bools (not bad because there are at
00654          * most five elements */
00655         for (i = num_bools; i > 1; i--) {
00656                 for (j = 1; j < i; j++) {
00657                         compval = strcmp(key->bools[j - 1], key->bools[j]);
00658                         if (compval > 0) {
00659                                 t = key->bools[j];
00660                                 key->bools[j] = key->bools[j - 1];
00661                                 key->bools[j - 1] = t;
00662                                 qbool = bools[j];
00663                                 bools[j] = bools[j - 1];
00664                                 bools[j - 1] = qbool;
00665                         }
00666                 }
00667         }
00668 
00669         /* now compute the truth table for the booleans */
00670         key->bool_val = 0;
00671         for (i = 0; i < 32; i++) {
00672                 for (j = 0; j < num_bools; j++) {
00673                         int state = ((i & (1 << j)) ? 1 : 0);
00674                         if (qpol_bool_set_state_no_eval(q, bools[j], state) < 0) {
00675                                 error = errno;
00676                                 goto cleanup;
00677                         }
00678                 }
00679                 if (qpol_cond_eval(q, cond, &truthiness) < 0) {
00680                         error = errno;
00681                         goto cleanup;
00682                 }
00683                 key->bool_val = (key->bool_val << 1) | truthiness;
00684         }
00685 
00686         key->cond = cond;
00687         retval = 0;
00688       cleanup:
00689         qpol_iterator_destroy(&iter);
00690         return retval;
00691 }
00692 
00693 /**
00694  * Given a rule, construct a new pseudo-terule and insert it into the
00695  * BST if not already there.
00696  *
00697  * @param diff Policy difference structure.
00698  * @param p Policy from which the rule came.
00699  * @param rule TE rule to insert.
00700  * @param source Source pseudo-type value.
00701  * @param target Target pseudo-type value.
00702  * @param b BST containing pseudo-terules.
00703  *
00704  * @return 0 on success, < 0 on error.
00705  */
00706 static int terule_add_to_bst(poldiff_t * diff, const apol_policy_t * p,
00707                              const qpol_terule_t * rule, uint32_t source, uint32_t target, apol_bst_t * b)
00708 {
00709         pseudo_terule_t *key, *inserted_key;
00710         const qpol_class_t *obj_class;
00711         const qpol_type_t *default_type;
00712         const char *class_name;
00713         const qpol_cond_t *cond;
00714         qpol_policy_t *q = apol_policy_get_qpol(p);
00715         int retval = -1, error = 0, compval;
00716         int which = (p == diff->orig_pol ? POLDIFF_POLICY_ORIG : POLDIFF_POLICY_MOD);
00717         if ((key = calloc(1, sizeof(*key))) == NULL) {
00718                 error = errno;
00719                 ERR(diff, "%s", strerror(error));
00720                 goto cleanup;
00721         }
00722         if (qpol_terule_get_rule_type(q, rule, &(key->spec)) < 0 ||
00723             qpol_terule_get_object_class(q, rule, &obj_class) < 0 ||
00724             qpol_terule_get_default_type(q, rule, &default_type) < 0 || qpol_terule_get_cond(q, rule, &cond) < 0) {
00725                 error = errno;
00726                 goto cleanup;
00727         }
00728         if (qpol_class_get_name(q, obj_class, &class_name) < 0) {
00729                 error = errno;
00730                 goto cleanup;
00731         }
00732         if (apol_bst_get_element(diff->class_bst, (void *)class_name, NULL, (void **)&key->cls) < 0) {
00733                 error = EBADRQC;       /* should never get here */
00734                 ERR(diff, "%s", strerror(error));
00735                 assert(0);
00736                 goto cleanup;
00737         }
00738         if ((key->default_type = type_map_lookup(diff, default_type, which)) == 0) {
00739                 error = errno;
00740                 ERR(diff, "%s", strerror(error));
00741                 goto cleanup;
00742         }
00743         key->source = source;
00744         key->target = target;
00745         if (cond != NULL && (qpol_terule_get_which_list(q, rule, &(key->branch)) < 0 || terule_build_cond(diff, p, cond, key) < 0)) {
00746                 error = errno;
00747                 goto cleanup;
00748         }
00749 
00750         /* insert this pseudo into the tree if not already there */
00751         if ((compval = apol_bst_insert_and_get(b, (void **)&key, diff)) < 0) {
00752                 error = errno;
00753                 ERR(diff, "%s", strerror(error));
00754                 goto cleanup;
00755         }
00756         inserted_key = key;
00757         key = NULL;
00758 
00759         /* store the rule pointer, to be used for showing line numbers */
00760         if (qpol_policy_has_capability(q, QPOL_CAP_LINE_NUMBERS)) {
00761                 const qpol_terule_t **t = realloc(inserted_key->rules,
00762                                                   (inserted_key->num_rules + 1) * sizeof(*t));
00763                 if (t == NULL) {
00764                         error = errno;
00765                         ERR(diff, "%s", strerror(error));
00766                         goto cleanup;
00767                 }
00768                 inserted_key->rules = t;
00769                 inserted_key->rules[inserted_key->num_rules++] = rule;
00770         }
00771 
00772         retval = 0;
00773       cleanup:
00774         if (retval < 0) {
00775                 terule_free_item(key);
00776         }
00777         errno = error;
00778         return retval;
00779 }
00780 
00781 /**
00782  * Given a rule, expand its source and target types into individual
00783  * pseudo-type values.  Then add the expanded rule to the BST.  This
00784  * is needed for when the source and/or target is an attribute.
00785  *
00786  * @param diff Policy difference structure.
00787  * @param p Policy from which the rule came.
00788  * @param rule TE rule to insert.
00789  * @param b BST containing pseudo-terules.
00790  *
00791  * @return 0 on success, < 0 on error.
00792  */
00793 static int terule_expand(poldiff_t * diff, const apol_policy_t * p, const qpol_terule_t * rule, apol_bst_t * b)
00794 {
00795         const qpol_type_t *source, *orig_target, *target;
00796         unsigned char source_attr, target_attr;
00797         qpol_iterator_t *source_iter = NULL, *target_iter = NULL;
00798         uint32_t source_val, target_val;
00799         qpol_policy_t *q = apol_policy_get_qpol(p);
00800         int which = (p == diff->orig_pol ? POLDIFF_POLICY_ORIG : POLDIFF_POLICY_MOD);
00801         int retval = -1, error = 0;
00802         if (qpol_terule_get_source_type(q, rule, &source) < 0 ||
00803             qpol_terule_get_target_type(q, rule, &orig_target) < 0 ||
00804             qpol_type_get_isattr(q, source, &source_attr) < 0 || qpol_type_get_isattr(q, orig_target, &target_attr)) {
00805                 error = errno;
00806                 goto cleanup;
00807         }
00808         if (source_attr && qpol_type_get_type_iter(q, source, &source_iter) < 0) {
00809                 error = errno;
00810                 goto cleanup;
00811         }
00812         do {
00813                 if (source_attr) {
00814                         if (qpol_iterator_get_item(source_iter, (void **)&source) < 0) {
00815                                 error = errno;
00816                                 goto cleanup;
00817                         }
00818                         qpol_iterator_next(source_iter);
00819                 }
00820                 if (target_attr) {
00821                         if (qpol_type_get_type_iter(q, orig_target, &target_iter) < 0) {
00822                                 error = errno;
00823                                 goto cleanup;
00824                         }
00825                 } else {
00826                         target = orig_target;
00827                 }
00828                 do {
00829                         if (target_attr) {
00830                                 if (qpol_iterator_get_item(target_iter, (void **)&target) < 0) {
00831                                         error = errno;
00832                                         goto cleanup;
00833                                 }
00834                                 qpol_iterator_next(target_iter);
00835                         }
00836                         const char *n1, *n2;
00837                         qpol_type_get_name(q, source, &n1);
00838                         qpol_type_get_name(q, target, &n2);
00839                         if ((source_val = type_map_lookup(diff, source, which)) == 0 ||
00840                             (target_val = type_map_lookup(diff, target, which)) == 0 ||
00841                             terule_add_to_bst(diff, p, rule, source_val, target_val, b) < 0) {
00842                                 error = errno;
00843                                 goto cleanup;
00844                         }
00845                 } while (target_attr && !qpol_iterator_end(target_iter));
00846                 qpol_iterator_destroy(&target_iter);
00847         } while (source_attr && !qpol_iterator_end(source_iter));
00848         retval = 0;
00849       cleanup:
00850         qpol_iterator_destroy(&source_iter);
00851         qpol_iterator_destroy(&target_iter);
00852         errno = error;
00853         return retval;
00854 }
00855 
00856 /**
00857  * Get a vector of terules from the given policy, sorted.  This
00858  * function will remap source and target types to their pseudo-type
00859  * value equivalents.
00860  *
00861  * @param diff Policy diff error handler.
00862  * @param policy The policy from which to get the items.
00863  * @param which Kind of rule to get, one of QPOL_RULE_TYPE_TRANS, etc.
00864  *
00865  * @return A newly allocated vector of all te rules (of type
00866  * pseudo_terule_t).  The caller is responsible for calling
00867  * apol_vector_destroy() afterwards.  On error, return NULL and set
00868  * errno.
00869  */
00870 static apol_vector_t *terule_get_items(poldiff_t * diff, const apol_policy_t * policy, unsigned int which)
00871 {
00872         apol_vector_t *bools = NULL, *bool_states = NULL;
00873         size_t i, num_rules, j;
00874         apol_bst_t *b = NULL;
00875         apol_vector_t *v = NULL;
00876         qpol_iterator_t *iter = NULL;
00877         qpol_terule_t *rule;
00878         qpol_policy_t *q = apol_policy_get_qpol(policy);
00879         int retval = -1, error = 0;
00880         if (poldiff_build_bsts(diff) < 0) {
00881                 error = errno;
00882                 goto cleanup;
00883         }
00884 
00885         /* store original boolean values */
00886         if (apol_bool_get_by_query(policy, NULL, &bools) < 0) {
00887                 error = errno;
00888                 goto cleanup;
00889         }
00890         if ((bool_states = apol_vector_create_with_capacity(apol_vector_get_size(bools), NULL)) == NULL) {
00891                 error = errno;
00892                 ERR(diff, "%s", strerror(error));
00893                 goto cleanup;
00894         }
00895         for (i = 0; i < apol_vector_get_size(bools); i++) {
00896                 qpol_bool_t *qbool = apol_vector_get_element(bools, i);
00897                 int state;
00898                 if (qpol_bool_get_state(q, qbool, &state) < 0) {
00899                         error = errno;
00900                         goto cleanup;
00901                 }
00902                 if (apol_vector_append(bool_states, (void *)((size_t) state)) < 0) {
00903                         error = errno;
00904                         ERR(diff, "%s", strerror(error));
00905                         goto cleanup;
00906                 }
00907         }
00908         if ((b = apol_bst_create(terule_bst_comp, terule_free_item)) == NULL) {
00909                 error = errno;
00910                 ERR(diff, "%s", strerror(error));
00911                 goto cleanup;
00912         }
00913         if (qpol_policy_get_terule_iter(q, which, &iter) < 0) {
00914                 error = errno;
00915                 ERR(diff, "%s", strerror(error));
00916                 goto cleanup;
00917         }
00918         qpol_iterator_get_size(iter, &num_rules);
00919         for (j = 0; !qpol_iterator_end(iter); qpol_iterator_next(iter), j++) {
00920                 if (qpol_iterator_get_item(iter, (void **)&rule) < 0 || terule_expand(diff, policy, rule, b) < 0) {
00921                         error = errno;
00922                         goto cleanup;
00923                 }
00924                 if (!(j % 1024)) {
00925                         int percent = 50 * j / num_rules + (policy == diff->mod_pol ? 50 : 0);
00926                         INFO(diff, "Computing TE rule difference: %02d%% complete", percent);
00927                 }
00928         }
00929         if ((v = apol_bst_get_vector(b, 1)) == NULL) {
00930                 error = errno;
00931                 ERR(diff, "%s", strerror(error));
00932                 goto cleanup;
00933         }
00934         retval = 0;
00935       cleanup:
00936         /* restore boolean states */
00937         for (i = 0; bools != NULL && i < apol_vector_get_size(bools); i++) {
00938                 qpol_bool_t *qbool = apol_vector_get_element(bools, i);
00939                 int state = (int)((size_t) apol_vector_get_element(bool_states, i));
00940                 qpol_bool_set_state_no_eval(q, qbool, state);
00941         }
00942         apol_vector_destroy(&bools);
00943         apol_vector_destroy(&bool_states);
00944         qpol_policy_reevaluate_conds(q);
00945         apol_bst_destroy(&b);
00946         qpol_iterator_destroy(&iter);
00947         if (retval < 0) {
00948                 apol_vector_destroy(&v);
00949                 errno = error;
00950                 return NULL;
00951         }
00952         return v;
00953 }
00954 
00955 apol_vector_t *terule_get_items_change(poldiff_t * diff, const apol_policy_t * policy)
00956 {
00957         return terule_get_items(diff, policy, QPOL_RULE_TYPE_CHANGE);
00958 }
00959 
00960 apol_vector_t *terule_get_items_member(poldiff_t * diff, const apol_policy_t * policy)
00961 {
00962         return terule_get_items(diff, policy, QPOL_RULE_TYPE_MEMBER);
00963 }
00964 
00965 apol_vector_t *terule_get_items_trans(poldiff_t * diff, const apol_policy_t * policy)
00966 {
00967         return terule_get_items(diff, policy, QPOL_RULE_TYPE_TRANS);
00968 }
00969 
00970 int terule_comp(const void *x, const void *y, const poldiff_t * diff __attribute__ ((unused)))
00971 {
00972         const pseudo_terule_t *r1 = (const pseudo_terule_t *)x;
00973         const pseudo_terule_t *r2 = (const pseudo_terule_t *)y;
00974         return pseudo_terule_comp(r1, r2, 0);
00975 }
00976 
00977 /**
00978  * Allocate and return a new terule difference object.  If the
00979  * pseudo-terule's source and/or target expands to multiple read
00980  * types, then just choose the first one for display.
00981  *
00982  * @param diff Policy diff error handler.
00983  * @param form Form of the difference.
00984  * @param rule Pseudo terule that changed.
00985  *
00986  * @return A newly allocated and initialized diff, or NULL upon error.
00987  * The caller is responsible for calling poldiff_terule_free() upon
00988  * the returned value.
00989  */
00990 static poldiff_terule_t *make_tediff(const poldiff_t * diff, poldiff_form_e form, const pseudo_terule_t * rule)
00991 {
00992         poldiff_terule_t *pt;
00993         const char *n1, *n2;
00994         int error;
00995         if (form == POLDIFF_FORM_ADDED || form == POLDIFF_FORM_ADD_TYPE) {
00996                 n1 = type_map_get_name(diff, rule->source, POLDIFF_POLICY_MOD);
00997                 n2 = type_map_get_name(diff, rule->target, POLDIFF_POLICY_MOD);
00998         } else {
00999                 n1 = type_map_get_name(diff, rule->source, POLDIFF_POLICY_ORIG);
01000                 n2 = type_map_get_name(diff, rule->target, POLDIFF_POLICY_ORIG);
01001         }
01002         assert(n1 != NULL && n2 != NULL);
01003         if ((pt = calloc(1, sizeof(*pt))) == NULL) {
01004                 error = errno;
01005                 poldiff_terule_free(pt);
01006                 ERR(diff, "%s", strerror(error));
01007                 errno = error;
01008                 return NULL;
01009         }
01010         pt->spec = rule->spec;
01011         pt->source = n1;
01012         pt->target = n2;
01013         pt->cls = rule->cls;
01014         pt->form = form;
01015         pt->cond = rule->cond;
01016         pt->branch = rule->branch;
01017         return pt;
01018 }
01019 
01020 /**
01021  * Create, initialize, and insert a new semantic difference entry for
01022  * a pseudo-te rule.
01023  *
01024  * @param diff The policy difference structure to which to add the entry.
01025  * @param form The form of the difference.
01026  * @param item Item for which the entry is being created.
01027  * @param idx Index into the terule differences specifying int which
01028  * to place the constructed pseudo-te rule.
01029  * @return 0 on success and < 0 on error; if the call fails, set errno
01030  * and leave the policy difference structure unchanged.
01031  */
01032 static int terule_new_diff(poldiff_t * diff, poldiff_form_e form, const void *item, terule_offset_e idx)
01033 {
01034         pseudo_terule_t *rule = (pseudo_terule_t *) item;
01035         poldiff_terule_t *pt = NULL;
01036         const apol_vector_t *v1, *v2;
01037         apol_policy_t *p;
01038         const char *orig_default = NULL, *mod_default = NULL;
01039         int retval = -1, error = errno;
01040 
01041         /* check if form should really become ADD_TYPE / REMOVE_TYPE,
01042          * by seeing if the /other/ policy's reverse lookup is
01043          * empty */
01044         if (form == POLDIFF_FORM_ADDED) {
01045                 if ((v1 = type_map_lookup_reverse(diff, rule->source, POLDIFF_POLICY_ORIG)) == NULL ||
01046                     (v2 = type_map_lookup_reverse(diff, rule->target, POLDIFF_POLICY_ORIG)) == NULL ||
01047                     (mod_default = type_map_get_name(diff, rule->default_type, POLDIFF_POLICY_MOD)) == NULL) {
01048                         error = errno;
01049                         goto cleanup;
01050                 }
01051                 if (apol_vector_get_size(v1) == 0 || apol_vector_get_size(v2) == 0) {
01052                         form = POLDIFF_FORM_ADD_TYPE;
01053                 }
01054                 p = diff->mod_pol;
01055         } else {
01056                 if ((v1 = type_map_lookup_reverse(diff, rule->source, POLDIFF_POLICY_MOD)) == NULL ||
01057                     (v2 = type_map_lookup_reverse(diff, rule->target, POLDIFF_POLICY_MOD)) == NULL ||
01058                     (orig_default = type_map_get_name(diff, rule->default_type, POLDIFF_POLICY_ORIG)) == NULL) {
01059                         error = errno;
01060                         goto cleanup;
01061                 }
01062                 if (apol_vector_get_size(v1) == 0 || apol_vector_get_size(v2) == 0) {
01063                         form = POLDIFF_FORM_REMOVE_TYPE;
01064                 }
01065                 p = diff->orig_pol;
01066         }
01067 
01068         pt = make_tediff(diff, form, rule);
01069         if (pt == NULL) {
01070                 return -1;
01071         }
01072         pt->orig_default = orig_default;
01073         pt->mod_default = mod_default;
01074 
01075         /* calculate line numbers */
01076         if (qpol_policy_has_capability(apol_policy_get_qpol(p), QPOL_CAP_LINE_NUMBERS)) {
01077                 apol_vector_t *vl = NULL;
01078                 if ((vl = apol_vector_create(NULL)) == NULL) {
01079                         error = errno;
01080                         ERR(diff, "%s", strerror(error));
01081                         goto cleanup;
01082                 }
01083                 if (form == POLDIFF_FORM_ADDED || form == POLDIFF_FORM_ADD_TYPE) {
01084                         pt->mod_linenos = vl;
01085                 } else {
01086                         pt->orig_linenos = vl;
01087                 }
01088 
01089                 /* copy rule pointers for delayed line number claculation */
01090                 if (form == POLDIFF_FORM_ADDED || form == POLDIFF_FORM_ADD_TYPE) {
01091                         pt->num_mod_rules = rule->num_rules;
01092                         pt->mod_rules = calloc(rule->num_rules, sizeof(qpol_terule_t *));
01093                         if (!pt->mod_rules) {
01094                                 error = errno;
01095                                 ERR(diff, "%s", strerror(error));
01096                                 goto cleanup;
01097                         }
01098                         memcpy(pt->mod_rules, rule->rules, rule->num_rules * sizeof(qpol_terule_t *));
01099                 } else {
01100                         pt->num_orig_rules = rule->num_rules;
01101                         pt->orig_rules = calloc(rule->num_rules, sizeof(qpol_terule_t *));
01102                         if (!pt->orig_rules) {
01103                                 error = errno;
01104                                 ERR(diff, "%s", strerror(error));
01105                                 goto cleanup;
01106                         }
01107                         memcpy(pt->orig_rules, rule->rules, rule->num_rules * sizeof(qpol_terule_t *));
01108                 }
01109         }
01110 
01111         if (apol_vector_append(diff->terule_diffs[idx]->diffs, pt) < 0) {
01112                 error = errno;
01113                 ERR(diff, "%s", strerror(error));
01114                 goto cleanup;
01115         }
01116         switch (form) {
01117         case POLDIFF_FORM_ADDED:
01118                 diff->terule_diffs[idx]->num_added++;
01119                 break;
01120         case POLDIFF_FORM_ADD_TYPE:
01121                 diff->terule_diffs[idx]->num_added_type++;
01122                 break;
01123         case POLDIFF_FORM_REMOVED:
01124                 diff->terule_diffs[idx]->num_removed++;
01125                 break;
01126         case POLDIFF_FORM_REMOVE_TYPE:
01127                 diff->terule_diffs[idx]->num_removed_type++;
01128                 break;
01129         default:
01130                 error = EBADRQC;       /* should never get here */
01131                 ERR(diff, "%s", strerror(error));
01132                 assert(0);
01133                 goto cleanup;
01134         }
01135         diff->terule_diffs[idx]->diffs_sorted = 0;
01136         retval = 0;
01137       cleanup:
01138         if (retval < 0) {
01139                 poldiff_terule_free(pt);
01140         }
01141         errno = error;
01142         return retval;
01143 }
01144 
01145 int terule_new_diff_change(poldiff_t * diff, poldiff_form_e form, const void *item)
01146 {
01147         return terule_new_diff(diff, form, item, TERULE_OFFSET_CHANGE);
01148 }
01149 
01150 int terule_new_diff_member(poldiff_t * diff, poldiff_form_e form, const void *item)
01151 {
01152         return terule_new_diff(diff, form, item, TERULE_OFFSET_MEMBER);
01153 }
01154 
01155 int terule_new_diff_trans(poldiff_t * diff, poldiff_form_e form, const void *item)
01156 {
01157         return terule_new_diff(diff, form, item, TERULE_OFFSET_TRANS);
01158 }
01159 
01160 /**
01161  * Compute the semantic difference of two pseudo-te rules for which
01162  * the compare callback returns 0.  If a difference is found then
01163  * allocate, initialize, and insert a new semantic difference entry
01164  * for that pseudo-te rule.
01165  *
01166  * @param diff The policy difference structure associated with both
01167  * pseudo-te rules and to which to add an entry if needed.
01168  * @param x The pseudo-te rule from the original policy.
01169  * @param y The pseudo-te rule from the modified policy.
01170  * @param idx Index into the terule differences specifying into which
01171  * to place the constructed pseudo-ate rule.
01172  *
01173  * @return 0 on success and < 0 on error; if the call fails, set errno
01174  * and leave the policy difference structure unchanged.
01175  */
01176 static int terule_deep_diff(poldiff_t * diff, const void *x, const void *y, terule_offset_e idx)
01177 {
01178         pseudo_terule_t *r1 = (pseudo_terule_t *) x;
01179         pseudo_terule_t *r2 = (pseudo_terule_t *) y;
01180         poldiff_terule_t *pt = NULL;
01181         int retval = -1, error = 0;
01182 
01183         if (r1->default_type != r2->default_type) {
01184                 if ((pt = make_tediff(diff, POLDIFF_FORM_MODIFIED, r1)) == NULL) {
01185                         error = errno;
01186                         goto cleanup;
01187                 }
01188                 pt->orig_default = type_map_get_name(diff, r1->default_type, POLDIFF_POLICY_ORIG);
01189                 pt->mod_default = type_map_get_name(diff, r2->default_type, POLDIFF_POLICY_MOD);
01190 
01191                 /* calculate line numbers */
01192                 if (qpol_policy_has_capability(apol_policy_get_qpol(diff->orig_pol), QPOL_CAP_LINE_NUMBERS)) {
01193                         if ((pt->orig_linenos = apol_vector_create(NULL)) == NULL) {
01194                                 error = errno;
01195                                 ERR(diff, "%s", strerror(error));
01196                                 goto cleanup;
01197                         }
01198 
01199                         /* copy rule pointers for delayed line number claculation */
01200                         pt->num_orig_rules = r1->num_rules;
01201                         pt->orig_rules = calloc(r1->num_rules, sizeof(qpol_terule_t *));
01202                         if (!pt->orig_rules) {
01203                                 error = errno;
01204                                 ERR(diff, "%s", strerror(error));
01205                                 goto cleanup;
01206                         }
01207                         memcpy(pt->orig_rules, r1->rules, r1->num_rules * sizeof(qpol_terule_t *));
01208                 }
01209                 if (qpol_policy_has_capability(apol_policy_get_qpol(diff->mod_pol), QPOL_CAP_LINE_NUMBERS)) {
01210                         if ((pt->mod_linenos = apol_vector_create(NULL)) == NULL) {
01211                                 error = errno;
01212                                 ERR(diff, "%s", strerror(error));
01213                                 goto cleanup;
01214                         }
01215 
01216                         /* copy rule pointers for delayed line number claculation */
01217                         pt->num_mod_rules = r2->num_rules;
01218                         pt->mod_rules = calloc(r2->num_rules, sizeof(qpol_terule_t *));
01219                         if (!pt->mod_rules) {
01220                                 error = errno;
01221                                 ERR(diff, "%s", strerror(error));
01222                                 goto cleanup;
01223                         }
01224                         memcpy(pt->mod_rules, r2->rules, r2->num_rules * sizeof(qpol_terule_t *));
01225                 }
01226 
01227                 if (apol_vector_append(diff->terule_diffs[idx]->diffs, pt) < 0) {
01228                         error = errno;
01229                         ERR(diff, "%s", strerror(error));
01230                         goto cleanup;
01231                 }
01232                 diff->terule_diffs[idx]->num_modified++;
01233                 diff->terule_diffs[idx]->diffs_sorted = 0;
01234         }
01235         retval = 0;
01236       cleanup:
01237         if (retval != 0) {
01238                 poldiff_terule_free(pt);
01239         }
01240         errno = error;
01241         return retval;
01242 }
01243 
01244 int terule_deep_diff_change(poldiff_t * diff, const void *x, const void *y)
01245 {
01246         return terule_deep_diff(diff, x, y, TERULE_OFFSET_CHANGE);
01247 }
01248 
01249 int terule_deep_diff_member(poldiff_t * diff, const void *x, const void *y)
01250 {
01251         return terule_deep_diff(diff, x, y, TERULE_OFFSET_MEMBER);
01252 }
01253 
01254 int terule_deep_diff_trans(poldiff_t * diff, const void *x, const void *y)
01255 {
01256         return terule_deep_diff(diff, x, y, TERULE_OFFSET_TRANS);
01257 }
01258 
01259 int terule_enable_line_numbers(poldiff_t * diff, terule_offset_e idx)
01260 {
01261         const apol_vector_t *te = NULL;
01262         poldiff_terule_t *terule = NULL;
01263         size_t i, j;
01264         qpol_iterator_t *iter = NULL;
01265         qpol_syn_terule_t *ste = NULL;
01266         int error = 0;
01267         unsigned long lineno = 0;
01268 
01269         te = poldiff_get_terule_vector(diff, idx);
01270 
01271         for (i = 0; i < apol_vector_get_size(te); i++) {
01272                 terule = apol_vector_get_element(te, i);
01273                 if (apol_vector_get_size(terule->mod_linenos) || apol_vector_get_size(terule->orig_linenos))
01274                         continue;
01275                 for (j = 0; j < terule->num_orig_rules; j++) {
01276                         if (qpol_terule_get_syn_terule_iter(diff->orig_qpol, terule->orig_rules[j], &iter)) {
01277                                 error = errno;
01278                                 goto err;
01279                         }
01280                         for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
01281                                 if (qpol_iterator_get_item(iter, (void **)&ste) < 0) {
01282                                         error = errno;
01283                                         ERR(diff, "%s", strerror(error));
01284                                         goto err;
01285                                 }
01286                                 if (qpol_syn_terule_get_lineno(diff->orig_qpol, ste, &lineno) < 0) {
01287                                         error = errno;
01288                                         goto err;
01289                                 }
01290                                 if (apol_vector_append(terule->orig_linenos, (void *)lineno) < 0) {
01291                                         error = errno;
01292                                         ERR(diff, "%s", strerror(error));
01293                                         goto err;
01294                                 }
01295                         }
01296                         qpol_iterator_destroy(&iter);
01297                 }
01298                 apol_vector_sort_uniquify(terule->orig_linenos, NULL, NULL);
01299                 for (j = 0; j < terule->num_mod_rules; j++) {
01300                         if (qpol_terule_get_syn_terule_iter(diff->mod_qpol, terule->mod_rules[j], &iter)) {
01301                                 error = errno;
01302                                 goto err;
01303                         }
01304                         for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
01305                                 if (qpol_iterator_get_item(iter, (void **)&ste) < 0) {
01306                                         error = errno;
01307                                         ERR(diff, "%s", strerror(error));
01308                                         goto err;
01309                                 }
01310                                 if (qpol_syn_terule_get_lineno(diff->mod_qpol, ste, &lineno) < 0) {
01311                                         error = errno;
01312                                         goto err;
01313                                 }
01314                                 if (apol_vector_append(terule->mod_linenos, (void *)lineno) < 0) {
01315                                         error = errno;
01316                                         ERR(diff, "%s", strerror(error));
01317                                         goto err;
01318                                 }
01319                         }
01320                         qpol_iterator_destroy(&iter);
01321                 }
01322                 apol_vector_sort_uniquify(terule->mod_linenos, NULL, NULL);
01323         }
01324 
01325         return 0;
01326       err:
01327         qpol_iterator_destroy(&iter);
01328         return -1;
01329 }