level_internal.h File Reference


Detailed Description

Protected interface for computing semantic differences in levels, either from level declarations, user's default level, user's permitted range, or a range_transition's target range.

Author:
Jeremy A. Mowery jmowery@tresys.com

Jason Tang jtang@tresys.com

Copyright (C) 2007 Tresys Technology, LLC

This library is free software; you can redistribute it and/or modify it under the terms of the GNU Lesser General Public License as published by the Free Software Foundation; either version 2.1 of the License, or (at your option) any later version.

This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.

You should have received a copy of the GNU Lesser General Public License along with this library; if not, write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA

Definition in file level_internal.h.

Go to the source code of this file.


Classes

struct  poldiff_level

Typedefs

typedef poldiff_level_summary poldiff_level_summary_t

Functions

poldiff_level_summary_tlevel_create (void)
 Allocate and return a new poldiff_level_summary_t object.
void level_destroy (poldiff_level_summary_t **ls)
 Deallocate all space associated with a poldiff_level_summary_t object, including the pointer itself.
int level_reset (poldiff_t *diff)
 Reset the state of all level differences.
apol_vector_tlevel_get_items (poldiff_t *diff, const apol_policy_t *policy)
 Get a vector of all levels from the given policy, sorted by name.
int level_comp (const void *x, const void *y, const poldiff_t *diff)
 Compare two qpol_level_t objects, determining if they have the same level name or not.
int level_new_diff (poldiff_t *diff, poldiff_form_e form, const void *item)
 Create, initialize, and insert a new semantic difference entry for a level.
int level_deep_diff (poldiff_t *diff, const void *x, const void *y)
 Compute the semantic difference of two levels for which the compare callback returns 0.
poldiff_level_tlevel_create_from_apol_mls_level (const apol_mls_level_t *level, poldiff_form_e form)
 Allocate and return a poldiff_level_t object.
void level_free (void *elem)
 Deallocate all space associated with a poldiff_level_t, including the pointer itself.
int level_deep_diff_apol_mls_levels (poldiff_t *diff, const apol_mls_level_t *level1, const apol_mls_level_t *level2, poldiff_level_t **orig_pl, poldiff_level_t **mod_pl)
 Perform a deep diff of two levels.
int level_deep_diff_cats (poldiff_t *diff, const apol_vector_t *v1, const apol_vector_t *v2, apol_vector_t **added, apol_vector_t **removed, apol_vector_t **unmodified)
 Calculate the differences between two sorted vectors of category names.

Typedef Documentation

typedef struct poldiff_level_summary poldiff_level_summary_t
 

Definition at line 35 of file level_internal.h.

Referenced by level_create(), and level_destroy().


Function Documentation

poldiff_level_summary_t* level_create void   ) 
 

Allocate and return a new poldiff_level_summary_t object.

Returns:
A new level summary. The caller must call level_destroy() afterwards. On error, return NULL and set errno.

Definition at line 258 of file level_diff.c.

References apol_vector_create(), poldiff_level_summary::diffs, level_destroy(), level_free(), and poldiff_level_summary_t.

Referenced by level_reset(), and poldiff_create().

00259 {
00260         poldiff_level_summary_t *ls = calloc(1, sizeof(poldiff_level_summary_t));
00261         if (ls == NULL)
00262                 return NULL;
00263         if ((ls->diffs = apol_vector_create(level_free)) == NULL) {
00264                 level_destroy(&ls);
00265                 return NULL;
00266         }
00267         return ls;
00268 }

void level_destroy poldiff_level_summary_t **  ls  ) 
 

Deallocate all space associated with a poldiff_level_summary_t object, including the pointer itself.

If the pointer is already NULL then do nothing.

Parameters:
ls Reference to a level summary to destroy. The pointer will be set to NULL afterwards.

Definition at line 270 of file level_diff.c.

References apol_vector_destroy(), and poldiff_level_summary_t.

Referenced by level_create(), level_reset(), and poldiff_destroy().

00271 {
00272         if (ls == NULL || *ls == NULL)
00273                 return;
00274         apol_vector_destroy(&(*ls)->diffs);
00275         free(*ls);
00276         *ls = NULL;
00277 }

