poldiff.c

Go to the documentation of this file.
00001 /**
00002  *  @file
00003  *  Implementation for computing a semantic policy difference.
00004  *
00005  *  @author Jeremy A. Mowery jmowery@tresys.com
00006  *  @author Jason Tang jtang@tresys.com
00007  *
00008  *  Copyright (C) 2006-2007 Tresys Technology, LLC
00009  *
00010  *  This library is free software; you can redistribute it and/or
00011  *  modify it under the terms of the GNU Lesser General Public
00012  *  License as published by the Free Software Foundation; either
00013  *  version 2.1 of the License, or (at your option) any later version.
00014  *
00015  *  This library is distributed in the hope that it will be useful,
00016  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00017  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00018  *  Lesser General Public License for more details.
00019  *
00020  *  You should have received a copy of the GNU Lesser General Public
00021  *  License along with this library; if not, write to the Free Software
00022  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00023  */
00024 
00025 #include <config.h>
00026 
00027 #include "poldiff_internal.h"
00028 #include <poldiff/component_record.h>
00029 
00030 #include <apol/util.h>
00031 #include <qpol/policy_extend.h>
00032 #include <errno.h>
00033 #include <stdio.h>
00034 #include <string.h>
00035 
00036 /**
00037  * All policy items (object classes, types, rules, etc.) must
00038  * implement at least these functions.  Next, a record should be
00039  * appended to the array 'component_records' below.
00040  */
00041 struct poldiff_component_record
00042 {
00043         const char *item_name;
00044         uint32_t flag_bit;
00045         poldiff_get_item_stats_fn_t get_stats;
00046         poldiff_get_result_items_fn_t get_results;
00047         poldiff_item_get_form_fn_t get_form;
00048         poldiff_item_to_string_fn_t to_string;
00049         poldiff_reset_fn_t reset;
00050         poldiff_get_items_fn_t get_items;
00051         poldiff_item_comp_fn_t comp;
00052         poldiff_new_diff_fn_t new_diff;
00053         poldiff_deep_diff_fn_t deep_diff;
00054 };
00055 
00056 static const poldiff_component_record_t component_records[] = {
00057         {
00058          "attribute",
00059          POLDIFF_DIFF_ATTRIBS,
00060          poldiff_attrib_get_stats,
00061          poldiff_get_attrib_vector,
00062          poldiff_attrib_get_form,
00063          poldiff_attrib_to_string,
00064          attrib_reset,
00065          attrib_get_items,
00066          attrib_comp,
00067          attrib_new_diff,
00068          attrib_deep_diff,
00069          },
00070         {
00071          "Allow Rules",
00072          POLDIFF_DIFF_AVALLOW,
00073          poldiff_avrule_get_stats_allow,
00074          poldiff_get_avrule_vector_allow,
00075          poldiff_avrule_get_form,
00076          poldiff_avrule_to_string,
00077          avrule_reset_allow,
00078          avrule_get_items_allow,
00079          avrule_comp,
00080          avrule_new_diff_allow,
00081          avrule_deep_diff_allow,
00082          },
00083         {
00084          "Audit Allow Rules",
00085          POLDIFF_DIFF_AVAUDITALLOW,
00086          poldiff_avrule_get_stats_auditallow,
00087          poldiff_get_avrule_vector_auditallow,
00088          poldiff_avrule_get_form,
00089          poldiff_avrule_to_string,
00090          avrule_reset_auditallow,
00091          avrule_get_items_auditallow,
00092          avrule_comp,
00093          avrule_new_diff_auditallow,
00094          avrule_deep_diff_auditallow,
00095          },
00096         {
00097          "Don't Audit Rules",
00098          POLDIFF_DIFF_AVDONTAUDIT,
00099          poldiff_avrule_get_stats_dontaudit,
00100          poldiff_get_avrule_vector_dontaudit,
00101          poldiff_avrule_get_form,
00102          poldiff_avrule_to_string,
00103          avrule_reset_dontaudit,
00104          avrule_get_items_dontaudit,
00105          avrule_comp,
00106          avrule_new_diff_dontaudit,
00107          avrule_deep_diff_dontaudit,
00108          },
00109         {
00110          "Never Allow Rules",
00111          POLDIFF_DIFF_AVNEVERALLOW,
00112          poldiff_avrule_get_stats_neverallow,
00113          poldiff_get_avrule_vector_neverallow,
00114          poldiff_avrule_get_form,
00115          poldiff_avrule_to_string,
00116          avrule_reset_neverallow,
00117          avrule_get_items_neverallow,
00118          avrule_comp,
00119          avrule_new_diff_neverallow,
00120          avrule_deep_diff_neverallow,
00121          },
00122         {
00123          "bool",
00124          POLDIFF_DIFF_BOOLS,
00125          poldiff_bool_get_stats,
00126          poldiff_get_bool_vector,
00127          poldiff_bool_get_form,
00128          poldiff_bool_to_string,
00129          bool_reset,
00130          bool_get_items,
00131          bool_comp,
00132          bool_new_diff,
00133          bool_deep_diff,
00134          },
00135         {
00136          "category",
00137          POLDIFF_DIFF_CATS,
00138          poldiff_cat_get_stats,
00139          poldiff_get_cat_vector,
00140          poldiff_cat_get_form,
00141          poldiff_cat_to_string,
00142          cat_reset,
00143          cat_get_items,
00144          cat_comp,
00145          cat_new_diff,
00146          cat_deep_diff,
00147          },
00148         {
00149          "class",
00150          POLDIFF_DIFF_CLASSES,
00151          poldiff_class_get_stats,
00152          poldiff_get_class_vector,
00153          poldiff_class_get_form,
00154          poldiff_class_to_string,
00155          class_reset,
00156          class_get_items,
00157          class_comp,
00158          class_new_diff,
00159          class_deep_diff,
00160          },
00161         {
00162          "common",
00163          POLDIFF_DIFF_COMMONS,
00164          poldiff_common_get_stats,
00165          poldiff_get_common_vector,
00166          poldiff_common_get_form,
00167          poldiff_common_to_string,
00168          common_reset,
00169          common_get_items,
00170          common_comp,
00171          common_new_diff,
00172          common_deep_diff,
00173          },
00174         {
00175          "level",
00176          POLDIFF_DIFF_LEVELS,
00177          poldiff_level_get_stats,
00178          poldiff_get_level_vector,
00179          poldiff_level_get_form,
00180          poldiff_level_to_string,
00181          level_reset,
00182          level_get_items,
00183          level_comp,
00184          level_new_diff,
00185          level_deep_diff,
00186          },
00187         {
00188          "range transition",
00189          POLDIFF_DIFF_RANGE_TRANS,
00190          poldiff_range_trans_get_stats,
00191          poldiff_get_range_trans_vector,
00192          poldiff_range_trans_get_form,
00193          poldiff_range_trans_to_string,
00194          range_trans_reset,
00195          range_trans_get_items,
00196          range_trans_comp,
00197          range_trans_new_diff,
00198          range_trans_deep_diff,
00199          },
00200         {
00201          "role",
00202          POLDIFF_DIFF_ROLES,
00203          poldiff_role_get_stats,
00204          poldiff_get_role_vector,
00205          poldiff_role_get_form,
00206          poldiff_role_to_string,
00207          role_reset,
00208          role_get_items,
00209          role_comp,
00210          role_new_diff,
00211          role_deep_diff,
00212          },
00213         {
00214          "role_allow",
00215          POLDIFF_DIFF_ROLE_ALLOWS,
00216          poldiff_role_allow_get_stats,
00217          poldiff_get_role_allow_vector,
00218          poldiff_role_allow_get_form,
00219          poldiff_role_allow_to_string,
00220          role_allow_reset,
00221          role_allow_get_items,
00222          role_allow_comp,
00223          role_allow_new_diff,
00224          role_allow_deep_diff,
00225          },
00226         {
00227          "role_transition",
00228          POLDIFF_DIFF_ROLE_TRANS,
00229          poldiff_role_trans_get_stats,
00230          poldiff_get_role_trans_vector,
00231          poldiff_role_trans_get_form,
00232          poldiff_role_trans_to_string,
00233          role_trans_reset,
00234          role_trans_get_items,
00235          role_trans_comp,
00236          role_trans_new_diff,
00237          role_trans_deep_diff,
00238          },
00239         {
00240          "Type Change rules",
00241          POLDIFF_DIFF_TECHANGE,
00242          poldiff_terule_get_stats_change,
00243          poldiff_get_terule_vector_change,
00244          poldiff_terule_get_form,
00245          poldiff_terule_to_string,
00246          terule_reset_change,
00247          terule_get_items_change,
00248          terule_comp,
00249          terule_new_diff_change,
00250          terule_deep_diff_change,
00251          },
00252         {
00253          "Type Member Rules",
00254          POLDIFF_DIFF_TEMEMBER,
00255          poldiff_terule_get_stats_member,
00256          poldiff_get_terule_vector_member,
00257          poldiff_terule_get_form,
00258          poldiff_terule_to_string,
00259          terule_reset_member,
00260          terule_get_items_member,
00261          terule_comp,
00262          terule_new_diff_member,
00263          terule_deep_diff_member,
00264          },
00265         {
00266          "Type Transition Rules",
00267          POLDIFF_DIFF_TETRANS,
00268          poldiff_terule_get_stats_trans,
00269          poldiff_get_terule_vector_trans,
00270          poldiff_terule_get_form,
00271          poldiff_terule_to_string,
00272          terule_reset_trans,
00273          terule_get_items_trans,
00274          terule_comp,
00275          terule_new_diff_trans,
00276          terule_deep_diff_trans,
00277          },
00278         {
00279          "type",
00280          POLDIFF_DIFF_TYPES,
00281          poldiff_type_get_stats,
00282          poldiff_get_type_vector,
00283          poldiff_type_get_form,
00284          poldiff_type_to_string,
00285          type_reset,
00286          type_get_items,
00287          type_comp,
00288          type_new_diff,
00289          type_deep_diff,
00290          },
00291         {
00292          "user",
00293          POLDIFF_DIFF_USERS,
00294          poldiff_user_get_stats,
00295          poldiff_get_user_vector,
00296          poldiff_user_get_form,
00297          poldiff_user_to_string,
00298          user_reset,
00299          user_get_items,
00300          user_comp,
00301          user_new_diff,
00302          user_deep_diff,
00303          },
00304 };
00305 
00306 const poldiff_component_record_t *poldiff_get_component_record(uint32_t which)
00307 {
00308         size_t i = 0;
00309         size_t num_items;
00310 
00311         num_items = sizeof(component_records) / sizeof(poldiff_component_record_t);
00312         for (i = 0; i < num_items; i++) {
00313                 if (component_records[i].flag_bit == which)
00314                         return &component_records[i];
00315         }
00316         return NULL;
00317 }
00318 
00319 poldiff_t *poldiff_create(apol_policy_t * orig_policy, apol_policy_t * mod_policy, poldiff_handle_fn_t fn, void *callback_arg)
00320 {
00321         poldiff_t *diff = NULL;
00322         int error;
00323 
00324         if (!orig_policy || !mod_policy) {
00325                 ERR(NULL, "%s", strerror(EINVAL));
00326                 errno = EINVAL;
00327                 return NULL;
00328         }
00329 
00330         if (!(diff = calloc(1, sizeof(poldiff_t)))) {
00331                 ERR(NULL, "%s", strerror(ENOMEM));
00332                 errno = ENOMEM;
00333                 return NULL;
00334         }
00335         diff->orig_pol = orig_policy;
00336         diff->mod_pol = mod_policy;
00337         diff->orig_qpol = apol_policy_get_qpol(diff->orig_pol);
00338         diff->mod_qpol = apol_policy_get_qpol(diff->mod_pol);
00339         diff->fn = fn;
00340         diff->handle_arg = callback_arg;
00341         if ((diff->type_map = type_map_create()) == NULL) {
00342                 ERR(diff, "%s", strerror(ENOMEM));
00343                 poldiff_destroy(&diff);
00344                 errno = ENOMEM;
00345                 return NULL;
00346         }
00347         if (type_map_infer(diff) < 0) {
00348                 error = errno;
00349                 poldiff_destroy(&diff);
00350                 errno = error;
00351                 return NULL;
00352         }
00353 
00354         if ((diff->attrib_diffs = attrib_summary_create()) == NULL ||
00355             (diff->avrule_diffs[AVRULE_OFFSET_ALLOW] = avrule_create()) == NULL ||
00356             (diff->avrule_diffs[AVRULE_OFFSET_AUDITALLOW] = avrule_create()) == NULL ||
00357             (diff->avrule_diffs[AVRULE_OFFSET_DONTAUDIT] = avrule_create()) == NULL ||
00358             (diff->avrule_diffs[AVRULE_OFFSET_NEVERALLOW] = avrule_create()) == NULL ||
00359             (diff->bool_diffs = bool_create()) == NULL ||
00360             (diff->cat_diffs = cat_create()) == NULL ||
00361             (diff->class_diffs = class_create()) == NULL ||
00362             (diff->common_diffs = common_create()) == NULL ||
00363             (diff->level_diffs = level_create()) == NULL ||
00364             (diff->range_trans_diffs = range_trans_create()) == NULL ||
00365             (diff->role_diffs = role_create()) == NULL ||
00366             (diff->role_allow_diffs = role_allow_create()) == NULL ||
00367             (diff->role_trans_diffs = role_trans_create()) == NULL ||
00368             (diff->terule_diffs[TERULE_OFFSET_CHANGE] = terule_create()) == NULL ||
00369             (diff->terule_diffs[TERULE_OFFSET_MEMBER] = terule_create()) == NULL ||
00370             (diff->terule_diffs[TERULE_OFFSET_TRANS] = terule_create()) == NULL ||
00371             (diff->type_diffs = type_summary_create()) == NULL || (diff->user_diffs = user_create()) == NULL) {
00372                 ERR(diff, "%s", strerror(ENOMEM));
00373                 poldiff_destroy(&diff);
00374                 errno = ENOMEM;
00375                 return NULL;
00376         }
00377 
00378         diff->policy_opts = QPOL_POLICY_OPTION_NO_RULES | QPOL_POLICY_OPTION_NO_NEVERALLOWS;
00379         return diff;
00380 }
00381 
00382 void poldiff_destroy(poldiff_t ** diff)
00383 {
00384         if (!diff || !(*diff))
00385                 return;
00386         apol_policy_destroy(&(*diff)->orig_pol);
00387         apol_policy_destroy(&(*diff)->mod_pol);
00388         apol_bst_destroy(&(*diff)->class_bst);
00389         apol_bst_destroy(&(*diff)->perm_bst);
00390         apol_bst_destroy(&(*diff)->bool_bst);
00391 
00392         type_map_destroy(&(*diff)->type_map);
00393         attrib_summary_destroy(&(*diff)->attrib_diffs);
00394         avrule_destroy(&(*diff)->avrule_diffs[AVRULE_OFFSET_ALLOW]);
00395         avrule_destroy(&(*diff)->avrule_diffs[AVRULE_OFFSET_AUDITALLOW]);
00396         avrule_destroy(&(*diff)->avrule_diffs[AVRULE_OFFSET_DONTAUDIT]);
00397         avrule_destroy(&(*diff)->avrule_diffs[AVRULE_OFFSET_NEVERALLOW]);
00398         bool_destroy(&(*diff)->bool_diffs);
00399         cat_destroy(&(*diff)->cat_diffs);
00400         class_destroy(&(*diff)->class_diffs);
00401         common_destroy(&(*diff)->common_diffs);
00402         level_destroy(&(*diff)->level_diffs);
00403         range_trans_destroy(&(*diff)->range_trans_diffs);
00404         role_destroy(&(*diff)->role_diffs);
00405         role_allow_destroy(&(*diff)->role_allow_diffs);
00406         role_trans_destroy(&(*diff)->role_trans_diffs);
00407         user_destroy(&(*diff)->user_diffs);
00408         terule_destroy(&(*diff)->terule_diffs[TERULE_OFFSET_CHANGE]);
00409         terule_destroy(&(*diff)->terule_diffs[TERULE_OFFSET_MEMBER]);
00410         terule_destroy(&(*diff)->terule_diffs[TERULE_OFFSET_TRANS]);
00411         type_summary_destroy(&(*diff)->type_diffs);
00412         free(*diff);
00413         *diff = NULL;
00414 }
00415 
00416 /**
00417  * Given a particular policy item record (e.g., one for object
00418  * classes), (re-)perform a diff of them between the two policies
00419  * listed in the poldiff_t structure.  Upon success, set the status
00420  * flag within 'diff' to indicate that this diff is done.
00421  *
00422  * @param diff The policy difference structure containing the policies
00423  * to compare and to populate with the item differences.
00424  * @param component_record Item record containg callbacks to perform each
00425  * step of the computation for a particular kind of item.
00426  *
00427  * @return 0 on success and < 0 on error; if the call fails; errno
00428  * will be set and the only defined operation on the policy difference
00429  * structure will be poldiff_destroy().
00430  */
00431 static int poldiff_do_item_diff(poldiff_t * diff, const poldiff_component_record_t * component_record)
00432 {
00433         apol_vector_t *p1_v = NULL, *p2_v = NULL;
00434         int error = 0, retv;
00435         size_t x = 0, y = 0;
00436         void *item_x = NULL, *item_y = NULL;
00437 
00438         if (!diff || !component_record) {
00439                 ERR(diff, "%s", strerror(EINVAL));
00440                 errno = EINVAL;
00441                 return -1;
00442         }
00443         diff->diff_status &= (~component_record->flag_bit);
00444 
00445         INFO(diff, "Getting %s items from original policy.", component_record->item_name);
00446         p1_v = component_record->get_items(diff, diff->orig_pol);
00447         if (!p1_v) {
00448                 error = errno;
00449                 goto err;
00450         }
00451 
00452         INFO(diff, "Getting %s items from modified policy.", component_record->item_name);
00453         p2_v = component_record->get_items(diff, diff->mod_pol);
00454         if (!p2_v) {
00455                 error = errno;
00456                 goto err;
00457         }
00458 
00459         INFO(diff, "Finding differences in %s.", component_record->item_name);
00460         for (x = 0, y = 0; x < apol_vector_get_size(p1_v);) {
00461                 if (y >= apol_vector_get_size(p2_v))
00462                         break;
00463                 item_x = apol_vector_get_element(p1_v, x);
00464                 item_y = apol_vector_get_element(p2_v, y);
00465                 retv = component_record->comp(item_x, item_y, diff);
00466                 if (retv < 0) {
00467                         if (component_record->new_diff(diff, POLDIFF_FORM_REMOVED, item_x)) {
00468                                 error = errno;
00469                                 goto err;
00470                         }
00471                         x++;
00472                 } else if (retv > 0) {
00473                         if (component_record->new_diff(diff, POLDIFF_FORM_ADDED, item_y)) {
00474                                 error = errno;
00475                                 goto err;
00476                         }
00477                         y++;
00478                 } else {
00479                         if (component_record->deep_diff(diff, item_x, item_y)) {
00480                                 error = errno;
00481                                 goto err;
00482                         }
00483                         x++;
00484                         y++;
00485                 }
00486         }
00487         for (; x < apol_vector_get_size(p1_v); x++) {
00488                 item_x = apol_vector_get_element(p1_v, x);
00489                 if (component_record->new_diff(diff, POLDIFF_FORM_REMOVED, item_x)) {
00490                         error = errno;
00491                         goto err;
00492                 }
00493         }
00494         for (; y < apol_vector_get_size(p2_v); y++) {
00495                 item_y = apol_vector_get_element(p2_v, y);
00496                 if (component_record->new_diff(diff, POLDIFF_FORM_ADDED, item_y)) {
00497                         error = errno;
00498                         goto err;
00499                 }
00500         }
00501 
00502         apol_vector_destroy(&p1_v);
00503         apol_vector_destroy(&p2_v);
00504         diff->diff_status |= component_record->flag_bit;
00505         return 0;
00506       err:
00507         apol_vector_destroy(&p1_v);
00508         apol_vector_destroy(&p2_v);
00509         errno = error;
00510         return -1;
00511 }
00512 
00513 int poldiff_run(poldiff_t * diff, uint32_t flags)
00514 {
00515         size_t i, num_items;
00516 
00517         if (!flags)
00518                 return 0;              /* nothing to do */
00519 
00520         if (!diff) {
00521                 ERR(diff, "%s", strerror(EINVAL));
00522                 errno = EINVAL;
00523                 return -1;
00524         }
00525 
00526         int policy_opts = diff->policy_opts;
00527         if (flags & (POLDIFF_DIFF_AVRULES | POLDIFF_DIFF_TERULES)) {
00528                 policy_opts &= ~(QPOL_POLICY_OPTION_NO_RULES);
00529         }
00530         if (flags & POLDIFF_DIFF_AVNEVERALLOW) {
00531                 policy_opts &= ~(QPOL_POLICY_OPTION_NO_NEVERALLOWS);
00532         }
00533         if (policy_opts != diff->policy_opts) {
00534                 INFO(diff, "%s", "Loading rules from original policy.");
00535                 if (qpol_policy_rebuild(diff->orig_qpol, policy_opts)) {
00536                         return -1;
00537                 }
00538                 INFO(diff, "%s", "Loading rules from modified policy.");
00539                 if (qpol_policy_rebuild(diff->mod_qpol, policy_opts)) {
00540                         return -1;
00541                 }
00542                 // force flushing of existing pointers into policies
00543                 diff->remapped = 1;
00544                 diff->policy_opts = policy_opts;
00545         }
00546 
00547         num_items = sizeof(component_records) / sizeof(poldiff_component_record_t);
00548         if (diff->remapped) {
00549                 for (i = 0; i < num_items; i++) {
00550                         if (component_records[i].flag_bit & POLDIFF_DIFF_REMAPPED) {
00551                                 INFO(diff, "Resetting %s diff.", component_records[i].item_name);
00552                                 if (component_records[i].reset(diff))
00553                                         return -1;
00554                         }
00555                 }
00556                 diff->diff_status &= ~(POLDIFF_DIFF_REMAPPED);
00557                 diff->remapped = 0;
00558         }
00559 
00560         INFO(diff, "%s", "Building type map.");
00561         if (type_map_build(diff)) {
00562                 return -1;
00563         }
00564 
00565         diff->line_numbers_enabled = 0;
00566         for (i = 0; i < num_items; i++) {
00567                 /* item requested but not yet run */
00568                 if ((flags & component_records[i].flag_bit) && !(component_records[i].flag_bit & diff->diff_status)) {
00569                         INFO(diff, "Running %s diff.", component_records[i].item_name);
00570                         if (poldiff_do_item_diff(diff, &(component_records[i]))) {
00571                                 return -1;
00572                         }
00573                 }
00574         }
00575 
00576         return 0;
00577 }
00578 
00579 int poldiff_is_run(const poldiff_t * diff, uint32_t flags)
00580 {
00581         if (!flags)
00582                 return 1;              /* nothing to do */
00583 
00584         if (!diff) {
00585                 ERR(diff, "%s", strerror(EINVAL));
00586                 errno = EINVAL;
00587                 return -1;
00588         }
00589         if ((diff->diff_status & flags) == flags) {
00590                 return 1;
00591         }
00592         return 0;
00593 }
00594 
00595 int poldiff_get_stats(const poldiff_t * diff, uint32_t flags, size_t stats[5])
00596 {
00597         size_t i, j, num_items, tmp_stats[5] = { 0, 0, 0, 0, 0 };
00598 
00599         if (!diff || !flags) {
00600                 ERR(diff, "%s", strerror(EINVAL));
00601                 errno = EINVAL;
00602                 return -1;
00603         }
00604 
00605         stats[0] = stats[1] = stats[2] = stats[3] = stats[4] = 0;
00606 
00607         num_items = sizeof(component_records) / sizeof(poldiff_component_record_t);
00608         for (i = 0; i < num_items; i++) {
00609                 if (flags & component_records[i].flag_bit) {
00610                         component_records[i].get_stats(diff, tmp_stats);
00611                         for (j = 0; j < 5; j++)
00612                                 stats[j] += tmp_stats[j];
00613                 }
00614         }
00615 
00616         return 0;
00617 }
00618 
00619 int poldiff_enable_line_numbers(poldiff_t * diff)
00620 {
00621         int retval;
00622         if (diff == NULL) {
00623                 errno = EINVAL;
00624                 return -1;
00625         }
00626         if (!diff->line_numbers_enabled) {
00627                 if (qpol_policy_build_syn_rule_table(diff->orig_qpol))
00628                         return -1;
00629                 if (qpol_policy_build_syn_rule_table(diff->mod_qpol))
00630                         return -1;
00631                 if ((retval = avrule_enable_line_numbers(diff, AVRULE_OFFSET_ALLOW)) < 0) {
00632                         return retval;
00633                 }
00634                 if ((retval = avrule_enable_line_numbers(diff, AVRULE_OFFSET_AUDITALLOW)) < 0) {
00635                         return retval;
00636                 }
00637                 if ((retval = avrule_enable_line_numbers(diff, AVRULE_OFFSET_DONTAUDIT)) < 0) {
00638                         return retval;
00639                 }
00640                 if ((retval = avrule_enable_line_numbers(diff, AVRULE_OFFSET_NEVERALLOW)) < 0) {
00641                         return retval;
00642                 }
00643                 if ((retval = terule_enable_line_numbers(diff, TERULE_OFFSET_CHANGE)) < 0) {
00644                         return retval;
00645                 }
00646                 if ((retval = terule_enable_line_numbers(diff, TERULE_OFFSET_MEMBER)) < 0) {
00647                         return retval;
00648                 }
00649                 if ((retval = terule_enable_line_numbers(diff, TERULE_OFFSET_TRANS)) < 0) {
00650                         return retval;
00651                 }
00652                 diff->line_numbers_enabled = 1;
00653         }
00654         return 0;
00655 }
00656 
00657 int poldiff_build_bsts(poldiff_t * diff)
00658 {
00659         apol_vector_t *classes[2] = { NULL, NULL };
00660         apol_vector_t *perms[2] = { NULL, NULL };
00661         apol_vector_t *bools[2] = { NULL, NULL };
00662         size_t i, j;
00663         const qpol_class_t *cls;
00664         qpol_bool_t *qbool;
00665         const char *name;
00666         char *new_name;
00667         int retval = -1, error = 0;
00668         if (diff->class_bst != NULL) {
00669                 return 0;
00670         }
00671         if ((diff->class_bst = apol_bst_create(apol_str_strcmp, free)) == NULL ||
00672             (diff->perm_bst = apol_bst_create(apol_str_strcmp, free)) == NULL ||
00673             (diff->bool_bst = apol_bst_create(apol_str_strcmp, free)) == NULL) {
00674                 error = errno;
00675                 ERR(diff, "%s", strerror(error));
00676                 goto cleanup;
00677         }
00678         for (i = 0; i < 2; i++) {
00679                 apol_policy_t *p = (i == 0 ? diff->orig_pol : diff->mod_pol);
00680                 qpol_policy_t *q = apol_policy_get_qpol(p);
00681                 if (apol_class_get_by_query(p, NULL, &classes[i]) < 0 ||
00682                     apol_perm_get_by_query(p, NULL, &perms[i]) < 0 || apol_bool_get_by_query(p, NULL, &bools[i]) < 0) {
00683                         error = errno;
00684                         goto cleanup;
00685                 }
00686                 for (j = 0; j < apol_vector_get_size(classes[i]); j++) {
00687                         cls = apol_vector_get_element(classes[i], j);
00688                         if (qpol_class_get_name(q, cls, &name) < 0) {
00689                                 error = errno;
00690                                 goto cleanup;
00691                         }
00692                         if ((new_name = strdup(name)) == NULL ||
00693                             apol_bst_insert_and_get(diff->class_bst, (void **)&new_name, NULL) < 0) {
00694                                 error = errno;
00695                                 ERR(diff, "%s", strerror(error));
00696                                 goto cleanup;
00697                         }
00698                 }
00699                 for (j = 0; j < apol_vector_get_size(perms[i]); j++) {
00700                         name = (char *)apol_vector_get_element(perms[i], j);
00701                         if ((new_name = strdup(name)) == NULL ||
00702                             apol_bst_insert_and_get(diff->perm_bst, (void **)&new_name, NULL) < 0) {
00703                                 error = errno;
00704                                 ERR(diff, "%s", strerror(error));
00705                                 goto cleanup;
00706                         }
00707                 }
00708                 for (j = 0; j < apol_vector_get_size(bools[i]); j++) {
00709                         qbool = (qpol_bool_t *) apol_vector_get_element(bools[i], j);
00710                         if (qpol_bool_get_name(q, qbool, &name) < 0) {
00711                                 error = errno;
00712                                 goto cleanup;
00713                         }
00714                         if ((new_name = strdup(name)) == NULL ||
00715                             apol_bst_insert_and_get(diff->bool_bst, (void **)&new_name, NULL) < 0) {
00716                                 error = errno;
00717                                 ERR(diff, "%s", strerror(error));
00718                                 goto cleanup;
00719                         }
00720                 }
00721         }
00722         retval = 0;
00723       cleanup:
00724         apol_vector_destroy(&classes[0]);
00725         apol_vector_destroy(&classes[1]);
00726         apol_vector_destroy(&perms[0]);
00727         apol_vector_destroy(&perms[1]);
00728         apol_vector_destroy(&bools[0]);
00729         apol_vector_destroy(&bools[1]);
00730         errno = error;
00731         return retval;
00732 }
00733 
00734 static void poldiff_handle_default_callback(void *arg __attribute__ ((unused)),
00735                                             poldiff_t * p __attribute__ ((unused)), int level, const char *fmt, va_list va_args)
00736 {
00737         switch (level) {
00738         case POLDIFF_MSG_INFO:
00739         {
00740                 /* by default do not display these messages */
00741                 return;
00742         }
00743         case POLDIFF_MSG_WARN:
00744         {
00745                 fprintf(stderr, "WARNING: ");
00746                 break;
00747         }
00748         case POLDIFF_MSG_ERR:
00749         default:
00750         {
00751                 fprintf(stderr, "ERROR: ");
00752                 break;
00753         }
00754         }
00755         vfprintf(stderr, fmt, va_args);
00756         fprintf(stderr, "\n");
00757 }
00758 
00759 void poldiff_handle_msg(const poldiff_t * p, int level, const char *fmt, ...)
00760 {
00761         va_list ap;
00762         va_start(ap, fmt);
00763         if (p == NULL || p->fn == NULL) {
00764                 poldiff_handle_default_callback(NULL, NULL, level, fmt, ap);
00765         } else {
00766                 p->fn(p->handle_arg, p, level, fmt, ap);
00767         }
00768         va_end(ap);
00769 }
00770 
00771 poldiff_item_get_form_fn_t poldiff_component_record_get_form_fn(const poldiff_component_record_t * diff)
00772 {
00773         if (!diff) {
00774                 errno = EINVAL;
00775                 return NULL;
00776         }
00777         return diff->get_form;
00778 }
00779 
00780 poldiff_item_to_string_fn_t poldiff_component_record_get_to_string_fn(const poldiff_component_record_t * diff)
00781 {
00782         if (!diff) {
00783                 errno = EINVAL;
00784                 return NULL;
00785         }
00786         return diff->to_string;
00787 }
00788 
00789 poldiff_get_item_stats_fn_t poldiff_component_record_get_stats_fn(const poldiff_component_record_t * diff)
00790 {
00791         if (!diff) {
00792                 errno = EINVAL;
00793                 return NULL;
00794         }
00795         return diff->get_stats;
00796 }
00797 
00798 poldiff_get_result_items_fn_t poldiff_component_record_get_results_fn(const poldiff_component_record_t * diff)
00799 {
00800         if (!diff) {
00801                 errno = EINVAL;
00802                 return NULL;
00803         }
00804         return diff->get_results;
00805 }
00806 
00807 const char *poldiff_component_record_get_label(const poldiff_component_record_t * diff)
00808 {
00809         if (!diff) {
00810                 errno = EINVAL;
00811                 return NULL;
00812         }
00813         return diff->item_name;
00814 }