mls_range.c

Go to the documentation of this file.
00001 /**
00002  *  @file
00003  *  Implementation of apol_mls_range class.
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 <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                 // just a low level
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                 // both a low and a high level
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                 // just a low level
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                 // both a low and a high level
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         /* low */
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         /* high */
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         /* FIX ME:  intersect does not work */
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         /* EXACT has to come first because its bits are both SUB and SUPER */
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         /* parent range validity will be checked via
00361          * apol_mls_range_include_level() */
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         /* both low and high levels exist, so now check that high
00393          * dominates low */
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                         /* do not add categories that are not members of
00505                            the level */
00506                         if (apol_vector_get_index(catv, cat_name, mls_level_name_to_cat_comp, q, &j) < 0) {
00507                                 /* this category is not legal under the given policy */
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                 /* no high level set, so skip the rest of this render
00571                  * function */
00572                 retval = rt;
00573                 goto cleanup;
00574         }
00575         if (p == NULL) {
00576                 // no policy, so assume that high level dominates low level
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         /* if (high level != low level) */
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 }