int level_reset poldiff_t diff  ) 
 

Reset the state of all level differences.

Parameters:
diff The policy difference structure containing the differences to reset.
Returns:
0 on success and < 0 on error; if the call fails, errno will be set and the user should call poldiff_destroy() on diff.

Definition at line 279 of file level_diff.c.

References diff, ERR, level_create(), level_destroy(), poldiff::level_diffs, and poldiff_t.

00280 {
00281         int error = 0;
00282 
00283         if (diff == NULL) {
00284                 ERR(diff, "%s", strerror(EINVAL));
00285                 errno = EINVAL;
00286                 return -1;
00287         }
00288 
00289         level_destroy(&diff->level_diffs);
00290         diff->level_diffs = level_create();
00291         if (diff->level_diffs == NULL) {
00292                 error = errno;
00293                 ERR(diff, "%s", strerror(error));
00294                 errno = error;
00295                 return -1;
00296         }
00297 
00298         return 0;
00299 }

apol_vector_t* level_get_items poldiff_t diff,
const apol_policy_t policy
 

Get a vector of all levels from the given policy, sorted by name.

Parameters:
diff Policy diff error handler.
policy The policy from which to get the items.
Returns:
a newly allocated vector of all levels. The caller is responsible for calling apol_vector_destroy() afterwards. On error, return NULL and set errno.

Definition at line 317 of file level_diff.c.

References apol_policy_get_qpol(), apol_policy_t, apol_vector_create_from_iter(), apol_vector_sort(), apol_vector_t, diff, ERR, level_name_comp(), poldiff_t, qpol_iterator_destroy(), qpol_iterator_t, qpol_policy_get_level_iter(), and qpol_policy_t.

00318 {
00319         qpol_iterator_t *iter = NULL;
00320         apol_vector_t *v = NULL;
00321         qpol_policy_t *q = apol_policy_get_qpol(policy);
00322         int error = 0;
00323         if (qpol_policy_get_level_iter(q, &iter) < 0) {
00324                 return NULL;
00325         }
00326         v = apol_vector_create_from_iter(iter, NULL);
00327         if (v == NULL) {
00328                 error = errno;
00329                 ERR(diff, "%s", strerror(error));
00330                 qpol_iterator_destroy(&iter);
00331                 errno = error;
00332                 return NULL;
00333         }
00334         qpol_iterator_destroy(&iter);
00335         apol_vector_sort(v, level_name_comp, (void *)policy);
00336         return v;
00337 }

int level_comp const void *  x,
const void *  y,
const poldiff_t diff
 

Compare two qpol_level_t objects, determining if they have the same level name or not.

Parameters:
x The level from the original policy.
y The level from the modified policy.
diff The policy difference structure associated with both policies.
Returns:
< 0, 0, or > 0 if level x is respectively less than, equal to, or greater than level y.

Definition at line 339 of file level_diff.c.

References diff, poldiff::mod_qpol, poldiff::orig_qpol, poldiff_t, qpol_level_get_name(), and qpol_level_t.

00340 {
00341         const qpol_level_t *l1 = x;
00342         const qpol_level_t *l2 = y;
00343         const char *name1, *name2;
00344         if (qpol_level_get_name(diff->orig_qpol, l1, &name1) < 0 || qpol_level_get_name(diff->mod_qpol, l2, &name2) < 0) {
00345                 return 0;
00346         }
00347         return strcmp(name1, name2);
00348 }

int level_new_diff poldiff_t diff,
poldiff_form_e  form,
const void *  item
 

Create, initialize, and insert a new semantic difference entry for a level.

Parameters:
diff The policy difference structure to which to add the entry.
form The form of the difference.
item Item for which the entry is being created.
Returns:
0 on success and < 0 on error; if the call fails, set errno and leave the policy difference structure unchanged.

Definition at line 429 of file level_diff.c.

