role_diff.c

Go to the documentation of this file.
00001 /**
00002  *  @file
00003  *  Implementation for computing semantic differences in roles.
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 
00029 #include <apol/util.h>
00030 #include <errno.h>
00031 #include <stdio.h>
00032 #include <string.h>
00033 
00034 struct poldiff_role_summary
00035 {
00036         size_t num_added;
00037         size_t num_removed;
00038         size_t num_modified;
00039         apol_vector_t *diffs;
00040 };
00041 
00042 struct poldiff_role
00043 {
00044         char *name;
00045         poldiff_form_e form;
00046         apol_vector_t *added_types;
00047         apol_vector_t *removed_types;
00048 };
00049 
00050 void poldiff_role_get_stats(const poldiff_t * diff, size_t stats[5])
00051 {
00052         if (diff == NULL || stats == NULL) {
00053                 ERR(diff, "%s", strerror(EINVAL));
00054                 errno = EINVAL;
00055                 return;
00056         }
00057         stats[0] = diff->role_diffs->num_added;
00058         stats[1] = diff->role_diffs->num_removed;
00059         stats[2] = diff->role_diffs->num_modified;
00060         stats[3] = 0;
00061         stats[4] = 0;
00062 }
00063 
00064 char *poldiff_role_to_string(const poldiff_t * diff, const void *role)
00065 {
00066         const poldiff_role_t *r = role;
00067         size_t num_added, num_removed, len = 0, i;
00068         char *s = NULL, *type;
00069         if (diff == NULL || role == NULL) {
00070                 ERR(diff, "%s", strerror(EINVAL));
00071                 errno = EINVAL;
00072                 return NULL;
00073         }
00074         num_added = apol_vector_get_size(r->added_types);
00075         num_removed = apol_vector_get_size(r->removed_types);
00076         switch (r->form) {
00077         case POLDIFF_FORM_ADDED:
00078         {
00079                 if (apol_str_appendf(&s, &len, "+ %s", r->name) < 0) {
00080                         s = NULL;
00081                         break;
00082                 }
00083                 return s;
00084         }
00085         case POLDIFF_FORM_REMOVED:
00086         {
00087                 if (apol_str_appendf(&s, &len, "- %s", r->name) < 0) {
00088                         s = NULL;
00089                         break;
00090                 }
00091                 return s;
00092         }
00093         case POLDIFF_FORM_MODIFIED:
00094         {
00095                 if (apol_str_appendf(&s, &len, "* %s (", r->name) < 0) {
00096                         s = NULL;
00097                         break;
00098                 }
00099                 if (num_added > 0) {
00100                         if (apol_str_appendf(&s, &len, "%zd Added Type%s", num_added, (num_added == 1 ? "" : "s")) < 0) {
00101                                 break;
00102                         }
00103                 }
00104                 if (num_removed > 0) {
00105                         if (apol_str_appendf
00106                             (&s, &len, "%s%zd Removed Type%s", (num_added > 0 ? ", " : ""), num_removed,
00107                              (num_removed == 1 ? "" : "s")) < 0) {
00108                                 break;
00109                         }
00110                 }
00111                 if (apol_str_append(&s, &len, ")\n") < 0) {
00112                         break;
00113                 }
00114                 for (i = 0; i < apol_vector_get_size(r->added_types); i++) {
00115                         type = (char *)apol_vector_get_element(r->added_types, i);
00116                         if (apol_str_appendf(&s, &len, "\t+ %s\n", type) < 0) {
00117                                 goto err;
00118                         }
00119                 }
00120                 for (i = 0; i < apol_vector_get_size(r->removed_types); i++) {
00121                         type = (char *)apol_vector_get_element(r->removed_types, i);
00122                         if (apol_str_appendf(&s, &len, "\t- %s\n", type) < 0) {
00123                                 goto err;
00124                         }
00125                 }
00126                 return s;
00127         }
00128         default:
00129         {
00130                 ERR(diff, "%s", strerror(ENOTSUP));
00131                 errno = ENOTSUP;
00132                 return NULL;
00133         }
00134         }
00135       err:
00136         /* if this is reached then an error occurred */
00137         free(s);
00138         ERR(diff, "%s", strerror(ENOMEM));
00139         errno = ENOMEM;
00140         return NULL;
00141 }
00142 
00143 const apol_vector_t *poldiff_get_role_vector(const poldiff_t * diff)
00144 {
00145         if (diff == NULL) {
00146                 errno = EINVAL;
00147                 return NULL;
00148         }
00149         return diff->role_diffs->diffs;
00150 }
00151 
00152 const char *poldiff_role_get_name(const poldiff_role_t * role)
00153 {
00154         if (role == NULL) {
00155                 errno = EINVAL;
00156                 return NULL;
00157         }
00158         return role->name;
00159 }
00160 
00161 poldiff_form_e poldiff_role_get_form(const void *role)
00162 {
00163         if (role == NULL) {
00164                 errno = EINVAL;
00165                 return 0;
00166         }
00167         return ((const poldiff_role_t *)role)->form;
00168 }
00169 
00170 const apol_vector_t *poldiff_role_get_added_types(const poldiff_role_t * role)
00171 {
00172         if (role == NULL) {
00173                 errno = EINVAL;
00174                 return NULL;
00175         }
00176         return role->added_types;
00177 }
00178 
00179 const apol_vector_t *poldiff_role_get_removed_types(const poldiff_role_t * role)
00180 {
00181         if (role == NULL) {
00182                 errno = EINVAL;
00183                 return NULL;
00184         }
00185         return role->removed_types;
00186 }
00187 
00188 /*************** protected functions for roles ***************/
00189 
00190 static void role_free(void *elem)
00191 {
00192         if (elem != NULL) {
00193                 poldiff_role_t *r = (poldiff_role_t *) elem;
00194                 free(r->name);
00195                 apol_vector_destroy(&r->added_types);
00196                 apol_vector_destroy(&r->removed_types);
00197                 free(r);
00198         }
00199 }
00200 
00201 poldiff_role_summary_t *role_create(void)
00202 {
00203         poldiff_role_summary_t *rs = calloc(1, sizeof(*rs));
00204         if (rs == NULL) {
00205                 return NULL;
00206         }
00207         if ((rs->diffs = apol_vector_create(role_free)) == NULL) {
00208                 role_destroy(&rs);
00209                 return NULL;
00210         }
00211         return rs;
00212 }
00213 
00214 void role_destroy(poldiff_role_summary_t ** rs)
00215 {
00216         if (rs != NULL && *rs != NULL) {
00217                 apol_vector_destroy(&(*rs)->diffs);
00218                 free(*rs);
00219                 *rs = NULL;
00220         }
00221 }
00222 
00223 int role_reset(poldiff_t * diff)
00224 {
00225         int error = 0;
00226 
00227         if (diff == NULL) {
00228                 ERR(diff, "%s", strerror(EINVAL));
00229                 errno = EINVAL;
00230                 return -1;
00231         }
00232 
00233         role_destroy(&diff->role_diffs);
00234         diff->role_diffs = role_create();
00235         if (diff->role_diffs == NULL) {
00236                 error = errno;
00237                 ERR(diff, "%s", strerror(error));
00238                 errno = error;
00239                 return -1;
00240         }
00241 
00242         return 0;
00243 }
00244 
00245 /**
00246  * Comparison function for two roles from the same policy.
00247  */
00248 static int role_name_comp(const void *x, const void *y, void *arg)
00249 {
00250         const qpol_role_t *r1 = x;
00251         const qpol_role_t *r2 = y;
00252         apol_policy_t *p = (apol_policy_t *) arg;
00253         qpol_policy_t *q = apol_policy_get_qpol(p);
00254         const char *name1, *name2;
00255         if (qpol_role_get_name(q, r1, &name1) < 0 || qpol_role_get_name(q, r2, &name2) < 0) {
00256                 return 0;
00257         }
00258         return strcmp(name1, name2);
00259 }
00260 
00261 apol_vector_t *role_get_items(poldiff_t * diff, const apol_policy_t * policy)
00262 {
00263         qpol_iterator_t *iter = NULL;
00264         apol_vector_t *v = NULL;
00265         qpol_policy_t *q = apol_policy_get_qpol(policy);
00266         int error = 0;
00267         if (qpol_policy_get_role_iter(q, &iter) < 0) {
00268                 return NULL;
00269         }
00270         v = apol_vector_create_from_iter(iter, NULL);
00271         if (v == NULL) {
00272                 error = errno;
00273                 ERR(diff, "%s", strerror(error));
00274                 qpol_iterator_destroy(&iter);
00275                 errno = error;
00276                 return NULL;
00277         }
00278         qpol_iterator_destroy(&iter);
00279         apol_vector_sort(v, role_name_comp, (void *)policy);
00280         return v;
00281 }
00282 
00283 int role_comp(const void *x, const void *y, const poldiff_t * diff)
00284 {
00285         const qpol_role_t *r1 = x;
00286         const qpol_role_t *r2 = y;
00287         const char *name1, *name2;
00288         if (qpol_role_get_name(diff->orig_qpol, r1, &name1) < 0 || qpol_role_get_name(diff->mod_qpol, r2, &name2) < 0) {
00289                 return 0;
00290         }
00291         return strcmp(name1, name2);
00292 }
00293 
00294 /**
00295  * Allocate and return a new role difference object.
00296  *
00297  * @param diff Policy diff error handler.
00298  * @param form Form of the difference.
00299  * @param name Name of the role that is different.
00300  *
00301  * @return A newly allocated and initialized diff, or NULL upon error.
00302  * The caller is responsible for calling role_free() upon the returned
00303  * value.
00304  */
00305 static poldiff_role_t *make_diff(const poldiff_t * diff, poldiff_form_e form, const char *name)
00306 {
00307         poldiff_role_t *pr;
00308         int error;
00309         if ((pr = calloc(1, sizeof(*pr))) == NULL ||
00310             (pr->name = strdup(name)) == NULL ||
00311             (pr->added_types = apol_vector_create_with_capacity(1, free)) == NULL ||
00312             (pr->removed_types = apol_vector_create_with_capacity(1, free)) == NULL) {
00313                 error = errno;
00314                 role_free(pr);
00315                 ERR(diff, "%s", strerror(error));
00316                 errno = error;
00317                 return NULL;
00318         }
00319         pr->form = form;
00320         return pr;
00321 }
00322 
00323 int role_new_diff(poldiff_t * diff, poldiff_form_e form, const void *item)
00324 {
00325         const qpol_role_t *r = item;
00326         const char *name = NULL;
00327         poldiff_role_t *pr;
00328         int error;
00329         if ((form == POLDIFF_FORM_ADDED &&
00330              qpol_role_get_name(diff->mod_qpol, r, &name) < 0) ||
00331             ((form == POLDIFF_FORM_REMOVED || form == POLDIFF_FORM_MODIFIED) && qpol_role_get_name(diff->orig_qpol, r, &name) < 0))
00332         {
00333                 return -1;
00334         }
00335         pr = make_diff(diff, form, name);
00336         if (pr == NULL) {
00337                 return -1;
00338         }
00339         if (apol_vector_append(diff->role_diffs->diffs, pr) < 0) {
00340                 error = errno;
00341                 ERR(diff, "%s", strerror(error));
00342                 role_free(pr);
00343                 errno = error;
00344                 return -1;
00345         }
00346         if (form == POLDIFF_FORM_ADDED) {
00347                 diff->role_diffs->num_added++;
00348         } else {
00349                 diff->role_diffs->num_removed++;
00350         }
00351         return 0;
00352 }
00353 
00354 /**
00355  * Given a role, return an unsorted vector of its allowed types (in
00356  * the form of uint32_t corresponding to pseudo-type values).
00357  *
00358  * @param diff Policy diff error handler.
00359  * @param role Role whose roles to get.
00360  * @param which Which policy, one of POLDIFF_POLICY_ORIG or
00361  * POLDIFF_POLICY_MOD.
00362  *
00363  * @return Vector of pseudo-type values.  The caller is responsible
00364  * for calling apol_vector_destroy().  On error, return NULL.
00365  */
00366 static apol_vector_t *role_get_types(const poldiff_t * diff, const qpol_role_t * role, int which)
00367 {
00368         qpol_iterator_t *iter = NULL;
00369         const qpol_type_t *type;
00370         uint32_t new_val;
00371         apol_vector_t *v = NULL;
00372         int retval = -1, error = 0;
00373 
00374         if ((v = apol_vector_create(NULL)) == NULL) {
00375                 ERR(diff, "%s", strerror(errno));
00376                 goto cleanup;
00377         }
00378         if (which == POLDIFF_POLICY_ORIG) {
00379                 if (qpol_role_get_type_iter(diff->orig_qpol, role, &iter) < 0) {
00380                         goto cleanup;
00381                 }
00382         } else {
00383                 if (qpol_role_get_type_iter(diff->mod_qpol, role, &iter) < 0) {
00384                         goto cleanup;
00385                 }
00386         }
00387         for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
00388                 if (qpol_iterator_get_item(iter, (void **)&type) < 0 || (new_val = type_map_lookup(diff, type, which)) == 0) {
00389                         error = errno;
00390                         goto cleanup;
00391                 }
00392                 if (apol_vector_append(v, (void *)((size_t) new_val)) < 0) {
00393                         error = errno;
00394                         ERR(diff, "%s", strerror(error));
00395                         goto cleanup;
00396                 }
00397         }
00398 
00399         retval = 0;
00400       cleanup:
00401         qpol_iterator_destroy(&iter);
00402         if (retval < 0) {
00403                 apol_vector_destroy(&v);
00404                 errno = error;
00405                 return NULL;
00406         }
00407         return v;
00408 }
00409 
00410 int role_deep_diff(poldiff_t * diff, const void *x, const void *y)
00411 {
00412         const qpol_role_t *r1 = x;
00413         const qpol_role_t *r2 = y;
00414         apol_vector_t *v1 = NULL, *v2 = NULL;
00415         apol_vector_t *added_types = NULL, *removed_types = NULL;
00416         const apol_vector_t *reverse_v;
00417         const char *name;
00418         char *new_name;
00419         uint32_t t1, t2;
00420         poldiff_role_t *r = NULL;
00421         qpol_type_t *t;
00422         size_t i, j;
00423         int retval = -1, error = 0;
00424 
00425         if (qpol_role_get_name(diff->orig_qpol, r1, &name) < 0 ||
00426             (v1 = role_get_types(diff, r1, POLDIFF_POLICY_ORIG)) == NULL ||
00427             (v2 = role_get_types(diff, r2, POLDIFF_POLICY_MOD)) == NULL) {
00428                 error = errno;
00429                 goto cleanup;
00430         }
00431         apol_vector_sort_uniquify(v1, NULL, NULL);
00432         apol_vector_sort_uniquify(v2, NULL, NULL);
00433         if ((added_types = apol_vector_create(NULL)) == NULL || (removed_types = apol_vector_create(NULL)) == NULL) {
00434                 error = errno;
00435                 ERR(diff, "%s", strerror(error));
00436                 goto cleanup;
00437         }
00438         for (i = j = 0; i < apol_vector_get_size(v1);) {
00439                 if (j >= apol_vector_get_size(v2))
00440                         break;
00441                 t1 = (uint32_t) ((size_t) apol_vector_get_element(v1, i));
00442                 t2 = (uint32_t) ((size_t) apol_vector_get_element(v2, j));
00443                 if (t2 > t1) {
00444                         if (apol_vector_append(removed_types, (void *)((size_t) t1)) < 0) {
00445                                 error = errno;
00446                                 ERR(diff, "%s", strerror(error));
00447                                 goto cleanup;
00448                         }
00449                         i++;
00450                 } else if (t1 > t2) {
00451                         if (apol_vector_append(added_types, (void *)((size_t) t2)) < 0) {
00452                                 error = errno;
00453                                 ERR(diff, "%s", strerror(error));
00454                                 goto cleanup;
00455                         }
00456                         j++;
00457                 } else {
00458                         i++;
00459                         j++;
00460                 }
00461         }
00462         for (; i < apol_vector_get_size(v1); i++) {
00463                 t1 = (uint32_t) ((size_t) apol_vector_get_element(v1, i));
00464                 if (apol_vector_append(removed_types, (void *)((size_t) t1)) < 0) {
00465                         error = errno;
00466                         ERR(diff, "%s", strerror(error));
00467                         goto cleanup;
00468                 }
00469         }
00470         for (; j < apol_vector_get_size(v2); j++) {
00471                 t2 = (uint32_t) ((size_t) apol_vector_get_element(v2, j));
00472                 if (apol_vector_append(added_types, (void *)((size_t) t2)) < 0) {
00473                         error = errno;
00474                         ERR(diff, "%s", strerror(error));
00475                         goto cleanup;
00476                 }
00477         }
00478         if (apol_vector_get_size(added_types) > 0 || apol_vector_get_size(removed_types) > 0) {
00479                 if ((r = make_diff(diff, POLDIFF_FORM_MODIFIED, name)) == NULL) {
00480                         error = errno;
00481                         goto cleanup;
00482                 }
00483                 for (i = 0; i < apol_vector_get_size(removed_types); i++) {
00484                         t1 = (uint32_t) ((size_t) apol_vector_get_element(removed_types, i));
00485                         if ((reverse_v = type_map_lookup_reverse(diff, t1, POLDIFF_POLICY_ORIG)) == NULL) {
00486                                 error = errno;
00487                                 goto cleanup;
00488                         }
00489                         for (j = 0; j < apol_vector_get_size(reverse_v); j++) {
00490                                 t = (qpol_type_t *) apol_vector_get_element(reverse_v, j);
00491                                 if (qpol_type_get_name(diff->orig_qpol, t, &name) < 0) {
00492                                         error = errno;
00493                                         goto cleanup;
00494                                 }
00495                                 if ((new_name = strdup(name)) == NULL || apol_vector_append(r->removed_types, new_name) < 0) {
00496                                         error = errno;
00497                                         free(new_name);
00498                                         ERR(diff, "%s", strerror(error));
00499                                         goto cleanup;
00500                                 }
00501                         }
00502                 }
00503                 for (i = 0; i < apol_vector_get_size(added_types); i++) {
00504                         t2 = (uint32_t) ((size_t) apol_vector_get_element(added_types, i));
00505                         if ((reverse_v = type_map_lookup_reverse(diff, t2, POLDIFF_POLICY_MOD)) == NULL) {
00506                                 error = errno;
00507                                 goto cleanup;
00508                         }
00509                         for (j = 0; j < apol_vector_get_size(reverse_v); j++) {
00510                                 t = (qpol_type_t *) apol_vector_get_element(reverse_v, j);
00511                                 if (qpol_type_get_name(diff->mod_qpol, t, &name) < 0) {
00512                                         error = errno;
00513                                         goto cleanup;
00514                                 }
00515                                 if ((new_name = strdup(name)) == NULL || apol_vector_append(r->added_types, new_name) < 0) {
00516                                         error = errno;
00517                                         free(new_name);
00518                                         ERR(diff, "%s", strerror(error));
00519                                         goto cleanup;
00520                                 }
00521                         }
00522                 }
00523                 apol_vector_sort(r->removed_types, apol_str_strcmp, NULL);
00524                 apol_vector_sort(r->added_types, apol_str_strcmp, NULL);
00525                 if (apol_vector_append(diff->role_diffs->diffs, r) < 0) {
00526                         error = errno;
00527                         ERR(diff, "%s", strerror(error));
00528                         goto cleanup;
00529                 }
00530                 diff->role_diffs->num_modified++;
00531         }
00532         retval = 0;
00533       cleanup:
00534         apol_vector_destroy(&v1);
00535         apol_vector_destroy(&v2);
00536         apol_vector_destroy(&added_types);
00537         apol_vector_destroy(&removed_types);
00538         if (retval != 0) {
00539                 role_free(r);
00540         }
00541         errno = error;
00542         return retval;
00543 }