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 <apol/mls_range.h>
00028
00029 #include <assert.h>
00030 #include <errno.h>
00031 #include <stdlib.h>
00032 #include <string.h>
00033
00034 #include "policy-query-internal.h"
00035
00036 #include <qpol/iterator.h>
00037 #include <apol/vector.h>
00038
00039 struct apol_mls_range
00040 {
00041 apol_mls_level_t *low, *high;
00042 };
00043
00044 apol_mls_range_t *apol_mls_range_create(void)
00045 {
00046 return calloc(1, sizeof(apol_mls_range_t));
00047 }
00048
00049 apol_mls_range_t *apol_mls_range_create_from_mls_range(const apol_mls_range_t * range)
00050 {
00051 apol_mls_range_t *r;
00052 if ((r = apol_mls_range_create()) == NULL) {
00053 return NULL;
00054 }
00055 if (range != NULL &&
00056 ((r->low = apol_mls_level_create_from_mls_level(range->low)) == NULL ||
00057 (r->high = apol_mls_level_create_from_mls_level(range->high)) == NULL)) {
00058 apol_mls_range_destroy(&r);
00059 return NULL;
00060 }
00061 return r;
00062 }
00063
00064 apol_mls_range_t *apol_mls_range_create_from_string(const apol_policy_t * p, const char *mls_range_string)
00065 {
00066 if (p == NULL || mls_range_string == NULL) {
00067 ERR(p, "%s", strerror(EINVAL));
00068 errno = EINVAL;
00069 return NULL;
00070 }
00071
00072 apol_mls_range_t *r = apol_mls_range_create();
00073 if (r == NULL) {
00074 ERR(p, "%s", strerror(errno));
00075 return NULL;
00076 }
00077 char *dash;
00078 if ((dash = strchr(mls_range_string, '-')) == NULL) {
00079
00080 apol_mls_level_t *l = apol_mls_level_create_from_string(p, mls_range_string);
00081 if (l == NULL) {
00082 ERR(p, "%s", strerror(errno));
00083 apol_mls_range_destroy(&r);
00084 return NULL;
00085 }
00086 r->low = l;
00087 } else {
00088
00089 if (dash == mls_range_string) {
00090 apol_mls_range_destroy(&r);
00091 ERR(p, "%s", strerror(EINVAL));
00092 errno = EINVAL;
00093 return NULL;
00094 }
00095 char *s = strndup(mls_range_string, dash - mls_range_string);
00096 if (s == NULL) {
00097 ERR(p, "%s", strerror(errno));
00098 apol_mls_range_destroy(&r);
00099 return NULL;
00100 }
00101 apol_mls_level_t *l = apol_mls_level_create_from_string(p, s);
00102 if (l == NULL) {
00103 ERR(p, "%s", strerror(errno));
00104 apol_mls_range_destroy(&r);
00105 free(s);
00106 return NULL;
00107 }
00108 r->low = l;
00109 free(s);
00110 l = NULL;
00111
00112 if ((l = apol_mls_level_create_from_string(p, dash + 1)) == NULL) {
00113 ERR(p, "%s", strerror(errno));
00114 apol_mls_range_destroy(&r);
00115 return NULL;
00116 }
00117 r->high = l;
00118 }
00119
00120 if (apol_mls_range_validate(p, r) <= 0) {
00121 ERR(p, "%s", strerror(EINVAL));
00122 errno = EINVAL;
00123 apol_mls_range_destroy(&r);
00124 return NULL;
00125 }
00126 return r;
00127 }
00128
00129 apol_mls_range_t *apol_mls_range_create_from_literal(const char *mls_range_string)
00130 {
00131 if (mls_range_string == NULL) {
00132 errno = EINVAL;
00133 return NULL;
00134 }
00135
00136 apol_mls_range_t *r = apol_mls_range_create();
00137 if (r == NULL) {
00138 return NULL;
00139 }
00140 char *dash;
00141 if ((dash = strchr(mls_range_string, '-')) == NULL) {
00142
00143 apol_mls_level_t *l = apol_mls_level_create_from_literal(mls_range_string);
00144 if (l == NULL) {
00145 apol_mls_range_destroy(&r);
00146 return NULL;
00147 }
00148 r->low = l;
00149 } else {
00150
00151 if (dash == mls_range_string) {
00152 apol_mls_range_destroy(&r);
00153 errno = EINVAL;
00154 return NULL;
00155 }
00156 char *s = strndup(mls_range_string, dash - mls_range_string);
00157 if (s == NULL) {
00158 apol_mls_range_destroy(&r);
00159 return NULL;
00160 }
00161 apol_mls_level_t *l = apol_mls_level_create_from_literal(s);
00162 if (l == NULL) {
00163 apol_mls_range_destroy(&r);
00164 free(s);
00165 return NULL;
00166 }
00167 r->low = l;
00168 free(s);
00169 l = NULL;
00170
00171 if ((l = apol_mls_level_create_from_literal(dash + 1)) == NULL) {
00172 apol_mls_range_destroy(&r);
00173 return NULL;
00174 }
00175 r->high = l;
00176 }
00177 return r;
00178 }
00179
00180 apol_mls_range_t *apol_mls_range_create_from_qpol_mls_range(const apol_policy_t * p, const qpol_mls_range_t * qpol_range)
00181 {
00182 apol_mls_range_t *apol_range = NULL;
00183 const qpol_mls_level_t *tmp = NULL;
00184 apol_mls_level_t *tmp_lvl = NULL;
00185 int error = 0;
00186
00187 if (!p || !qpol_range) {
00188 ERR(p, "%s", strerror(EINVAL));
00189 errno = EINVAL;
00190 return NULL;
00191 }
00192
00193 apol_range = calloc(1, sizeof(apol_mls_range_t));
00194 if (!apol_range) {
00195 ERR(p, "%s", strerror(ENOMEM));
00196 return NULL;
00197 }
00198
00199
00200 if (qpol_mls_range_get_low_level(p->p, qpol_range, &tmp) ||
00201 !(tmp_lvl = apol_mls_level_create_from_qpol_mls_level(p, tmp)) || apol_mls_range_set_low(p, apol_range, tmp_lvl)) {
00202 error = errno;
00203 apol_mls_level_destroy(&tmp_lvl);
00204 goto err;
00205 }
00206 tmp_lvl = NULL;
00207
00208
00209 if (qpol_mls_range_get_high_level(p->p, qpol_range, &tmp) ||
00210 !(tmp_lvl = apol_mls_level_create_from_qpol_mls_level(p, tmp)) || apol_mls_range_set_high(p, apol_range, tmp_lvl)) {
00211 error = errno;
00212 apol_mls_level_destroy(&tmp_lvl);
00213 goto err;
00214 }
00215
00216 return apol_range;
00217
00218 err:
00219 apol_mls_range_destroy(&apol_range);
00220 errno = error;
00221 return NULL;
00222 }
00223
00224 void apol_mls_range_destroy(apol_mls_range_t ** range)
00225 {
00226 if (!range || !(*range))
00227 return;
00228
00229 if ((*range)->low != (*range)->high) {
00230 apol_mls_level_destroy(&((*range)->high));
00231 }
00232 apol_mls_level_destroy(&((*range)->low));
00233 free(*range);
00234 *range = NULL;
00235 }
00236
00237 int apol_mls_range_set_low(const apol_policy_t * p, apol_mls_range_t * range, apol_mls_level_t * level)
00238 {
00239 if (!range) {
00240 ERR(p, "%s", strerror(EINVAL));
00241 errno = EINVAL;
00242 return -1;
00243 }
00244 if (range->low != level) {
00245 apol_mls_level_destroy(&(range->low));
00246 range->low = level;
00247 }
00248 return 0;
00249 }
00250
00251 int apol_mls_range_set_high(const apol_policy_t * p, apol_mls_range_t * range, apol_mls_level_t * level)
00252 {
00253 if (!range) {
00254 ERR(p, "%s", strerror(EINVAL));
00255 errno = EINVAL;
00256 return -1;
00257 }
00258
00259 if (range->high != level) {
00260 if (range->low != range->high) {
00261 apol_mls_level_destroy(&(range->high));
00262 }
00263 range->high = level;
00264 }
00265 return 0;
00266 }
00267
00268 const apol_mls_level_t *apol_mls_range_get_low(const apol_mls_range_t * range)
00269 {
00270 if (!range) {
00271 errno = EINVAL;
00272 return NULL;
00273 }
00274 return range->low;
00275 }
00276
00277 const apol_mls_level_t *apol_mls_range_get_high(const apol_mls_range_t * range)
00278 {
00279 if (!range) {
00280 errno = EINVAL;
00281 return NULL;
00282 }
00283 return range->high;
00284 }
00285
00286 int apol_mls_range_compare(const apol_policy_t * p, const apol_mls_range_t * target, const apol_mls_range_t * search,
00287 unsigned int range_compare_type)
00288 {
00289 int ans1 = -1, ans2 = -1;
00290 if (search == NULL) {
00291 return 1;
00292 }
00293 if (p == NULL || target == NULL || target->low == NULL || search->low == NULL) {
00294 ERR(p, "%s", strerror(EINVAL));
00295 errno = EINVAL;
00296 return -1;
00297 }
00298
00299 if ((range_compare_type & APOL_QUERY_SUB) || (range_compare_type & APOL_QUERY_INTERSECT)) {
00300 ans1 = apol_mls_range_contain_subrange(p, target, search);
00301 if (ans1 < 0) {
00302 return -1;
00303 }
00304 }
00305 if ((range_compare_type & APOL_QUERY_SUPER) || (range_compare_type & APOL_QUERY_INTERSECT)) {
00306 ans2 = apol_mls_range_contain_subrange(p, search, target);
00307 if (ans2 < 0) {
00308 return -1;
00309 }
00310 }
00311
00312 if ((range_compare_type & APOL_QUERY_EXACT) == APOL_QUERY_EXACT) {
00313 return (ans1 && ans2);
00314 } else if (range_compare_type & APOL_QUERY_SUB) {
00315 return ans1;
00316 } else if (range_compare_type & APOL_QUERY_SUPER) {
00317 return ans2;
00318 } else if (range_compare_type & APOL_QUERY_INTERSECT) {
00319 return (ans1 || ans2);
00320 }
00321 ERR(p, "%s", "Invalid range compare type argument.");
00322 errno = EINVAL;
00323 return -1;
00324 }
00325
00326 static int apol_mls_range_does_include_level(const apol_policy_t * p, const apol_mls_range_t * range,
00327 const apol_mls_level_t * level)
00328 {
00329 int high_cmp = -1, low_cmp = -1;
00330
00331 if (range->low != range->high) {
00332 low_cmp = apol_mls_level_compare(p, range->low, level);
00333 if (low_cmp < 0) {
00334 return -1;
00335 }
00336 }
00337 const apol_mls_level_t *high_level = (range->high != NULL ? range->high : range->low);
00338 high_cmp = apol_mls_level_compare(p, high_level, level);
00339 if (high_cmp < 0) {
00340 return -1;
00341 }
00342
00343 if (high_cmp == APOL_MLS_EQ || high_cmp == APOL_MLS_DOM) {
00344 if ((low_cmp == APOL_MLS_EQ || low_cmp == APOL_MLS_DOMBY) && range->low != high_level) {
00345 return 1;
00346 } else if (range->low == high_level) {
00347 return apol_mls_sens_compare(p, apol_mls_level_get_sens(range->low), apol_mls_level_get_sens(level));
00348 }
00349 }
00350
00351 return 0;
00352 }
00353
00354 int apol_mls_range_contain_subrange(const apol_policy_t * p, const apol_mls_range_t * range, const apol_mls_range_t * subrange)
00355 {
00356 if (p == NULL || apol_mls_range_validate(p, subrange) != 1) {
00357 ERR(p, "%s", strerror(EINVAL));
00358 return -1;
00359 }
00360
00361
00362
00363 if (apol_mls_range_does_include_level(p, range, subrange->low)) {
00364 if (subrange->high == NULL || apol_mls_range_does_include_level(p, range, subrange->high)) {
00365 return 1;
00366 }
00367 }
00368 return 0;
00369 }
00370
00371 int apol_mls_range_validate(const apol_policy_t * p, const apol_mls_range_t * range)
00372 {
00373 int retv;
00374
00375 if (p == NULL || range == NULL || range->low == NULL) {
00376 ERR(p, "%s", strerror(EINVAL));
00377 errno = EINVAL;
00378 return -1;
00379 }
00380
00381 if ((retv = apol_mls_level_validate(p, range->low)) != 1) {
00382 return retv;
00383 }
00384
00385 if (range->high == NULL) {
00386 return retv;
00387 }
00388 if (range->high != range->low && (retv = apol_mls_level_validate(p, range->high)) != 1) {
00389 return retv;
00390 }
00391
00392
00393
00394 retv = apol_mls_level_compare(p, range->low, range->high);
00395 if (retv < 0) {
00396 return -1;
00397 } else if (retv != APOL_MLS_EQ && retv != APOL_MLS_DOMBY) {
00398 return 0;
00399 }
00400
00401 return 1;
00402 }
00403
00404 static int mls_range_comp(const void *a, const void *b, void *data)
00405 {
00406 const apol_mls_level_t *l1 = a;
00407 const apol_mls_level_t *l2 = b;
00408 qpol_policy_t *q = (qpol_policy_t *) data;
00409 const qpol_level_t *l;
00410 uint32_t low_value, high_value;
00411 qpol_policy_get_level_by_name(q, apol_mls_level_get_sens(l1), &l);
00412 qpol_level_get_value(q, l, &low_value);
00413 qpol_policy_get_level_by_name(q, apol_mls_level_get_sens(l2), &l);
00414 qpol_level_get_value(q, l, &high_value);
00415 assert(low_value != 0 && high_value != 0);
00416 return low_value - high_value;
00417 }
00418
00419 static int mls_level_name_to_cat_comp(const void *a, const void *b, void *data)
00420 {
00421 const qpol_cat_t *cat = a;
00422 const char *name = (const char *)b;
00423 qpol_policy_t *q = (qpol_policy_t *) data;
00424 const char *cat_name = "";
00425 qpol_cat_get_name(q, cat, &cat_name);
00426 return strcmp(name, cat_name);
00427 }
00428
00429 static void mls_level_free(void *elem)
00430 {
00431 apol_mls_level_t *level = elem;
00432 apol_mls_level_destroy(&level);
00433 }
00434
00435 apol_vector_t *apol_mls_range_get_levels(const apol_policy_t * p, const apol_mls_range_t * range)
00436 {
00437 qpol_policy_t *q = apol_policy_get_qpol(p);
00438 apol_vector_t *v = NULL, *catv = NULL;
00439 const qpol_level_t *l;
00440 uint32_t low_value, high_value, value;
00441 int error = 0;
00442 qpol_iterator_t *iter = NULL, *catiter = NULL;
00443
00444 if (p == NULL || range == NULL || range->low == NULL) {
00445 error = EINVAL;
00446 ERR(p, "%s", strerror(error));
00447 goto err;
00448 }
00449 apol_mls_level_t *low_level, *high_level;
00450 low_level = range->low;
00451 if (range->high == NULL) {
00452 high_level = low_level;
00453 } else {
00454 high_level = range->high;
00455 }
00456 if (qpol_policy_get_level_by_name(q, apol_mls_level_get_sens(low_level), &l) < 0 ||
00457 qpol_level_get_value(q, l, &low_value) < 0) {
00458 error = errno;
00459 goto err;
00460 }
00461 if (qpol_policy_get_level_by_name(q, apol_mls_level_get_sens(high_level), &l) < 0 ||
00462 qpol_level_get_value(q, l, &high_value) < 0) {
00463 error = errno;
00464 goto err;
00465 }
00466 assert(low_value <= high_value);
00467 if ((v = apol_vector_create(mls_level_free)) == NULL) {
00468 error = errno;
00469 ERR(p, "%s", strerror(error));
00470 goto err;
00471 }
00472 if (qpol_policy_get_level_iter(q, &iter) < 0) {
00473 error = errno;
00474 goto err;
00475 }
00476 for (; !qpol_iterator_end(iter); qpol_iterator_next(iter)) {
00477 const char *name;
00478 apol_mls_level_t *ml;
00479 if (qpol_iterator_get_item(iter, (void **)&l) < 0 ||
00480 qpol_level_get_value(q, l, &value) < 0 || qpol_level_get_name(q, l, &name) < 0) {
00481 error = errno;
00482 goto err;
00483 }
00484 if (value < low_value || value > high_value) {
00485 continue;
00486 }
00487 if ((ml = apol_mls_level_create()) == NULL || (apol_mls_level_set_sens(p, ml, name) < 0)) {
00488 error = errno;
00489 apol_mls_level_destroy(&ml);
00490 ERR(p, "%s", strerror(error));
00491 goto err;
00492 }
00493
00494 if (qpol_level_get_cat_iter(q, l, &catiter) < 0 || (catv = apol_vector_create_from_iter(catiter, NULL)) == NULL) {
00495 error = errno;
00496 goto err;
00497 }
00498
00499 const apol_vector_t *high_cats = apol_mls_level_get_cats(high_level);
00500 for (size_t i = 0; i < apol_vector_get_size(high_cats); i++) {
00501 char *cat_name = apol_vector_get_element(high_cats, i);
00502
00503 size_t j;
00504
00505
00506 if (apol_vector_get_index(catv, cat_name, mls_level_name_to_cat_comp, q, &j) < 0) {
00507
00508 continue;
00509 }
00510 if (apol_mls_level_append_cats(p, ml, cat_name) < 0) {
00511 error = errno;
00512 apol_mls_level_destroy(&ml);
00513 ERR(p, "%s", strerror(error));
00514 goto err;
00515 }
00516 }
00517
00518 qpol_iterator_destroy(&catiter);
00519 apol_vector_destroy(&catv);
00520
00521 if (apol_vector_append(v, ml) < 0) {
00522 error = errno;
00523 apol_mls_level_destroy(&ml);
00524 ERR(p, "%s", strerror(error));
00525 goto err;
00526 }
00527 }
00528 apol_vector_sort(v, mls_range_comp, q);
00529 qpol_iterator_destroy(&iter);
00530 qpol_iterator_destroy(&catiter);
00531 apol_vector_destroy(&catv);
00532 return v;
00533 err:
00534 qpol_iterator_destroy(&iter);
00535 qpol_iterator_destroy(&catiter);
00536 apol_vector_destroy(&v);
00537 apol_vector_destroy(&catv);
00538 errno = error;
00539 return NULL;
00540 }
00541
00542 char *apol_mls_range_render(const apol_policy_t * p, const apol_mls_range_t * range)
00543 {
00544 char *rt = NULL, *retval = NULL;
00545 char *sub_str = NULL;
00546 int retv;
00547 size_t sz = 0;
00548
00549 if (!range || range->low == NULL) {
00550 ERR(p, "%s", strerror(EINVAL));
00551 errno = EINVAL;
00552 goto cleanup;
00553 }
00554 if (p == NULL && apol_mls_range_is_literal(range) != 1) {
00555 ERR(p, "%s", strerror(EINVAL));
00556 errno = EINVAL;
00557 goto cleanup;
00558 }
00559
00560 if ((sub_str = apol_mls_level_render(p, range->low)) == NULL) {
00561 goto cleanup;
00562 }
00563 if (apol_str_append(&rt, &sz, sub_str)) {
00564 ERR(p, "%s", strerror(errno));
00565 goto cleanup;
00566 }
00567 free(sub_str);
00568 sub_str = NULL;
00569 if (range->high == NULL) {
00570
00571
00572 retval = rt;
00573 goto cleanup;
00574 }
00575 if (p == NULL) {
00576
00577 retv = APOL_MLS_DOM;
00578 } else {
00579 retv = apol_mls_level_compare(p, range->low, range->high);
00580 if (retv < 0) {
00581 goto cleanup;
00582 }
00583 }
00584
00585 if ((retv == APOL_MLS_DOM || retv == APOL_MLS_DOMBY) && range->high != NULL) {
00586 sub_str = apol_mls_level_render(p, range->high);
00587 if (!sub_str)
00588 goto cleanup;
00589 if (apol_str_appendf(&rt, &sz, " - %s", sub_str)) {
00590 ERR(p, "%s", strerror(errno));
00591 goto cleanup;
00592 }
00593 }
00594 retval = rt;
00595 cleanup:
00596 if (retval != rt) {
00597 free(rt);
00598 }
00599 free(sub_str);
00600 return retval;
00601 }
00602
00603 int apol_mls_range_convert(const apol_policy_t * p, apol_mls_range_t * range)
00604 {
00605 if (p == NULL || range == NULL) {
00606 ERR(p, "%s", strerror(EINVAL));
00607 errno = EINVAL;
00608 return -1;
00609 }
00610 apol_mls_level_t *low = range->low;
00611 apol_mls_level_t *high = range->high;
00612 int retval;
00613 if (low != NULL) {
00614 retval = apol_mls_level_convert(p, low);
00615 if (retval < 0) {
00616 return retval;
00617 }
00618 }
00619 if (high != NULL && high != low) {
00620 retval = apol_mls_level_convert(p, high);
00621 if (retval < 0) {
00622 return retval;
00623 }
00624 }
00625 return 0;
00626 }
00627
00628 int apol_mls_range_is_literal(const apol_mls_range_t * range)
00629 {
00630 if (range == NULL) {
00631 return -1;
00632 }
00633 int ret;
00634 if ((ret = apol_mls_level_is_literal(range->low)) != 0) {
00635 return ret;
00636 }
00637 if (range->high != NULL) {
00638 ret = apol_mls_level_is_literal(range->high);
00639 }
00640 return ret;
00641 }