References poldiff_level::added_cats, apol_policy_t, apol_str_strdup(), apol_vector_append(), apol_vector_create_from_vector(), apol_vector_destroy(), apol_vector_t, diff, poldiff_level_summary::diffs, ERR, poldiff::level_diffs, level_free(), level_get_cats(), make_diff(), poldiff::mod_pol, poldiff::mod_qpol, poldiff_level_summary::num_added, poldiff_level_summary::num_removed, poldiff::orig_pol, poldiff::orig_qpol, poldiff_level_t, poldiff_t, qpol_level_get_name(), qpol_level_t, qpol_policy_t, and poldiff_level::removed_cats.

00430 {
00431         const qpol_level_t *l = item;
00432         const char *name = NULL;
00433         poldiff_level_t *pl = NULL;
00434         apol_policy_t *p;
00435         qpol_policy_t *q;
00436         apol_vector_t *v = NULL;
00437         int error = 0, retval = -1;
00438         if (form == POLDIFF_FORM_ADDED) {
00439                 p = diff->mod_pol;
00440                 q = diff->mod_qpol;
00441         } else {
00442                 p = diff->orig_pol;
00443                 q = diff->orig_qpol;
00444         }
00445         if (qpol_level_get_name(q, l, &name) < 0 || (pl = make_diff(diff, form, name)) == NULL) {
00446                 error = errno;
00447                 goto cleanup;
00448         }
00449         if ((v = level_get_cats(diff, p, l)) == NULL) {
00450                 error = errno;
00451                 ERR(diff, "%s", strerror(error));
00452                 goto cleanup;
00453         }
00454         if (form == POLDIFF_FORM_ADDED) {
00455                 apol_vector_destroy(&pl->added_cats);
00456                 if ((pl->added_cats = apol_vector_create_from_vector(v, apol_str_strdup, NULL, free)) == NULL) {
00457                         error = errno;
00458                         ERR(diff, "%s", strerror(error));
00459                         goto cleanup;
00460                 }
00461         } else if (form == POLDIFF_FORM_REMOVED) {
00462                 apol_vector_destroy(&pl->removed_cats);
00463                 if ((pl->removed_cats = apol_vector_create_from_vector(v, apol_str_strdup, NULL, free)) == NULL) {
00464                         error = errno;
00465                         ERR(diff, "%s", strerror(error));
00466                         goto cleanup;
00467                 }
00468         }
00469         if (apol_vector_append(diff->level_diffs->diffs, pl) < 0) {
00470                 error = errno;
00471                 ERR(diff, "%s", strerror(error));
00472                 goto cleanup;
00473         }
00474         if (form == POLDIFF_FORM_ADDED) {
00475                 diff->level_diffs->num_added++;
00476         } else {
00477                 diff->level_diffs->num_removed++;
00478         }
00479         retval = 0;
00480       cleanup:
00481         apol_vector_destroy(&v);
00482         if (retval < 0) {
00483                 level_free(pl);
00484                 errno = error;
00485         }
00486         return retval;
00487 }

int level_deep_diff poldiff_t diff,
const void *  x,
const void *  y
 

Compute the semantic difference of two levels for which the compare callback returns 0.

If a difference is found then allocate, initialize, and insert a new semantic difference entry for that level.

Parameters:
diff The policy difference structure associated with both levels and to which to add an entry if needed.
x The level from the original policy.
y The level from the modified policy.
Returns:
0 on success and < 0 on error; if the call fails, set errno and leave the policy difference structure unchanged.

Definition at line 514 of file level_diff.c.

References poldiff_level::added_cats, apol_str_strcmp(), apol_str_strdup(), apol_vector_append(), apol_vector_create_from_vector(), apol_vector_destroy(), apol_vector_sort(), apol_vector_t, diff, poldiff_level_summary::diffs, ERR, level_cat_comp(), level_deep_diff_cats(), poldiff::level_diffs, level_free(), level_get_cats(), make_diff(), poldiff::mod_pol, poldiff::mod_qpol, poldiff_level_summary::num_modified, poldiff::orig_pol, poldiff::orig_qpol, POLDIFF_FORM_MODIFIED, poldiff_level_t, poldiff_t, qpol_level_get_name(), qpol_level_t, poldiff_level::removed_cats, and poldiff_level::unmodified_cats.

