00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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
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
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
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
00296
00297
00298
00299
00300
00301
00302
00303
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
00356
00357
00358
00359
00360
00361
00362
00363
00364
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 }