class_diff.c

Go to the documentation of this file.
00001 /**
00002  *  @file
00003  *  Implementation for computing semantic differences in classes and
00004  *  commons.
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/util.h>
00031 #include <errno.h>
00032 #include <stdio.h>
00033 #include <string.h>
00034 
00035 /******************** object classes ********************/
00036 
00037 struct poldiff_class_summary
00038 {
00039         size_t num_added;
00040         size_t num_removed;
00041         size_t num_modified;
00042         apol_vector_t *diffs;
00043 };
00044 
00045 struct poldiff_class
00046 {
00047         char *name;
00048         poldiff_form_e form;
00049         apol_vector_t *added_perms;
00050         apol_vector_t *removed_perms;
00051 };
00052 
00053 void poldiff_class_get_stats(const poldiff_t * diff, size_t stats[5])
00054 {
00055         if (diff == NULL || stats == NULL) {
00056                 ERR(diff, "%s", strerror(EINVAL));
00057                 errno = EINVAL;
00058                 return;
00059         }
00060         stats[0] = diff->class_diffs->num_added;
00061         stats[1] = diff->class_diffs->num_removed;
00062         stats[2] = diff->class_diffs->num_modified;
00063         stats[3] = 0;
00064         stats[4] = 0;
00065 }
00066 
00067 char *poldiff_class_to_string(const poldiff_t * diff, const void *cls)
00068 {
00069         poldiff_class_t *c = (poldiff_class_t *) cls;
00070         size_t num_added, num_removed, len = 0, i;
00071         char *s = NULL, *perm;
00072         if (diff == NULL || cls == NULL) {
00073                 ERR(diff, "%s", strerror(EINVAL));
00074                 errno = EINVAL;
00075                 return NULL;
00076         }
00077         num_added = apol_vector_get_size(c->added_perms);
00078         num_removed = apol_vector_get_size(c->removed_perms);
00079         switch (c->form) {
00080         case POLDIFF_FORM_ADDED:
00081         {
00082                 if (apol_str_appendf(&s, &len, "+ %s", c->name) < 0) {
00083                         break;
00084                 }
00085                 return s;
00086         }
00087         case POLDIFF_FORM_REMOVED:
00088         {
00089                 if (apol_str_appendf(&s, &len, "- %s", c->name) < 0) {
00090                         break;
00091                 }
00092                 return s;
00093         }
00094         case POLDIFF_FORM_MODIFIED:
00095         {
00096                 if (apol_str_appendf(&s, &len, "* %s (", c->name) < 0) {
00097                         s = NULL;
00098                         break;
00099                 }
00100                 if (num_added > 0) {
00101                         if (apol_str_appendf(&s, &len, "%zd Added Permission%s", num_added, (num_added == 1 ? "" : "s")) < 0) {
00102                                 break;
00103                         }
00104                 }
00105                 if (num_removed > 0) {
00106                         if (apol_str_appendf
00107                             (&s, &len, "%s%zd Removed Permission%s", (num_added > 0 ? ", " : ""), num_removed,
00108                              (num_removed == 1 ? "" : "s")) < 0) {
00109                                 break;
00110                         }
00111                 }
00112                 if (apol_str_append(&s, &len, ")\n") < 0) {
00113                         break;
00114                 }
00115                 for (i = 0; i < apol_vector_get_size(c->added_perms); i++) {
00116                         perm = (char *)apol_vector_get_element(c->added_perms, i);
00117                         if (apol_str_appendf(&s, &len, "\t+ %s\n", perm) < 0) {
00118                                 goto err;
00119                         }
00120                 }
00121                 for (i = 0; i < apol_vector_get_size(c->removed_perms); i++) {
00122                         perm = (char *)apol_vector_get_element(c->removed_perms, i);
00123                         if (apol_str_appendf(&s, &len, "\t- %s\n", perm) < 0) {
00124                                 goto err;
00125                         }
00126                 }
00127                 return s;
00128         }
00129         default:
00130         {
00131                 ERR(diff, "%s", strerror(ENOTSUP));
00132                 errno = ENOTSUP;
00133                 return NULL;
00134         }
00135         }
00136       err:
00137         /* if this is reached then an error occurred */
00138         free(s);
00139         ERR(diff, "%s", strerror(ENOMEM));
00140         errno = ENOMEM;
00141         return NULL;
00142 }
00143 
00144 const apol_vector_t *poldiff_get_class_vector(const poldiff_t * diff)
00145 {
00146         if (diff == NULL) {
00147                 errno = EINVAL;
00148                 return NULL;
00149         }
00150         return diff->class_diffs->diffs;
00151 }
00152 
00153 const char *poldiff_class_get_name(const poldiff_class_t * cls)
00154 {
00155         if (cls == NULL) {
00156                 errno = EINVAL;
00157                 return NULL;
00158         }
00159         return cls->name;
00160 }
00161 
00162 poldiff_form_e poldiff_class_get_form(const void *cls)
00163 {
00164         if (cls == NULL) {
00165                 errno = EINVAL;
00166                 return 0;
00167         }
00168         return ((const poldiff_class_t *)cls)->form;
00169 }
00170 
00171 const apol_vector_t *poldiff_class_get_added_perms(const poldiff_class_t * cls)
00172 {
00173         if (cls == NULL) {
00174                 errno = EINVAL;
00175                 return NULL;
00176         }
00177         return cls->added_perms;
00178 }
00179 
00180 const apol_vector_t *poldiff_class_get_removed_perms(const poldiff_class_t * cls)
00181 {
00182         if (cls == NULL) {
00183                 errno = EINVAL;
00184                 return NULL;
00185         }
00186         return cls->removed_perms;
00187 }
00188 
00189 /*************** protected functions for object classes ***************/
00190 
00191 static void class_free(void *elem)
00192 {
00193         if (elem != NULL) {
00194                 poldiff_class_t *c = (poldiff_class_t *) elem;
00195                 free(c->name);
00196                 apol_vector_destroy(&c->added_perms);
00197                 apol_vector_destroy(&c->removed_perms);
00198                 free(c);
00199         }
00200 }
00201 
00202 poldiff_class_summary_t *class_create(void)
00203 {
00204         poldiff_class_summary_t *cs = calloc(1, sizeof(*cs));
00205         if (cs == NULL) {
00206                 return NULL;
00207         }
00208         if ((cs->diffs = apol_vector_create(class_free)) == NULL) {
00209                 class_destroy(&cs);
00210                 return NULL;
00211         }
00212         return cs;
00213 }
00214 
00215 void class_destroy(poldiff_class_summary_t ** cs)
00216 {
00217         if (cs != NULL && *cs != NULL) {
00218                 apol_vector_destroy(&(*cs)->diffs);
00219                 free(*cs);
00220                 *cs = NULL;
00221         }
00222 }
00223 
00224 int class_reset(poldiff_t * diff)
00225 {
00226         int error = 0;
00227 
00228         if (diff == NULL) {
00229                 ERR(diff, "%s", strerror(EINVAL));
00230                 errno = EINVAL;
00231                 return -1;
00232         }
00233 
00234         class_destroy(&diff->class_diffs);
00235         diff->class_diffs = class_create();
00236         if (diff->class_diffs == NULL) {
00237                 error = errno;
00238                 ERR(diff, "%s", strerror(error));
00239                 errno = error;
00240                 return -1;
00241         }
00242 
00243         return 0;
00244 }
00245 
00246 /**
00247  * Comparison function for two classes from the same policy.
00248  */
00249 static int class_name_comp(const void *x, const void *y, void *arg)
00250 {
00251         const qpol_class_t *c1 = x;
00252         const qpol_class_t *c2 = y;
00253         apol_policy_t *p = (apol_policy_t *) arg;
00254         qpol_policy_t *q = apol_policy_get_qpol(p);
00255         const char *name1, *name2;
00256         if (qpol_class_get_name(q, c1, &name1) < 0 || qpol_class_get_name(q, c2, &name2) < 0) {
00257                 return 0;
00258         }
00259         return strcmp(name1, name2);
00260 }
00261 
00262 apol_vector_t *class_get_items(poldiff_t * diff, const apol_policy_t * policy)
00263 {
00264         qpol_iterator_t *iter = NULL;
00265         apol_vector_t *v = NULL;
00266         qpol_policy_t *q = apol_policy_get_qpol(policy);
00267         int error = 0;
00268         if (qpol_policy_get_class_iter(q, &iter) < 0) {
00269                 return NULL;
00270         }
00271         v = apol_vector_create_from_iter(iter, NULL);
00272         if (v == NULL) {
00273                 error = errno;
00274                 ERR(diff, "%s", strerror(error));
00275                 qpol_iterator_destroy(&iter);
00276                 errno = error;
00277                 return NULL;
00278         }
00279         qpol_iterator_destroy(&iter);
00280         apol_vector_sort(v, class_name_comp, (void *)policy);
00281         return v;
00282 }
00283 
00284 int class_comp(const void *x, const void *y, const poldiff_t * diff)
00285 {
00286         const qpol_class_t *c1 = x;
00287         const qpol_class_t *c2 = y;
00288         const char *name1, *name2;
00289         if (qpol_class_get_name(diff->orig_qpol, c1, &name1) < 0 || qpol_class_get_name(diff->mod_qpol, c2, &name2) < 0) {
00290                 return 0;
00291         }
00292         return strcmp(name1, name2);
00293 }
00294 
00295 /**
00296  * Allocate and return a new class difference object.
00297  *
00298  * @param diff Policy diff error handler.
00299  * @param form Form of the difference.
00300  * @param name Name of the class that is different.
00301  *
00302  * @return A newly allocated and initialized diff, or NULL upon error.
00303  * The caller is responsible for calling class_free() upon the
00304  * returned value.
00305  */
00306 static poldiff_class_t *make_diff(const poldiff_t * diff, poldiff_form_e form, const char *name)
00307 {
00308         poldiff_class_t *pc;
00309         int error;
00310         if ((pc = calloc(1, sizeof(*pc))) == NULL ||
00311             (pc->name = strdup(name)) == NULL ||
00312             (pc->added_perms = apol_vector_create_with_capacity(1, free)) == NULL ||
00313             (pc->removed_perms = apol_vector_create_with_capacity(1, free)) == NULL) {
00314                 error = errno;
00315                 class_free(pc);
00316                 ERR(diff, "%s", strerror(error));
00317                 errno = error;
00318                 return NULL;
00319         }
00320         pc->form = form;
00321         return pc;
00322 }
00323 
00324 int class_new_diff(poldiff_t * diff, poldiff_form_e form, const void *item)
00325 {
00326         const qpol_class_t *c = item;
00327         const char *name = NULL;
00328         poldiff_class_t *pc;
00329         int error;
00330         if ((form == POLDIFF_FORM_ADDED &&
00331              qpol_class_get_name(diff->mod_qpol, c, &name) < 0) ||
00332             ((form == POLDIFF_FORM_REMOVED || form == POLDIFF_FORM_MODIFIED) && qpol_class_get_name(diff->orig_qpol, c, &name) < 0))
00333         {
00334                 return -1;
00335         }
00336         pc = make_diff(diff, form, name);
00337         if (pc == NULL) {
00338                 return -1;
00339         }
00340         if (apol_vector_append(diff->class_diffs->diffs, pc) < 0) {
00341                 error = errno;
00342                 ERR(diff, "%s", strerror(error));
00343                 class_free(pc);
00344                 errno = error;
00345                 return -1;
00346         }
00347         if (form == POLDIFF_FORM_ADDED) {
00348                 diff->class_diffs->num_added++;
00349         } else {
00350                 diff->class_diffs->num_removed++;
00351         }
00352         return 0;
00353 }
00354 
00355 /**
00356  * Given an object class, return a vector of its permissions (in the
00357  * form of strings).  These permissions include those inherited from
00358  * the class's common, if present.
00359  *
00360  * @param diff Policy diff error handler.
00361  * @param p Policy from which the class came.
00362  * @param class Class whose permissions to get.
00363  *
00364  * @return Vector of permissions strings for the class.  The caller is
00365  * responsible for calling apol_vector_destroy().  On error, return
00366  * NULL.
00367  */
00368 static apol_vector_t *class_get_perms(const poldiff_t * diff, const apol_policy_t * p, const qpol_class_t * class)
00369 {
00370         const qpol_common_t *common;
00371         qpol_iterator_t *perm_iter = NULL, *common_iter = NULL;
00372         char *perm;
00373         apol_vector_t *v = NULL;
00374         qpol_policy_t *q = apol_policy_get_qpol(p);
00375         int retval = -1;
00376 
00377         if ((v = apol_vector_create(NULL)) == NULL) {
00378                 ERR(diff, "%s", strerror(errno));
00379                 goto cleanup;
00380         }
00381         if (qpol_class_get_common(q, class, &common) < 0 || qpol_class_get_perm_iter(q, class, &perm_iter) < 0) {
00382                 goto cleanup;
00383         }
00384         for (; !qpol_iterator_end(perm_iter); qpol_iterator_next(perm_iter)) {
00385                 if (qpol_iterator_get_item(perm_iter, (void **)&perm) < 0) {
00386                         goto cleanup;
00387                 }
00388                 if (apol_vector_append(v, perm) < 0) {
00389                         ERR(diff, "%s", strerror(errno));
00390                         goto cleanup;
00391                 }
00392         }
00393         if (common != NULL) {
00394                 if (qpol_common_get_perm_iter(q, common, &common_iter) < 0) {
00395                         goto cleanup;
00396                 }
00397                 for (; !qpol_iterator_end(common_iter); qpol_iterator_next(common_iter)) {
00398                         if (qpol_iterator_get_item(common_iter, (void **)&perm) < 0) {
00399                                 goto cleanup;
00400                         }
00401                         if (apol_vector_append(v, perm) < 0) {
00402                                 ERR(diff, "%s", strerror(errno));
00403                                 goto cleanup;
00404                         }
00405                 }
00406         }
00407 
00408         retval = 0;
00409       cleanup:
00410         qpol_iterator_destroy(&perm_iter);
00411         qpol_iterator_destroy(&common_iter);
00412         if (retval < 0) {
00413                 apol_vector_destroy(&v);
00414                 return NULL;
00415         }
00416         return v;
00417 }
00418 
00419 int class_deep_diff(poldiff_t * diff, const void *x, const void *y)
00420 {
00421         const qpol_class_t *c1 = x;
00422         const qpol_class_t *c2 = y;
00423         apol_vector_t *v1 = NULL, *v2 = NULL;
00424         char *perm1 = NULL, *perm2 = NULL;
00425         const char *name;
00426         poldiff_class_t *c = NULL;
00427         size_t i, j;
00428         int retval = -1, error = 0, compval;
00429 
00430         if (qpol_class_get_name(diff->orig_qpol, c1, &name) < 0 ||
00431             (v1 = class_get_perms(diff, diff->orig_pol, c1)) == NULL || (v2 = class_get_perms(diff, diff->mod_pol, c2)) == NULL) {
00432                 error = errno;
00433                 goto cleanup;
00434         }
00435         apol_vector_sort(v1, apol_str_strcmp, NULL);
00436         apol_vector_sort(v2, apol_str_strcmp, NULL);
00437         for (i = j = 0; i < apol_vector_get_size(v1);) {
00438                 if (j >= apol_vector_get_size(v2))
00439                         break;
00440                 perm1 = (char *)apol_vector_get_element(v1, i);
00441                 perm2 = (char *)apol_vector_get_element(v2, j);
00442                 compval = strcmp(perm1, perm2);
00443                 if (compval != 0 && c == NULL) {
00444                         if ((c = make_diff(diff, POLDIFF_FORM_MODIFIED, name)) == NULL) {
00445                                 error = errno;
00446                                 goto cleanup;
00447                         }
00448                 }
00449                 if (compval < 0) {
00450                         if ((perm1 = strdup(perm1)) == NULL || apol_vector_append(c->removed_perms, perm1) < 0) {
00451                                 error = errno;
00452                                 free(perm1);
00453                                 ERR(diff, "%s", strerror(error));
00454                                 goto cleanup;
00455                         }
00456                         i++;
00457                 } else if (compval > 0) {
00458                         if ((perm2 = strdup(perm2)) == NULL || apol_vector_append(c->added_perms, perm2) < 0) {
00459                                 error = errno;
00460                                 free(perm2);
00461                                 ERR(diff, "%s", strerror(error));
00462                                 goto cleanup;
00463                         }
00464                         j++;
00465                 } else {
00466                         i++;
00467                         j++;
00468                 }
00469         }
00470         for (; i < apol_vector_get_size(v1); i++) {
00471                 perm1 = (char *)apol_vector_get_element(v1, i);
00472                 if (c == NULL) {
00473                         if ((c = make_diff(diff, POLDIFF_FORM_MODIFIED, name)) == NULL) {
00474                                 error = errno;
00475                                 goto cleanup;
00476                         }
00477                 }
00478                 if ((perm1 = strdup(perm1)) == NULL || apol_vector_append(c->removed_perms, perm1) < 0) {
00479                         error = errno;
00480                         free(perm1);
00481                         ERR(diff, "%s", strerror(error));
00482                         goto cleanup;
00483                 }
00484         }
00485         for (; j < apol_vector_get_size(v2); j++) {
00486                 perm2 = (char *)apol_vector_get_element(v2, j);
00487                 if (c == NULL) {
00488                         if ((c = make_diff(diff, POLDIFF_FORM_MODIFIED, name)) == NULL) {
00489                                 error = errno;
00490                                 goto cleanup;
00491                         }
00492                 }
00493                 if ((perm2 = strdup(perm2)) == NULL || apol_vector_append(c->added_perms, perm2) < 0) {
00494                         error = errno;
00495                         free(perm2);
00496                         ERR(diff, "%s", strerror(error));
00497                         goto cleanup;
00498                 }
00499         }
00500         if (c != NULL) {
00501                 apol_vector_sort(c->removed_perms, apol_str_strcmp, NULL);
00502                 apol_vector_sort(c->added_perms, apol_str_strcmp, NULL);
00503                 if (apol_vector_append(diff->class_diffs->diffs, c) < 0) {
00504                         error = errno;
00505                         ERR(diff, "%s", strerror(error));
00506                         goto cleanup;
00507                 }
00508                 diff->class_diffs->num_modified++;
00509         }
00510         retval = 0;
00511       cleanup:
00512         apol_vector_destroy(&v1);
00513         apol_vector_destroy(&v2);
00514         if (retval != 0) {
00515                 class_free(c);
00516         }
00517         errno = error;
00518         return retval;
00519 }
00520 
00521 /******************** common classes ********************/
00522 
00523 struct poldiff_common_summary
00524 {
00525         size_t num_added;
00526         size_t num_removed;
00527         size_t num_modified;
00528         apol_vector_t *diffs;
00529 };
00530 
00531 struct poldiff_common
00532 {
00533         char *name;
00534         poldiff_form_e form;
00535         apol_vector_t *added_perms;
00536         apol_vector_t *removed_perms;
00537 };
00538 
00539 void poldiff_common_get_stats(const poldiff_t * diff, size_t stats[5])
00540 {
00541         if (diff == NULL || stats == NULL) {
00542                 ERR(diff, "%s", strerror(EINVAL));
00543                 errno = EINVAL;
00544                 return;
00545         }
00546         stats[0] = diff->common_diffs->num_added;
00547         stats[1] = diff->common_diffs->num_removed;
00548         stats[2] = diff->common_diffs->num_modified;
00549         stats[3] = 0;
00550         stats[4] = 0;
00551 }
00552 
00553 char *poldiff_common_to_string(const poldiff_t * diff, const void *cls)
00554 {
00555         poldiff_common_t *c = (poldiff_common_t *) cls;
00556         size_t num_added, num_removed, len = 0, i;
00557         char *s = NULL, *perm;
00558         if (diff == NULL || cls == NULL) {
00559                 ERR(diff, "%s", strerror(EINVAL));
00560                 errno = EINVAL;
00561                 return NULL;
00562         }
00563         num_added = apol_vector_get_size(c->added_perms);
00564         num_removed = apol_vector_get_size(c->removed_perms);
00565         switch (c->form) {
00566         case POLDIFF_FORM_ADDED:
00567         {
00568                 if (apol_str_appendf(&s, &len, "+ %s", c->name) < 0) {
00569                         s = NULL;
00570                         break;
00571                 }
00572                 return s;
00573         }
00574         case POLDIFF_FORM_REMOVED:
00575         {
00576                 if (apol_str_appendf(&s, &len, "- %s", c->name) < 0) {
00577                         s = NULL;
00578                         break;
00579                 }
00580                 return s;
00581         }
00582         case POLDIFF_FORM_MODIFIED:
00583         {
00584                 if (apol_str_appendf(&s, &len, "* %s (", c->name) < 0) {
00585                         s = NULL;
00586                         break;
00587                 }
00588                 if (num_added > 0) {
00589                         if (apol_str_appendf(&s, &len, "%zd Added Permission%s", num_added, (num_added == 1 ? "" : "s")) < 0) {
00590                                 break;
00591                         }
00592                 }
00593                 if (num_removed > 0) {
00594                         if (apol_str_appendf
00595                             (&s, &len, "%s%zd Removed Permission%s", (num_added > 0 ? ", " : ""), num_removed,
00596                              (num_removed == 1 ? "" : "s")) < 0) {
00597                                 break;
00598                         }
00599                 }
00600                 if (apol_str_append(&s, &len, ")\n") < 0) {
00601                         break;
00602                 }
00603                 for (i = 0; i < apol_vector_get_size(c->added_perms); i++) {
00604                         perm = (char *)apol_vector_get_element(c->added_perms, i);
00605                         if (apol_str_appendf(&s, &len, "\t+ %s\n", perm) < 0) {
00606                                 goto err;
00607                         }
00608                 }
00609                 for (i = 0; i < apol_vector_get_size(c->removed_perms); i++) {
00610                         perm = (char *)apol_vector_get_element(c->removed_perms, i);
00611                         if (apol_str_appendf(&s, &len, "\t- %s\n", perm) < 0) {
00612                                 goto err;
00613                         }
00614                 }
00615                 return s;
00616         }
00617         default:
00618         {
00619                 ERR(diff, "%s", strerror(ENOTSUP));
00620                 errno = ENOTSUP;
00621                 return NULL;
00622         }
00623         }
00624       err:
00625         /* if this is reached then an error occurred */
00626         free(s);
00627         ERR(diff, "%s", strerror(ENOMEM));
00628         errno = ENOMEM;
00629         return NULL;
00630 }
00631 
00632 const apol_vector_t *poldiff_get_common_vector(const poldiff_t * diff)
00633 {
00634         if (diff == NULL) {
00635                 errno = EINVAL;
00636                 return NULL;
00637         }
00638         return diff->common_diffs->diffs;
00639 }
00640 
00641 const char *poldiff_common_get_name(const poldiff_common_t * cls)
00642 {
00643         if (cls == NULL) {
00644                 errno = EINVAL;
00645                 return NULL;
00646         }
00647         return cls->name;
00648 }
00649 
00650 poldiff_form_e poldiff_common_get_form(const void *cls)
00651 {
00652         if (cls == NULL) {
00653                 errno = EINVAL;
00654                 return 0;
00655         }
00656         return ((const poldiff_common_t *)cls)->form;
00657 }
00658 
00659 const apol_vector_t *poldiff_common_get_added_perms(const poldiff_common_t * cls)
00660 {
00661         if (cls == NULL) {
00662                 errno = EINVAL;
00663                 return NULL;
00664         }
00665         return cls->added_perms;
00666 }
00667 
00668 const apol_vector_t *poldiff_common_get_removed_perms(const poldiff_common_t * cls)
00669 {
00670         if (cls == NULL) {
00671                 errno = EINVAL;
00672                 return NULL;
00673         }
00674         return cls->removed_perms;
00675 }
00676 
00677 /*************** protected functions for common classes ***************/
00678 
00679 static void common_free(void *elem)
00680 {
00681         if (elem != NULL) {
00682                 poldiff_common_t *c = (poldiff_common_t *) elem;
00683                 free(c->name);
00684                 apol_vector_destroy(&c->added_perms);
00685                 apol_vector_destroy(&c->removed_perms);
00686                 free(c);
00687         }
00688 }
00689 
00690 poldiff_common_summary_t *common_create(void)
00691 {
00692         poldiff_common_summary_t *cs = calloc(1, sizeof(*cs));
00693         if (cs == NULL) {
00694                 return NULL;
00695         }
00696         if ((cs->diffs = apol_vector_create(common_free)) == NULL) {
00697                 common_destroy(&cs);
00698                 return NULL;
00699         }
00700         return cs;
00701 }
00702 
00703 void common_destroy(poldiff_common_summary_t ** cs)
00704 {
00705         if (cs != NULL && *cs != NULL) {
00706                 apol_vector_destroy(&(*cs)->diffs);
00707                 free(*cs);
00708                 *cs = NULL;
00709         }
00710 }
00711 
00712 int common_reset(poldiff_t * diff)
00713 {
00714         int error = 0;
00715 
00716         if (diff == NULL) {
00717                 ERR(diff, "%s", strerror(EINVAL));
00718                 errno = EINVAL;
00719                 return -1;
00720         }
00721 
00722         common_destroy(&diff->common_diffs);
00723         diff->common_diffs = common_create();
00724         if (diff->common_diffs == NULL) {
00725                 error = errno;
00726                 ERR(diff, "%s", strerror(error));
00727                 errno = error;
00728                 return -1;
00729         }
00730 
00731         return 0;
00732 }
00733 
00734 /**
00735  * Comparison function for two commons from the same policy.
00736  */
00737 static int common_name_comp(const void *x, const void *y, void *arg)
00738 {
00739         const qpol_common_t *c1 = x;
00740         const qpol_common_t *c2 = y;
00741         apol_policy_t *p = (apol_policy_t *) arg;
00742         qpol_policy_t *q = apol_policy_get_qpol(p);
00743         const char *name1, *name2;
00744         if (qpol_common_get_name(q, c1, &name1) < 0 || qpol_common_get_name(q, c2, &name2) < 0) {
00745                 return 0;
00746         }
00747         return strcmp(name1, name2);
00748 }
00749 
00750 apol_vector_t *common_get_items(poldiff_t * diff, const apol_policy_t * policy)
00751 {
00752         qpol_iterator_t *iter = NULL;
00753         apol_vector_t *v = NULL;
00754         qpol_policy_t *q = apol_policy_get_qpol(policy);
00755         int error = 0;
00756         if (qpol_policy_get_common_iter(q, &iter) < 0) {
00757                 return NULL;
00758         }
00759         v = apol_vector_create_from_iter(iter, NULL);
00760         if (v == NULL) {
00761                 error = errno;
00762                 ERR(diff, "%s", strerror(error));
00763                 qpol_iterator_destroy(&iter);
00764                 errno = error;
00765                 return NULL;
00766         }
00767         qpol_iterator_destroy(&iter);
00768         apol_vector_sort(v, common_name_comp, (void *)policy);
00769         return v;
00770 }
00771 
00772 int common_comp(const void *x, const void *y, const poldiff_t * diff)
00773 {
00774         const qpol_common_t *c1 = x;
00775         const qpol_common_t *c2 = y;
00776         const char *name1, *name2;
00777         if (qpol_common_get_name(diff->orig_qpol, c1, &name1) < 0 || qpol_common_get_name(diff->mod_qpol, c2, &name2) < 0) {
00778                 return 0;
00779         }
00780         return strcmp(name1, name2);
00781 }
00782 
00783 /**
00784  * Allocate and return a new common difference object.
00785  *
00786  * @param diff Policy diff error handler.
00787  * @param form Form of the difference.
00788  * @param name Name of the common that is different.
00789  *
00790  * @return A newly allocated and initialized diff, or NULL upon error.
00791  * The caller is responsible for calling common_free() upon the
00792  * returned value.
00793  */
00794 static poldiff_common_t *make_common_diff(const poldiff_t * diff, poldiff_form_e form, const char *name)
00795 {
00796         poldiff_common_t *pc;
00797         int error;
00798         if ((pc = calloc(1, sizeof(*pc))) == NULL ||
00799             (pc->name = strdup(name)) == NULL ||
00800             (pc->added_perms = apol_vector_create_with_capacity(1, free)) == NULL ||
00801             (pc->removed_perms = apol_vector_create_with_capacity(1, free)) == NULL) {
00802                 error = errno;
00803                 common_free(pc);
00804                 ERR(diff, "%s", strerror(error));
00805                 errno = error;
00806                 return NULL;
00807         }
00808         pc->form = form;
00809         return pc;
00810 }
00811 
00812 int common_new_diff(poldiff_t * diff, poldiff_form_e form, const void *item)
00813 {
00814         const qpol_common_t *c = item;
00815         const char *name = NULL;
00816         poldiff_common_t *pc;
00817         int error;
00818         if ((form == POLDIFF_FORM_ADDED &&
00819              qpol_common_get_name(diff->mod_qpol, c, &name) < 0) ||
00820             ((form == POLDIFF_FORM_REMOVED || form == POLDIFF_FORM_MODIFIED) &&
00821              qpol_common_get_name(diff->orig_qpol, c, &name) < 0)) {
00822                 return -1;
00823         }
00824         pc = make_common_diff(diff, form, name);
00825         if (pc == NULL) {
00826                 return -1;
00827         }
00828         if (apol_vector_append(diff->common_diffs->diffs, pc) < 0) {
00829                 error = errno;
00830                 ERR(diff, "%s", strerror(error));
00831                 common_free(pc);
00832                 errno = error;
00833                 return -1;
00834         }
00835         if (form == POLDIFF_FORM_ADDED) {
00836                 diff->common_diffs->num_added++;
00837         } else {
00838                 diff->common_diffs->num_removed++;
00839         }
00840         return 0;
00841 }
00842 
00843 /**
00844  * Given a common class, return a vector of its permissions (in the
00845  * form of strings).
00846  *
00847  * @param diff Policy diff error handler.
00848  * @param p Policy from which the common came.
00849  * @param common Common whose permissions to get.
00850  *
00851  * @return Vector of permissions strings for the common.  The caller
00852  * is responsible for calling apol_vector_destroy().  On error, return
00853  * NULL.
00854  */
00855 static apol_vector_t *common_get_perms(const poldiff_t * diff, const apol_policy_t * p, const qpol_common_t * common)
00856 {
00857         qpol_iterator_t *perm_iter = NULL;
00858         char *perm;
00859         apol_vector_t *v = NULL;
00860         qpol_policy_t *q = apol_policy_get_qpol(p);
00861         int retval = -1;
00862 
00863         if ((v = apol_vector_create(NULL)) == NULL) {
00864                 ERR(diff, "%s", strerror(errno));
00865                 goto cleanup;
00866         }
00867         if (qpol_common_get_perm_iter(q, common, &perm_iter) < 0) {
00868                 goto cleanup;
00869         }
00870         for (; !qpol_iterator_end(perm_iter); qpol_iterator_next(perm_iter)) {
00871                 if (qpol_iterator_get_item(perm_iter, (void **)&perm) < 0) {
00872                         goto cleanup;
00873                 }
00874                 if (apol_vector_append(v, perm) < 0) {
00875                         ERR(diff, "%s", strerror(errno));
00876                         goto cleanup;
00877                 }
00878         }
00879 
00880         retval = 0;
00881       cleanup:
00882         qpol_iterator_destroy(&perm_iter);
00883         if (retval < 0) {
00884                 apol_vector_destroy(&v);
00885                 return NULL;
00886         }
00887         return v;
00888 }
00889 
00890 int common_deep_diff(poldiff_t * diff, const void *x, const void *y)
00891 {
00892         const qpol_common_t *c1 = x;
00893         const qpol_common_t *c2 = y;
00894         apol_vector_t *v1 = NULL, *v2 = NULL;
00895         char *perm1 = NULL, *perm2 = NULL;
00896         const char *name;
00897         poldiff_common_t *c = NULL;
00898         size_t i, j;
00899         int retval = -1, error = 0, compval;
00900 
00901         if (qpol_common_get_name(diff->orig_qpol, c1, &name) < 0 ||
00902             (v1 = common_get_perms(diff, diff->orig_pol, c1)) == NULL || (v2 = common_get_perms(diff, diff->mod_pol, c2)) == NULL) {
00903                 error = errno;
00904                 goto cleanup;
00905         }
00906         apol_vector_sort(v1, apol_str_strcmp, NULL);
00907         apol_vector_sort(v2, apol_str_strcmp, NULL);
00908         for (i = j = 0; i < apol_vector_get_size(v1);) {
00909                 if (j >= apol_vector_get_size(v2))
00910                         break;
00911                 perm1 = (char *)apol_vector_get_element(v1, i);
00912                 perm2 = (char *)apol_vector_get_element(v2, j);
00913                 compval = strcmp(perm1, perm2);
00914                 if (compval != 0 && c == NULL) {
00915                         if ((c = make_common_diff(diff, POLDIFF_FORM_MODIFIED, name)) == NULL) {
00916                                 error = errno;
00917                                 goto cleanup;
00918                         }
00919                 }
00920                 if (compval < 0) {
00921                         if ((perm1 = strdup(perm1)) == NULL || apol_vector_append(c->removed_perms, perm1) < 0) {
00922                                 error = errno;
00923                                 free(perm1);
00924                                 ERR(diff, "%s", strerror(error));
00925                                 goto cleanup;
00926                         }
00927                         i++;
00928                 } else if (compval > 0) {
00929                         if ((perm2 = strdup(perm2)) == NULL || apol_vector_append(c->added_perms, perm2) < 0) {
00930                                 error = errno;
00931                                 free(perm2);
00932                                 ERR(diff, "%s", strerror(error));
00933                                 goto cleanup;
00934                         }
00935                         j++;
00936                 } else {
00937                         i++;
00938                         j++;
00939                 }
00940         }
00941         for (; i < apol_vector_get_size(v1); i++) {
00942                 perm1 = (char *)apol_vector_get_element(v1, i);
00943                 if (c == NULL) {
00944                         if ((c = make_common_diff(diff, POLDIFF_FORM_MODIFIED, name)) == NULL) {
00945                                 error = errno;
00946                                 goto cleanup;
00947                         }
00948                 }
00949                 if ((perm1 = strdup(perm1)) == NULL || apol_vector_append(c->removed_perms, perm1) < 0) {
00950                         error = errno;
00951                         free(perm1);
00952                         ERR(diff, "%s", strerror(error));
00953                         goto cleanup;
00954                 }
00955         }
00956         for (; j < apol_vector_get_size(v2); j++) {
00957                 perm2 = (char *)apol_vector_get_element(v2, j);
00958                 if (c == NULL) {
00959                         if ((c = make_common_diff(diff, POLDIFF_FORM_MODIFIED, name)) == NULL) {
00960                                 error = errno;
00961                                 goto cleanup;
00962                         }
00963                 }
00964                 if ((perm2 = strdup(perm2)) == NULL || apol_vector_append(c->added_perms, perm2) < 0) {
00965                         error = errno;
00966                         free(perm2);
00967                         ERR(diff, "%s", strerror(error));
00968                         goto cleanup;
00969                 }
00970         }
00971         if (c != NULL) {
00972                 apol_vector_sort(c->removed_perms, apol_str_strcmp, NULL);
00973                 apol_vector_sort(c->added_perms, apol_str_strcmp, NULL);
00974                 if (apol_vector_append(diff->common_diffs->diffs, c) < 0) {
00975                         error = errno;
00976                         ERR(diff, "%s", strerror(error));
00977                         goto cleanup;
00978                 }
00979                 diff->common_diffs->num_modified++;
00980         }
00981         retval = 0;
00982       cleanup:
00983         apol_vector_destroy(&v1);
00984         apol_vector_destroy(&v2);
00985         if (retval != 0) {
00986                 common_free(c);
00987         }
00988         errno = error;
00989         return retval;
00990 }