00515 {
00516         const qpol_level_t *l1 = x;
00517         const qpol_level_t *l2 = y;
00518         apol_vector_t *v1 = NULL, *v2 = NULL;
00519         apol_vector_t *added = NULL, *removed = NULL, *unmodified = NULL;
00520         const char *name;
00521         poldiff_level_t *l = NULL;
00522         int retval = -1, error = 0, compval;
00523 
00524         if (qpol_level_get_name(diff->orig_qpol, l1, &name) < 0 ||
00525             (v1 = level_get_cats(diff, diff->orig_pol, l1)) == NULL || (v2 = level_get_cats(diff, diff->mod_pol, l2)) == NULL) {
00526                 error = errno;
00527                 goto cleanup;
00528         }
00529         apol_vector_sort(v1, apol_str_strcmp, NULL);
00530         apol_vector_sort(v2, apol_str_strcmp, NULL);
00531         compval = level_deep_diff_cats(diff, v1, v2, &added, &removed, &unmodified);
00532         if (compval < 0) {
00533                 error = errno;
00534                 goto cleanup;
00535         } else if (compval > 0) {
00536                 if ((l = make_diff(diff, POLDIFF_FORM_MODIFIED, name)) == NULL) {
00537                         error = errno;
00538                         goto cleanup;
00539                 }
00540                 apol_vector_destroy(&l->added_cats);
00541                 apol_vector_destroy(&l->removed_cats);
00542                 apol_vector_destroy(&l->unmodified_cats);
00543                 if ((l->added_cats = apol_vector_create_from_vector(added, apol_str_strdup, NULL, free)) == NULL ||
00544                     (l->removed_cats = apol_vector_create_from_vector(removed, apol_str_strdup, NULL, free)) == NULL ||
00545                     (l->unmodified_cats = apol_vector_create_from_vector(unmodified, apol_str_strdup, NULL, free)) == NULL) {
00546                         error = errno;
00547                         ERR(diff, "%s", strerror(error));
00548                         goto cleanup;
00549                 }
00550                 apol_vector_sort(l->removed_cats, level_cat_comp, diff->orig_qpol);
00551                 apol_vector_sort(l->added_cats, level_cat_comp, diff->mod_qpol);
00552                 apol_vector_sort(l->unmodified_cats, level_cat_comp, diff->orig_qpol);
00553                 if (apol_vector_append(diff->level_diffs->diffs, l) < 0) {
00554                         error = errno;
00555                         ERR(diff, "%s", strerror(error));
00556                         goto cleanup;
00557                 }
00558                 diff->level_diffs->num_modified++;
00559         }
00560         retval = 0;
00561       cleanup:
00562         apol_vector_destroy(&v1);
00563         apol_vector_destroy(&v2);
00564         apol_vector_destroy(&added);
00565         apol_vector_destroy(&removed);
00566         apol_vector_destroy(&unmodified);
00567         if (retval != 0) {
00568                 level_free(l);
00569         }
00570         errno = error;
00571         return retval;
00572 }

poldiff_level_t* level_create_from_apol_mls_level const apol_mls_level_t level,
poldiff_form_e  form
 

Allocate and return a poldiff_level_t object.

If the form is added or removed, set that respective vector to be all of the categories from the given level.

Parameters:
level Level object to use as a template.
form Form of difference for the level.
Returns:
Initialized level, or NULL upon error. Caller must call level_free() upon the returned value.

Definition at line 574 of file level_diff.c.

References apol_mls_level_get_cats(), apol_mls_level_get_sens(), apol_mls_level_t, apol_str_strdup(), apol_vector_create_from_vector(), apol_vector_create_with_capacity(), apol_vector_t, level, level_free(), and poldiff_level_t.

Referenced by range_deep_diff(), and user_deep_diff_default_levels().

