rbac_diff.c

Go to the documentation of this file.
00001 /**
00002  *  @file
00003  *  Implementation for computing semantic differences in role allow
00004  *  rules and role_transition rules.
00005  *
00006  *  @author Jeremy A. Mowery jmowery@tresys.com
00007  *  @author Jason Tang jtang@tresys.com
00008  *
00009  *  Copyright (C) 2006-2007 Tresys Technology, LLC
00010  *
00011  *  This library is free software; you can redistribute it and/or
00012  *  modify it under the terms of the GNU Lesser General Public
00013  *  License as published by the Free Software Foundation; either
00014  *  version 2.1 of the License, or (at your option) any later version.
00015  *
00016  *  This library is distributed in the hope that it will be useful,
00017  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00018  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00019  *  Lesser General Public License for more details.
00020  *
00021  *  You should have received a copy of the GNU Lesser General Public
00022  *  License along with this library; if not, write to the Free Software
00023  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
00024  */
00025 
00026 #include <config.h>
00027 
00028 #include "poldiff_internal.h"
00029 
00030 #include <apol/bst.h>
00031 #include <apol/util.h>
00032 #include <assert.h>
00033 #include <errno.h>
00034 #include <stdio.h>
00035 #include <string.h>
00036 
00037 struct poldiff_role_allow_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_role_trans_summary
00046 {
00047         size_t num_added;
00048         size_t num_removed;
00049         size_t num_modified;
00050         size_t num_added_type;
00051         size_t num_removed_type;
00052         apol_vector_t *diffs;
00053 };
00054 
00055 struct poldiff_role_allow
00056 {
00057         const char *source_role;
00058         poldiff_form_e form;
00059         apol_vector_t *orig_roles;
00060         apol_vector_t *added_roles;
00061         apol_vector_t *removed_roles;
00062 };
00063 
00064 struct poldiff_role_trans
00065 {
00066         const char *source_role;
00067         char *target_type;
00068         const char *orig_default;
00069         const char *mod_default;
00070         poldiff_form_e form;
00071 };
00072 
00073 /**************** role allow functions *******************/
00074 
00075 void poldiff_role_allow_get_stats(const poldiff_t * diff, size_t stats[5])
00076 {
00077         if (diff == NULL || stats == NULL) {
00078                 ERR(diff, "%s", strerror(EINVAL));
00079                 errno = EINVAL;
00080                 return;
00081         }
00082         stats[0] = diff->role_allow_diffs->num_added;
00083         stats[1] = diff->role_allow_diffs->num_removed;
00084         stats[2] = diff->role_allow_diffs->num_modified;
00085         stats[3] = 0;
00086         stats[4] = 0;
00087 }
00088 
00089 char *poldiff_role_allow_to_string(const poldiff_t * diff, const void *role_allow)
00090 {
00091         const poldiff_role_allow_t *ra = role_allow;
00092         size_t len = 0, i;
00093         char *s = NULL, *role;
00094         if (diff == NULL || role_allow == NULL) {
00095                 ERR(diff, "%s", strerror(EINVAL));
00096                 errno = EINVAL;
00097                 return NULL;
00098         }
00099         switch (ra->form) {
00100         case POLDIFF_FORM_ADDED:
00101         {
00102                 if (apol_str_appendf(&s, &len, "+ allow %s { ", ra->source_role) < 0) {
00103                         s = NULL;
00104                         break;
00105                 }
00106                 for (i = 0; i < apol_vector_get_size(ra->added_roles); i++) {
00107                         role = apol_vector_get_element(ra->added_roles, i);
00108                         if (apol_str_appendf(&s, &len, "%s ", role) < 0) {
00109                                 goto err;
00110                         }
00111                 }
00112                 if (apol_str_append(&s, &len, "};") < 0) {
00113                         break;
00114                 }
00115                 return s;
00116         }
00117         case POLDIFF_FORM_REMOVED:
00118         {
00119                 if (apol_str_appendf(&s, &len, "- allow %s { ", ra->source_role) < 0) {
00120                         break;
00121                 }
00122                 for (i = 0; i < apol_vector_get_size(ra->removed_roles); i++) {
00123                         role = apol_vector_get_element(ra->removed_roles, i);
00124                         if (apol_str_appendf(&s, &len, "%s ", role) < 0) {
00125                                 goto err;
00126                         }
00127                 }
00128                 if (apol_str_append(&s, &len, "};") < 0) {
00129                         break;
00130                 }
00131                 return s;
00132         }
00133         case POLDIFF_FORM_MODIFIED:
00134         {
00135                 if (apol_str_appendf(&s, &len, "* allow %s { ", ra->source_role) < 0) {
00136                         s = NULL;
00137                         break;
00138                 }
00139                 for (i = 0; i < apol_vector_get_size(ra->orig_roles); i++) {
00140                         role = apol_vector_get_element(ra->orig_roles, i);
00141                         if (apol_str_appendf(&s, &len, "%s ", role) < 0) {
00142                                 goto err;
00143                         }
00144                 }
00145                 for (i = 0; i < apol_vector_get_size(ra->added_roles); i++) {
00146                         role = apol_vector_get_element(ra->added_roles, i);
00147                         if (apol_str_appendf(&s, &len, "+%s ", role) < 0) {
00148                                 goto err;
00149                         }
00150                 }
00151                 for (i = 0; i < apol_vector_get_size(ra->removed_roles); i++) {
00152                         role = apol_vector_get_element(ra->removed_roles, i);
00153                         if (apol_str_appendf(&s, &len, "-%s ", role) < 0) {
00154                                 goto err;
00155                         }
00156                 }
00157                 if (apol_str_append(&s, &len, "};") < 0) {
00158                         break;
00159                 }
00160                 return s;
00161         }
00162         default:
00163         {
00164                 ERR(diff, "%s", strerror(ENOTSUP));
00165                 errno = ENOTSUP;
00166                 return NULL;
00167         }
00168         }
00169         /* if this is reached then an error occurred */
00170       err:
00171         free(s);
00172         ERR(diff, "%s", strerror(ENOMEM));
00173         errno = ENOMEM;
00174         return NULL;
00175 }
00176 
00177 const apol_vector_t *poldiff_get_role_allow_vector(const poldiff_t * diff)
00178 {
00179         if (diff == NULL) {
00180                 ERR(diff, "%s", strerror(EINVAL));
00181                 errno = EINVAL;
00182                 return NULL;
00183         }
00184         return diff->role_allow_diffs->diffs;
00185 }
00186 
00187 const char *poldiff_role_allow_get_name(const poldiff_role_allow_t * role_allow)
00188 {
00189         if (role_allow == NULL) {
00190                 errno = EINVAL;
00191                 return NULL;
00192         }
00193         return role_allow->source_role;
00194 }
00195 
00196 poldiff_form_e poldiff_role_allow_get_form(const void *role_allow)
00197 {
00198         if (role_allow == NULL) {
00199                 errno = EINVAL;
00200                 return POLDIFF_FORM_NONE;
00201         }
00202         return ((const poldiff_role_allow_t *)role_allow)->form;
00203 }
00204 
00205 const apol_vector_t *poldiff_role_allow_get_unmodified_roles(const poldiff_role_allow_t * role_allow)
00206 {
00207         if (role_allow == NULL) {
00208                 errno = EINVAL;
00209                 return NULL;
00210         }
00211         return role_allow->orig_roles;
00212 }
00213 
00214 const apol_vector_t *poldiff_role_allow_get_added_roles(const poldiff_role_allow_t * role_allow)
00215 {
00216         if (role_allow == NULL) {
00217                 errno = EINVAL;
00218                 return NULL;
00219         }
00220         return role_allow->added_roles;
00221 }
00222 
00223 const apol_vector_t *poldiff_role_allow_get_removed_roles(const poldiff_role_allow_t * role_allow)
00224 {
00225         if (role_allow == NULL) {
00226                 errno = EINVAL;
00227                 return NULL;
00228         }
00229         return role_allow->removed_roles;
00230 }
00231 
00232 static void role_allow_free(void *elem)
00233 {
00234         if (elem != NULL) {
00235                 poldiff_role_allow_t *r = (poldiff_role_allow_t *) elem;
00236                 apol_vector_destroy(&r->orig_roles);
00237                 apol_vector_destroy(&r->added_roles);
00238                 apol_vector_destroy(&r->removed_roles);
00239                 free(r);
00240         }
00241 }
00242 
00243 poldiff_role_allow_summary_t *role_allow_create(void)
00244 {
00245         poldiff_role_allow_summary_t *ras = calloc(1, sizeof(*ras));
00246         if (ras == NULL) {
00247                 return NULL;
00248         }
00249         if ((ras->diffs = apol_vector_create(role_allow_free)) == NULL) {
00250                 role_allow_destroy(&ras);
00251                 return NULL;
00252         }
00253         return ras;
00254 }
00255 
00256 void role_allow_destroy(poldiff_role_allow_summary_t ** ras)
00257 {
00258         if (ras != NULL && *ras != NULL) {
00259                 apol_vector_destroy(&(*ras)->diffs);
00260                 free(*ras);
00261                 *ras = NULL;
00262         }
00263 }
00264 
00265 typedef struct pseudo_role_allow
00266 {
00267         const char *source_role;
00268         apol_vector_t *target_roles;
00269 } pseudo_role_allow_t;
00270 
00271 static void role_allow_free_item(void *item)
00272 {
00273         pseudo_role_allow_t *pra = item;
00274 
00275         if (!item)
00276                 return;
00277 
00278         /* no need to free source name or target role names */
00279         apol_vector_destroy(&pra->target_roles);
00280         free(item);
00281 }
00282 
00283 static int role_allow_source_comp(const void *x, const void *y, void *arg __attribute__ ((unused)))
00284 {
00285         const pseudo_role_allow_t *p1 = x;
00286         const pseudo_role_allow_t *p2 = y;
00287 
00288         return strcmp(p1->source_role, p2->source_role);
00289 }
00290 
00291 apol_vector_t *role_allow_get_items(poldiff_t * diff, const apol_policy_t * policy)
00292 {
00293         qpol_iterator_t *iter = NULL;
00294         apol_vector_t *tmp = NULL, *v = NULL;
00295         int error = 0, retv;
00296         size_t i;
00297         apol_bst_t *bst = NULL;
00298         pseudo_role_allow_t *pra = NULL;
00299         const qpol_role_t *sr = NULL, *tr = NULL;
00300         const char *sr_name = NULL, *tr_name = NULL;
00301         const qpol_role_allow_t *qra = NULL;
00302         qpol_policy_t *q = apol_policy_get_qpol(policy);
00303 
00304         if (qpol_policy_get_role_allow_iter(q, &iter) < 0) {
00305                 return NULL;
00306         }
00307 
00308         tmp = apol_vector_create_from_iter(iter, NULL);
00309         if (tmp == NULL) {
00310                 error = errno;
00311                 ERR(diff, "%s", strerror(error));
00312                 qpol_iterator_destroy(&iter);
00313                 errno = error;
00314                 return NULL;
00315         }
00316         qpol_iterator_destroy(&iter);
00317 
00318         bst = apol_bst_create(role_allow_source_comp, role_allow_free_item);
00319 
00320         for (i = 0; i < apol_vector_get_size(tmp); i++) {
00321                 qra = apol_vector_get_element(tmp, i);
00322                 if (!(pra = calloc(1, sizeof(*pra))) || (!(pra->target_roles = apol_vector_create_with_capacity(1, NULL)))) {
00323                         error = errno;
00324                         ERR(diff, "%s", strerror(error));
00325                         goto err;
00326                 }
00327                 if (qpol_role_allow_get_source_role(q, qra, &sr) || qpol_role_get_name(q, sr, &sr_name)) {
00328                         error = errno;
00329                         ERR(diff, "%s", strerror(error));
00330                         goto err;
00331                 }
00332                 sr = NULL;
00333                 if (qpol_role_allow_get_target_role(q, qra, &tr) || qpol_role_get_name(q, tr, &tr_name)) {
00334                         error = errno;
00335                         ERR(diff, "%s", strerror(error));
00336                         goto err;
00337                 }
00338                 tr = NULL;
00339                 pra->source_role = sr_name;
00340                 retv = apol_bst_insert_and_get(bst, (void **)&pra, NULL);
00341                 if (retv < 0) {
00342                         error = errno;
00343                         ERR(diff, "%s", strerror(error));
00344                         goto err;
00345                 }
00346                 apol_vector_append_unique(pra->target_roles, (void *)tr_name, apol_str_strcmp, NULL);
00347                 pra = NULL;
00348         }
00349         apol_vector_destroy(&tmp);
00350 
00351         v = apol_bst_get_vector(bst, 1);
00352         if (!v) {
00353                 error = errno;
00354                 ERR(diff, "%s", strerror(error));
00355                 goto err;
00356         }
00357         apol_bst_destroy(&bst);
00358 
00359         return v;
00360 
00361       err:
00362         role_allow_free_item(pra);
00363         apol_bst_destroy(&bst);
00364         errno = error;
00365         return NULL;
00366 }
00367 
00368 int role_allow_comp(const void *x, const void *y, const poldiff_t * diff __attribute__ ((unused)))
00369 {
00370         const pseudo_role_allow_t *p1 = x;
00371         const pseudo_role_allow_t *p2 = y;
00372 
00373         return strcmp(p1->source_role, p2->source_role);
00374 }
00375 
00376 int role_allow_reset(poldiff_t * diff)
00377 {
00378         int error = 0;
00379 
00380         if (diff == NULL) {
00381                 ERR(diff, "%s", strerror(EINVAL));
00382                 errno = EINVAL;
00383                 return -1;
00384         }
00385 
00386         role_allow_destroy(&diff->role_allow_diffs);
00387         diff->role_allow_diffs = role_allow_create();
00388         if (diff->role_allow_diffs == NULL) {
00389                 error = errno;
00390                 ERR(diff, "%s", strerror(error));
00391                 errno = error;
00392                 return -1;
00393         }
00394 
00395         return 0;
00396 }
00397 
00398 /**
00399  *  Allocate and return a new role allow rule difference object.
00400  *
00401  *  @param diff Policy diff error handler.
00402  *  @param form Form of the difference.
00403  *  @param source_role Name of the source role in the role allow rule.
00404  *
00405  *  @return A newly allocated and initialized diff, or NULL upon error.
00406  *  The caller is responsible for calling role_allow_free() upon the returned
00407  *  value.
00408  */
00409 static poldiff_role_allow_t *make_ra_diff(const poldiff_t * diff, poldiff_form_e form, const char *source_role)
00410 {
00411         poldiff_role_allow_t *ra = NULL;
00412         int error = 0;
00413         if ((ra = calloc(1, sizeof(*ra))) == NULL ||
00414             (ra->source_role = source_role) == NULL ||
00415             (ra->added_roles = apol_vector_create_with_capacity(1, NULL)) == NULL ||
00416             (ra->orig_roles = apol_vector_create_with_capacity(1, NULL)) == NULL ||
00417             (ra->removed_roles = apol_vector_create_with_capacity(1, NULL)) == NULL) {
00418                 error = errno;
00419                 role_allow_free(ra);
00420                 ERR(diff, "%s", strerror(error));
00421                 errno = error;
00422                 return NULL;
00423         }
00424         ra->form = form;
00425         return ra;
00426 }
00427 
00428 int role_allow_new_diff(poldiff_t * diff, poldiff_form_e form, const void *item)
00429 {
00430         pseudo_role_allow_t *ra = (pseudo_role_allow_t *) item;
00431         poldiff_role_allow_t *pra;
00432         int error;
00433 
00434         pra = make_ra_diff(diff, form, ra->source_role);
00435         if (pra == NULL) {
00436                 return -1;
00437         }
00438         int rt;
00439         if (form == POLDIFF_FORM_ADDED) {
00440                 rt = apol_vector_cat(pra->added_roles, ra->target_roles);
00441         } else {
00442                 rt = apol_vector_cat(pra->removed_roles, ra->target_roles);
00443         }
00444         if (rt < 0) {
00445                 error = errno;
00446                 ERR(diff, "%s", strerror(error));
00447                 role_allow_free(pra);
00448                 errno = error;
00449                 return -1;
00450         }
00451         if (apol_vector_append(diff->role_allow_diffs->diffs, pra) < 0) {
00452                 error = errno;
00453                 ERR(diff, "%s", strerror(error));
00454                 role_allow_free(pra);
00455                 errno = error;
00456                 return -1;
00457         }
00458         if (form == POLDIFF_FORM_ADDED) {
00459                 diff->role_allow_diffs->num_added++;
00460         } else {
00461                 diff->role_allow_diffs->num_removed++;
00462         }
00463         return 0;
00464 }
00465 
00466 int role_allow_deep_diff(poldiff_t * diff, const void *x, const void *y)
00467 {
00468         const pseudo_role_allow_t *p1 = x;
00469         const pseudo_role_allow_t *p2 = y;
00470         apol_vector_t *v1 = NULL, *v2 = NULL;
00471         char *role1, *role2;
00472         poldiff_role_allow_t *pra = NULL;
00473         size_t i, j;
00474         int retval = -1, error = 0, compval;
00475 
00476         v1 = p1->target_roles;
00477         v2 = p2->target_roles;
00478 
00479         apol_vector_sort(v1, apol_str_strcmp, NULL);
00480         apol_vector_sort(v2, apol_str_strcmp, NULL);
00481         for (i = j = 0; i < apol_vector_get_size(v1);) {
00482                 if (j >= apol_vector_get_size(v2))
00483                         break;
00484                 role1 = (char *)apol_vector_get_element(v1, i);
00485                 role2 = (char *)apol_vector_get_element(v2, j);
00486                 compval = strcmp(role1, role2);
00487                 if (pra == NULL) {
00488                         if ((pra = make_ra_diff(diff, POLDIFF_FORM_MODIFIED, p1->source_role)) == NULL) {
00489                                 error = errno;
00490                                 goto cleanup;
00491                         }
00492                 }
00493                 if (compval < 0) {
00494                         if (apol_vector_append(pra->removed_roles, role1) < 0) {
00495                                 error = errno;
00496                                 ERR(diff, "%s", strerror(error));
00497                                 goto cleanup;
00498                         }
00499                         i++;
00500                 } else if (compval > 0) {
00501                         if (apol_vector_append(pra->added_roles, role2) < 0) {
00502                                 error = errno;
00503                                 ERR(diff, "%s", strerror(error));
00504                                 goto cleanup;
00505                         }
00506                         j++;
00507                 } else {
00508                         if (apol_vector_append(pra->orig_roles, role1) < 0) {
00509                                 error = errno;
00510                                 ERR(diff, "%s", strerror(error));
00511                                 goto cleanup;
00512                         }
00513                         i++;
00514                         j++;
00515                 }
00516         }
00517         for (; i < apol_vector_get_size(v1); i++) {
00518                 role1 = (char *)apol_vector_get_element(v1, i);
00519                 if (pra == NULL) {
00520                         if ((pra = make_ra_diff(diff, POLDIFF_FORM_MODIFIED, p1->source_role)) == NULL) {
00521                                 error = errno;
00522                                 goto cleanup;
00523                         }
00524                 }
00525                 if (apol_vector_append(pra->removed_roles, role1) < 0) {
00526                         error = errno;
00527                         free(role1);
00528                         ERR(diff, "%s", strerror(error));
00529                         goto cleanup;
00530                 }
00531         }
00532         for (; j < apol_vector_get_size(v2); j++) {
00533                 role2 = (char *)apol_vector_get_element(v2, j);
00534                 if (pra == NULL) {
00535                         if ((pra = make_ra_diff(diff, POLDIFF_FORM_MODIFIED, p1->source_role)) == NULL) {
00536                                 error = errno;
00537                                 goto cleanup;
00538                         }
00539                 }
00540                 if (apol_vector_append(pra->added_roles, role2) < 0) {
00541                         error = errno;
00542                         free(role2);
00543                         ERR(diff, "%s", strerror(error));
00544                         goto cleanup;
00545                 }
00546         }
00547         if (apol_vector_get_size(pra->added_roles) || apol_vector_get_size(pra->removed_roles)) {
00548                 apol_vector_sort(pra->removed_roles, apol_str_strcmp, NULL);
00549                 apol_vector_sort(pra->added_roles, apol_str_strcmp, NULL);
00550                 apol_vector_sort(pra->orig_roles, apol_str_strcmp, NULL);
00551                 if (apol_vector_append(diff->role_allow_diffs->diffs, pra) < 0) {
00552                         error = errno;
00553                         ERR(diff, "%s", strerror(error));
00554                         goto cleanup;
00555                 }
00556                 diff->role_allow_diffs->num_modified++;
00557         } else {
00558                 role_allow_free(pra);
00559                 pra = NULL;
00560         }
00561         retval = 0;
00562       cleanup:
00563         if (retval != 0) {
00564                 role_allow_free(pra);
00565         }
00566         errno = error;
00567         return retval;
00568 }
00569 
00570 /**************** role_transition functions *******************/
00571 
00572 void poldiff_role_trans_get_stats(const poldiff_t * diff, size_t stats[5])
00573 {
00574         if (diff == NULL || stats == NULL) {
00575                 ERR(diff, "%s", strerror(EINVAL));
00576                 errno = EINVAL;
00577                 return;
00578         }
00579         stats[0] = diff->role_trans_diffs->num_added;
00580         stats[1] = diff->role_trans_diffs->num_removed;
00581         stats[2] = diff->role_trans_diffs->num_modified;
00582         stats[3] = diff->role_trans_diffs->num_added_type;
00583         stats[4] = diff->role_trans_diffs->num_removed_type;
00584 }
00585 
00586 extern char *poldiff_role_trans_to_string(const poldiff_t * diff, const void *role_trans)
00587 {
00588         const poldiff_role_trans_t *rt = role_trans;
00589         char *s = NULL;
00590 
00591         if (diff == NULL || role_trans == NULL) {
00592                 ERR(diff, "%s", strerror(EINVAL));
00593                 errno = EINVAL;
00594                 return NULL;
00595         }
00596         switch (rt->form) {
00597         case POLDIFF_FORM_ADDED:
00598         case POLDIFF_FORM_ADD_TYPE:
00599         {
00600                 if (asprintf(&s, "+ role_transition %s %s %s;", rt->source_role, rt->target_type, rt->mod_default) < 0)
00601                         break;
00602                 return s;
00603         }
00604         case POLDIFF_FORM_REMOVED:
00605         case POLDIFF_FORM_REMOVE_TYPE:
00606         {
00607                 if (asprintf(&s, "- role_transition %s %s %s;", rt->source_role, rt->target_type, rt->orig_default) < 0)
00608                         break;
00609                 return s;
00610         }
00611         case POLDIFF_FORM_MODIFIED:
00612         {
00613                 if (asprintf
00614                     (&s, "* role_transition %s %s { +%s -%s };", rt->source_role, rt->target_type, rt->mod_default,
00615                      rt->orig_default) < 0)
00616                         break;
00617                 return s;
00618         }
00619         case POLDIFF_FORM_NONE:
00620         default:
00621         {
00622                 ERR(diff, "%s", strerror(ENOTSUP));
00623                 errno = ENOTSUP;
00624                 return NULL;
00625         }
00626         }
00627         /* if this is reached then an error occurred */
00628         free(s);
00629         ERR(diff, "%s", strerror(ENOMEM));
00630         errno = ENOMEM;
00631         return NULL;
00632 }
00633 
00634 const apol_vector_t *poldiff_get_role_trans_vector(const poldiff_t * diff)
00635 {
00636         if (diff == NULL) {
00637                 ERR(diff, "%s", strerror(EINVAL));
00638                 errno = EINVAL;
00639                 return NULL;
00640         }
00641         return diff->role_trans_diffs->diffs;
00642 }
00643 
00644 extern const char *poldiff_role_trans_get_source_role(const poldiff_role_trans_t * role_trans)
00645 {
00646         if (role_trans == NULL) {
00647                 errno = EINVAL;
00648                 return NULL;
00649         }
00650         return role_trans->source_role;
00651 }
00652 
00653 extern const char *poldiff_role_trans_get_target_type(const poldiff_role_trans_t * role_trans)
00654 {
00655         if (role_trans == NULL) {
00656                 errno = EINVAL;
00657                 return NULL;
00658         }
00659         return role_trans->target_type;
00660 }
00661 
00662 extern poldiff_form_e poldiff_role_trans_get_form(const void *role_trans)
00663 {
00664         if (role_trans == NULL) {
00665                 errno = EINVAL;
00666                 return POLDIFF_FORM_NONE;
00667         }
00668         return ((const poldiff_role_trans_t *)role_trans)->form;
00669 }
00670 
00671 extern const char *poldiff_role_trans_get_original_default(const poldiff_role_trans_t * role_trans)
00672 {
00673         if (role_trans == NULL) {
00674                 errno = EINVAL;
00675                 return NULL;
00676         }
00677         return role_trans->orig_default;
00678 }
00679 
00680 extern const char *poldiff_role_trans_get_modified_default(const poldiff_role_trans_t * role_trans)
00681 {
00682         if (role_trans == NULL) {
00683                 errno = EINVAL;
00684                 return NULL;
00685         }
00686         return role_trans->mod_default;
00687 }
00688 
00689 static void role_trans_free(void *elem)
00690 {
00691         if (elem != NULL) {
00692                 poldiff_role_trans_t *rt = elem;
00693                 free(rt->target_type);
00694                 free(rt);
00695         }
00696 }
00697 
00698 poldiff_role_trans_summary_t *role_trans_create(void)
00699 {
00700         poldiff_role_trans_summary_t *rts = calloc(1, sizeof(*rts));
00701         if (rts == NULL) {
00702                 return NULL;
00703         }
00704         if ((rts->diffs = apol_vector_create(role_trans_free)) == NULL) {
00705                 role_trans_destroy(&rts);
00706                 return NULL;
00707         }
00708         return rts;
00709 }
00710 
00711 void role_trans_destroy(poldiff_role_trans_summary_t ** rts)
00712 {
00713         if (rts != NULL && *rts != NULL) {
00714                 apol_vector_destroy(&(*rts)->diffs);
00715                 free(*rts);
00716                 *rts = NULL;
00717         }
00718 }
00719 
00720 int role_trans_reset(poldiff_t * diff)
00721 {
00722         int error = 0;
00723 
00724         if (diff == NULL) {
00725                 ERR(diff, "%s", strerror(EINVAL));
00726                 errno = EINVAL;
00727                 return -1;
00728         }
00729 
00730         role_trans_destroy(&diff->role_trans_diffs);
00731         diff->role_trans_diffs = role_trans_create();
00732         if (diff->role_trans_diffs == NULL) {
00733                 error = errno;
00734                 ERR(diff, "%s", strerror(error));
00735                 errno = error;
00736                 return -1;
00737         }
00738 
00739         return 0;
00740 }
00741 
00742 typedef struct pseudo_role_trans
00743 {
00744         const char *source_role;
00745         uint32_t pseudo_target;
00746         const char *default_role;
00747 } pseudo_role_trans_t;
00748 
00749 /**
00750  *  Compare two pseudo role_transition rules from the same policy.
00751  *  Compares the source role name and then pseudo type value of the target.
00752  *
00753  *  @param x A pseudo_role_trans_t entry.
00754  *  @param y A pseudo_role_trans_t entry.
00755  *  @param arg The policy difference structure.
00756  *
00757  *  @return < 0, 0, or > 0 if the first rule is respectively less than,
00758  *  equal to, or greater than the second. If the return value would be 0
00759  *  but the default role is different a warning is issued.
00760  */
00761 static int pseudo_role_trans_comp(const void *x, const void *y, void *arg)
00762 {
00763         int retv = 0;
00764         const pseudo_role_trans_t *a = x;
00765         const pseudo_role_trans_t *b = y;
00766         poldiff_t *diff = arg;
00767 
00768         retv = strcmp(a->source_role, b->source_role);
00769         if (!retv)
00770                 retv = a->pseudo_target - b->pseudo_target;
00771         else
00772                 return retv;
00773         if (!retv && strcmp(a->default_role, b->default_role))
00774                 WARN(diff, "Multiple role_transition rules for %s %s with different default roles.", a->source_role,
00775                      type_map_get_name(diff, a->pseudo_target, POLDIFF_POLICY_ORIG));
00776         return retv;
00777 }
00778 
00779 static void role_trans_free_item(void *item)
00780 {
00781         /* no need to free members of a pseudo role_transition */
00782         free(item);
00783 }
00784 
00785 apol_vector_t *role_trans_get_items(poldiff_t * diff, const apol_policy_t * policy)
00786 {
00787         qpol_iterator_t *iter = NULL, *attr_types = NULL;
00788         apol_vector_t *v = NULL;
00789         const qpol_role_trans_t *qrt = NULL;
00790         pseudo_role_trans_t *tmp_prt = NULL;
00791         const char *tmp_name = NULL;
00792         const qpol_role_t *tmp_role = NULL;
00793         const qpol_type_t *tmp_type = NULL;
00794         qpol_policy_t *q = apol_policy_get_qpol(policy);
00795         int error = 0, which_pol;
00796         unsigned char isattr = 0;
00797 
00798         which_pol = (policy == diff->orig_pol ? POLDIFF_POLICY_ORIG : POLDIFF_POLICY_MOD);
00799         if (qpol_policy_get_role_trans_iter(q, &iter)) {
00800                 error = errno;
00801                 goto err;
00802         }
00803         v = apol_vector_create(role_trans_free_item);
00804         if (!v) {
00805                 error = errno;
00806                 ERR(diff, "%s", strerror(error));
00807                 goto err;
00808         }
00809         for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
00810                 isattr = 0;
00811                 if (qpol_iterator_get_item(iter, (void **)&qrt) < 0) {
00812                         error = errno;
00813                         ERR(diff, "%s", strerror(error));
00814                         goto err;
00815                 }
00816                 if (qpol_role_trans_get_target_type(q, qrt, &tmp_type) < 0) {
00817                         error = errno;
00818                         goto err;
00819                 }
00820                 qpol_type_get_isattr(q, tmp_type, &isattr);
00821                 if (isattr) {
00822                         qpol_type_get_type_iter(q, tmp_type, &attr_types);
00823                         for (; !qpol_iterator_end(attr_types); qpol_iterator_next(attr_types)) {
00824                                 qpol_iterator_get_item(attr_types, (void **)&tmp_type);
00825                                 if (!(tmp_prt = calloc(1, sizeof(*tmp_prt)))) {
00826                                         error = errno;
00827                                         ERR(diff, "%s", strerror(error));
00828                                         goto err;
00829                                 }
00830                                 tmp_prt->pseudo_target = type_map_lookup(diff, tmp_type, which_pol);
00831                                 qpol_role_trans_get_source_role(q, qrt, &tmp_role);
00832                                 qpol_role_get_name(q, tmp_role, &tmp_name);
00833                                 tmp_prt->source_role = tmp_name;
00834                                 qpol_role_trans_get_default_role(q, qrt, &tmp_role);
00835                                 qpol_role_get_name(q, tmp_role, &tmp_name);
00836                                 tmp_prt->default_role = tmp_name;
00837                                 if (apol_vector_append(v, tmp_prt)) {
00838                                         error = errno;
00839                                         ERR(diff, "%s", strerror(error));
00840                                         goto err;
00841                                 }
00842                                 tmp_prt = NULL;
00843                         }
00844                         qpol_iterator_destroy(&attr_types);
00845                 } else {
00846                         if (!(tmp_prt = calloc(1, sizeof(*tmp_prt)))) {
00847                                 error = errno;
00848                                 ERR(diff, "%s", strerror(error));
00849                                 goto err;
00850                         }
00851                         tmp_prt->pseudo_target = type_map_lookup(diff, tmp_type, which_pol);
00852                         qpol_role_trans_get_source_role(q, qrt, &tmp_role);
00853                         qpol_role_get_name(q, tmp_role, &tmp_name);
00854                         tmp_prt->source_role = tmp_name;
00855                         qpol_role_trans_get_default_role(q, qrt, &tmp_role);
00856                         qpol_role_get_name(q, tmp_role, &tmp_name);
00857                         tmp_prt->default_role = tmp_name;
00858                         if (apol_vector_append(v, tmp_prt)) {
00859                                 error = errno;
00860                                 ERR(diff, "%s", strerror(error));
00861                                 goto err;
00862                         }
00863                         tmp_prt = NULL;
00864                 }
00865         }
00866         qpol_iterator_destroy(&iter);
00867         apol_vector_sort_uniquify(v, pseudo_role_trans_comp, diff);
00868 
00869         return v;
00870 
00871       err:
00872         qpol_iterator_destroy(&iter);
00873         qpol_iterator_destroy(&attr_types);
00874         apol_vector_destroy(&v);
00875         free(tmp_prt);
00876         errno = error;
00877         return NULL;
00878 }
00879 
00880 int role_trans_comp(const void *x, const void *y, const poldiff_t * diff __attribute__ ((unused)))
00881 {
00882         int retv = 0;
00883         const pseudo_role_trans_t *a = x;
00884         const pseudo_role_trans_t *b = y;
00885 
00886         retv = strcmp(a->source_role, b->source_role);
00887         if (!retv)
00888                 return a->pseudo_target - b->pseudo_target;
00889         else
00890                 return retv;
00891 }
00892 
00893 /**
00894  *  Allocate and return a new role_transition rule difference object.
00895  *
00896  *  @param diff Policy difference error handler.
00897  *  @param form Form of the difference.
00898  *  @param src Name of the source role.
00899  *  @param tgt Name of the target type.
00900  *
00901  *  @return A newly allocated and initialised diff or NULL upon error.
00902  *  The caller is responsible for calling free() upon the returned
00903  *  value.
00904  */
00905 static poldiff_role_trans_t *make_rt_diff(const poldiff_t * diff, poldiff_form_e form, const char *src, const char *tgt)
00906 {
00907         poldiff_role_trans_t *rt = NULL;
00908         int error = 0;
00909         if ((rt = calloc(1, sizeof(*rt))) == NULL || (rt->source_role = src) == NULL || (rt->target_type = strdup(tgt)) == NULL) {
00910                 error = errno;
00911                 role_trans_free(rt);
00912                 ERR(diff, "%s", strerror(error));
00913                 errno = error;
00914                 return NULL;
00915         }
00916         rt->form = form;
00917         return rt;
00918 }
00919 
00920 int role_trans_new_diff(poldiff_t * diff, poldiff_form_e form, const void *item)
00921 {
00922         const pseudo_role_trans_t *rt = item;
00923         poldiff_role_trans_t *prt = NULL;
00924         const char *tgt_name = NULL;
00925         int error = 0;
00926 
00927         /* get tgt_name from type_map */
00928         switch (form) {
00929         case POLDIFF_FORM_ADDED:
00930         {
00931                 tgt_name = type_map_get_name(diff, rt->pseudo_target, POLDIFF_POLICY_MOD);
00932                 if (type_map_get_name(diff, rt->pseudo_target, POLDIFF_POLICY_ORIG) == NULL) {
00933                         form = POLDIFF_FORM_ADD_TYPE;
00934                 }
00935                 break;
00936         }
00937         case POLDIFF_FORM_REMOVED:
00938         {
00939                 tgt_name = type_map_get_name(diff, rt->pseudo_target, POLDIFF_POLICY_ORIG);
00940                 if (type_map_get_name(diff, rt->pseudo_target, POLDIFF_POLICY_MOD) == NULL) {
00941                         form = POLDIFF_FORM_REMOVE_TYPE;
00942                 }
00943                 break;
00944         }
00945         case POLDIFF_FORM_MODIFIED:   /* not supported here */
00946         case POLDIFF_FORM_NONE:
00947         default:
00948         {
00949                 assert(0);
00950                 return -1;
00951         }
00952         }
00953         assert(tgt_name != NULL);
00954 
00955         /* create a new diff */
00956         prt = make_rt_diff(diff, form, rt->source_role, tgt_name);
00957         if (!prt)
00958                 return -1;
00959 
00960         /* set the appropriate default */
00961         switch (form) {
00962         case POLDIFF_FORM_ADDED:
00963         case POLDIFF_FORM_ADD_TYPE:
00964         {
00965                 prt->mod_default = rt->default_role;
00966                 break;
00967         }
00968         case POLDIFF_FORM_REMOVED:
00969         case POLDIFF_FORM_REMOVE_TYPE:
00970         {
00971                 prt->orig_default = rt->default_role;
00972                 break;
00973         }
00974         default:
00975         {
00976                 /* not reachable */
00977                 assert(0);
00978         }
00979         }
00980         if (apol_vector_append(diff->role_trans_diffs->diffs, prt)) {
00981                 error = errno;
00982                 ERR(diff, "%s", strerror(error));
00983                 role_trans_free(prt);
00984                 errno = error;
00985                 return -1;
00986         };
00987 
00988         /* increment appropriate counter */
00989         switch (form) {
00990         case POLDIFF_FORM_ADDED:
00991         {
00992                 diff->role_trans_diffs->num_added++;
00993                 break;
00994         }
00995         case POLDIFF_FORM_ADD_TYPE:
00996         {
00997                 diff->role_trans_diffs->num_added_type++;
00998                 break;
00999         }
01000         case POLDIFF_FORM_REMOVED:
01001         {
01002                 diff->role_trans_diffs->num_removed++;
01003                 break;
01004         }
01005         case POLDIFF_FORM_REMOVE_TYPE:
01006         {
01007                 diff->role_trans_diffs->num_removed_type++;
01008                 break;
01009         }
01010         default:
01011         {
01012                 /* not reachable */
01013                 assert(0);
01014         }
01015         }
01016 
01017         return 0;
01018 }
01019 
01020 int role_trans_deep_diff(poldiff_t * diff, const void *x, const void *y)
01021 {
01022         const pseudo_role_trans_t *prt1 = x;
01023         const pseudo_role_trans_t *prt2 = y;
01024         const char *default1 = NULL, *default2 = NULL;
01025         poldiff_role_trans_t *rt = NULL;
01026         const char *tgt = NULL;
01027         int error = 0;
01028 
01029         default1 = prt1->default_role;
01030         default2 = prt2->default_role;
01031 
01032         if (!strcmp(default1, default2))
01033                 return 0;              /* no difference */
01034 
01035         tgt = type_map_get_name(diff, prt1->pseudo_target, POLDIFF_POLICY_ORIG);
01036         assert(tgt != NULL);
01037         rt = make_rt_diff(diff, POLDIFF_FORM_MODIFIED, prt1->source_role, tgt);
01038         if (!rt)
01039                 return -1;             /* errors already reported */
01040         rt->orig_default = default1;
01041         rt->mod_default = default2;
01042         if (apol_vector_append(diff->role_trans_diffs->diffs, rt)) {
01043                 error = errno;
01044                 ERR(diff, "%s", strerror(error));
01045                 role_trans_free(rt);
01046                 errno = error;
01047                 return -1;
01048         };
01049         diff->role_trans_diffs->num_modified++;
01050 
01051         return 0;
01052 }