00575 {
00576         const char *sens = apol_mls_level_get_sens(level);
00577         const apol_vector_t *cats = apol_mls_level_get_cats(level);
00578         poldiff_level_t *pl = NULL;
00579         apol_vector_t **target;
00580         if ((pl = calloc(1, sizeof(*pl))) == NULL ||
00581             (pl->name = strdup(sens)) == NULL || (pl->unmodified_cats = apol_vector_create_with_capacity(1, free)) == NULL) {
00582                 level_free(pl);
00583                 return NULL;;
00584         }
00585         pl->form = form;
00586         if (form == POLDIFF_FORM_ADDED) {
00587                 if ((pl->removed_cats = apol_vector_create_with_capacity(1, free)) == NULL) {
00588                         level_free(pl);
00589                         return NULL;
00590                 }
00591                 target = &pl->added_cats;
00592         } else if (form == POLDIFF_FORM_REMOVED) {
00593                 if ((pl->added_cats = apol_vector_create_with_capacity(1, free)) == NULL) {
00594                         level_free(pl);
00595                         return NULL;
00596                 }
00597                 target = &pl->removed_cats;
00598         } else {
00599                 if ((pl->added_cats = apol_vector_create_with_capacity(1, free)) == NULL ||
00600                     (pl->removed_cats = apol_vector_create_with_capacity(1, free)) == NULL) {
00601                         level_free(pl);
00602                         return NULL;
00603                 }
00604                 return pl;
00605         }
00606         if ((*target = apol_vector_create_from_vector(cats, apol_str_strdup, NULL, free)) == NULL) {
00607                 level_free(pl);
00608                 return NULL;
00609         }
00610         return pl;
00611 }

void level_free void *  elem  ) 
 

Deallocate all space associated with a poldiff_level_t, including the pointer itself.

Parameters:
elem Pointer to a poldiff_level_t object. If NULL then do nothing.

Definition at line 613 of file level_diff.c.

References poldiff_level::added_cats, apol_vector_destroy(), poldiff_level::name, poldiff_level_t, poldiff_level::removed_cats, and poldiff_level::unmodified_cats.

Referenced by level_create(), level_create_from_apol_mls_level(), level_deep_diff(), level_deep_diff_apol_mls_levels(), level_new_diff(), make_diff(), range_create(), range_deep_diff(), user_deep_diff_default_levels(), and user_free().

00614 {
00615         poldiff_level_t *s = elem;
00616         if (!elem)
00617                 return;
00618         free(s->name);
00619         apol_vector_destroy(&s->added_cats);
00620         apol_vector_destroy(&s->removed_cats);
00621         apol_vector_destroy(&s->unmodified_cats);
00622         free(s);
00623 }

int level_deep_diff_apol_mls_levels poldiff_t diff,
const apol_mls_level_t level1,
const apol_mls_level_t level2,
poldiff_level_t **  orig_pl,
poldiff_level_t **  mod_pl
 

Perform a deep diff of two levels.

This will first compare the sensitivity names; if they match then it compares the vectors of category names. If the sensitivities do not match, then generate two poldiff_level_ts, one for the original level and one for modified level. If they do match then create just one poldiff_level_t and write it to orig_pl.

Parameters:
diff Poldiff object, used for error reporting and for sorting the categories to policy order.
level1 Original level.
level2 Modified level.
orig_pl Destination to where to write the poldiff_level_t, if the sensitivites do not match or if the categories do not match.
mod_pl Destination to where to write the poldiff_level_t, if the sensitivities do not match.
Returns:
0 on success, < 0 on error.

Definition at line 625 of file level_diff.c.

References apol_mls_level_get_cats(), apol_mls_level_get_sens(), apol_mls_level_t, apol_str_strdup(), apol_vector_create_from_vector(), apol_vector_destroy(), apol_vector_sort(), apol_vector_t, diff, ERR, poldiff_level::form, level_cat_comp(), level_deep_diff_cats(), level_free(), make_diff(), poldiff::mod_qpol, poldiff::orig_qpol, POLDIFF_FORM_ADDED, POLDIFF_FORM_REMOVED, poldiff_level_t, poldiff_t, and poldiff_level::removed_cats.

Referenced by range_deep_diff(), and user_deep_diff_default_levels().

00627 {
00628         poldiff_level_t *u1 = NULL, *u2 = NULL;
00629         apol_vector_t *added = NULL, *removed = NULL, *unmodified = NULL;
00630         const char *sens1 = apol_mls_level_get_sens(level1);
00631         const apol_vector_t *cats1 = apol_mls_level_get_cats(level1);
00632         const char *sens2 = apol_mls_level_get_sens(level2);
00633         const apol_vector_t *cats2 = apol_mls_level_get_cats(level2);
00634         int retval = -1, compval;
00635 
00636         *orig_pl = *mod_pl = NULL;
00637         if (strcmp(sens1, sens2) != 0) {
00638                 /* sensitivities do not match, so don't check categories */
00639                 if ((u1 = make_diff(diff, POLDIFF_FORM_REMOVED, sens1)) == NULL ||
00640                     (u2 = make_diff(diff, POLDIFF_FORM_ADDED, sens2)) == NULL) {
00641                         ERR(diff, "%s", strerror(errno));
00642                         level_free(u1);
00643                         level_free(u2);
00644                         return -1;
00645                 }
00646                 apol_vector_destroy(&u1->removed_cats);
00647                 apol_vector_destroy(&u2->added_cats);
00648                 if ((u1->removed_cats = apol_vector_create_from_vector(cats1, apol_str_strdup, NULL, free)) == NULL ||
00649                     (u2->added_cats = apol_vector_create_from_vector(cats2, apol_str_strdup, NULL, free)) == NULL) {
00650                         ERR(diff, "%s", strerror(errno));
00651                         level_free(u1);
00652                         level_free(u2);
00653                         return -1;
00654                 }
00655                 apol_vector_sort(u1->removed_cats, level_cat_comp, diff->orig_qpol);
00656                 apol_vector_sort(u2->added_cats, level_cat_comp, diff->mod_qpol);
00657                 *orig_pl = u1;
00658                 *mod_pl = u2;
00659                 return 0;
00660         }
00661 
00662         compval = level_deep_diff_cats(diff, cats1, cats2, &added, &removed, &unmodified);
00663         if (compval < 0) {
00664                 goto cleanup;
00665         } else if (compval > 0) {
00666                 if ((u1 = calloc(1, sizeof(*u1))) == NULL || (u1->name = strdup(sens1)) == NULL ||
00667                     (u1->added_cats = apol_vector_create_from_vector(added, apol_str_strdup, NULL, free)) == NULL ||
00668                     (u1->removed_cats = apol_vector_create_from_vector(removed, apol_str_strdup, NULL, free)) == NULL ||
00669                     (u1->unmodified_cats = apol_vector_create_from_vector(unmodified, apol_str_strdup, NULL, free)) == NULL) {
00670                         ERR(diff, "%s", strerror(errno));
00671                         level_free(u1);
00672                         goto cleanup;
00673                 }
00674                 apol_vector_sort(u1->added_cats, level_cat_comp, diff->mod_qpol);
00675                 apol_vector_sort(u1->removed_cats, level_cat_comp, diff->orig_qpol);
00676                 apol_vector_sort(u1->unmodified_cats, level_cat_comp, diff->orig_qpol);
00677                 u1->form = POLDIFF_FORM_MODIFIED;
00678                 *orig_pl = u1;
00679         }
00680         retval = 0;
00681       cleanup:
00682         apol_vector_destroy(&added);
00683         apol_vector_destroy(&removed);
00684         apol_vector_destroy(&unmodified);
00685         return retval;
00686 }

int level_deep_diff_cats poldiff_t diff,
const apol_vector_t v1,
const apol_vector_t v2,
apol_vector_t **  added,
apol_vector_t **  removed,
apol_vector_t **  unmodified
 

Calculate the differences between two sorted vectors of category names.

Allocate the vectors added, removed, and unmodified; fill them with appropriate category names. The returned vectors' categories will be sorted alphabetically.

Parameters:
diff Error handler.
v1 First vector of category names, sorted alphabetically.
v2 Other vector of category names, sorted alphabetically.
added Reference to where to store added categories. The caller is responsible for calling apol_vector_destroy() upon the value. If no differences are found then this will be set to NULL.
removed Reference to where to store removed categories. The caller is responsible for calling apol_vector_destroy() upon the value. If no differences are found then this will be set to NULL.
unmodified Reference to where to store unmodified categories. The caller is responsible for calling apol_vector_destroy() upon the value. If no differences are found then this will be set to NULL.
Returns:
Greater than zero if a difference was found, zero upon no differences, less than zero on error.

Definition at line 688 of file level_diff.c.

References apol_vector_append(), apol_vector_create(), apol_vector_destroy(), apol_vector_get_element(), apol_vector_get_size(), apol_vector_t, diff, ERR, and poldiff_t.

Referenced by level_deep_diff(), level_deep_diff_apol_mls_levels(), and range_deep_diff().

00690 {
00691         size_t i, j;
00692         char *cat1, *cat2;
00693         int compval, retval = -1, error = 0;
00694         *added = *removed = *unmodified = NULL;
00695         if ((*added = apol_vector_create(free)) == NULL ||
00696             (*removed = apol_vector_create(free)) == NULL || (*unmodified = apol_vector_create(free)) == NULL) {
00697                 error = errno;
00698                 ERR(diff, "%s", strerror(error));
00699                 goto cleanup;
00700         }
00701         for (i = j = 0; i < apol_vector_get_size(v1);) {
00702                 if (j >= apol_vector_get_size(v2)) {
00703                         break;
00704                 }
00705                 cat1 = (char *)apol_vector_get_element(v1, i);
00706                 cat2 = (char *)apol_vector_get_element(v2, j);
00707                 compval = strcmp(cat1, cat2);
00708                 if (compval < 0) {
00709                         if ((cat1 = strdup(cat1)) == NULL || apol_vector_append(*removed, cat1) < 0) {
00710                                 error = errno;
00711                                 ERR(diff, "%s", strerror(error));
00712                                 free(cat1);
00713                                 goto cleanup;
00714                         }
00715                         i++;
00716                 } else if (compval > 0) {
00717                         if ((cat2 = strdup(cat2)) == NULL || apol_vector_append(*added, cat2) < 0) {
00718                                 error = errno;
00719                                 ERR(diff, "%s", strerror(error));
00720                                 free(cat2);
00721                                 goto cleanup;
00722                         }
00723                         j++;
00724                 } else {
00725                         if ((cat1 = strdup(cat1)) == NULL || apol_vector_append(*unmodified, cat1) < 0) {
00726                                 error = errno;
00727                                 ERR(diff, "%s", strerror(error));
00728                                 free(cat1);
00729                                 goto cleanup;
00730                         }
00731                         i++;
00732                         j++;
00733                 }
00734         }
00735         for (; i < apol_vector_get_size(v1); i++) {
00736                 cat1 = (char *)apol_vector_get_element(v1, i);
00737                 if ((cat1 = strdup(cat1)) == NULL || apol_vector_append(*removed, cat1) < 0) {
00738                         error = errno;
00739                         ERR(diff, "%s", strerror(error));
00740                         free(cat1);
00741                         goto cleanup;
00742                 }
00743         }
00744         for (; j < apol_vector_get_size(v2); j++) {
00745                 cat2 = (char *)apol_vector_get_element(v2, j);
00746                 if ((cat2 = strdup(cat2)) == NULL || apol_vector_append(*added, cat2) < 0) {
00747                         error = errno;
00748                         ERR(diff, "%s", strerror(error));
00749                         free(cat2);
00750                         goto cleanup;
00751                 }
00752         }
00753         if (apol_vector_get_size(*added) > 0 || apol_vector_get_size(*removed) > 0) {
00754                 retval = 1;
00755         } else {
00756                 retval = 0;
00757         }
00758       cleanup:
00759         if (retval <= 0) {
00760                 /* if no differences found, then destroy all vectors */
00761                 apol_vector_destroy(added);
00762                 apol_vector_destroy(removed);
00763                 apol_vector_destroy(unmodified);
00764         }
00765         if (retval < 0) {
00766                 error = errno;
00767         }
00768         return retval;
00769 }