context-query.c

Go to the documentation of this file.
00001 /**
00002  *  @file
00003  *  Implementation for querying aspects of a context.
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 "policy-query-internal.h"
00026 
00027 #include <assert.h>
00028 #include <errno.h>
00029 #include <stdbool.h>
00030 #include <stdlib.h>
00031 #include <string.h>
00032 
00033 #include <apol/render.h>
00034 
00035 struct apol_context
00036 {
00037         char *user, *role, *type;
00038         apol_mls_range_t *range;
00039 };
00040 
00041 apol_context_t *apol_context_create(void)
00042 {
00043         return calloc(1, sizeof(apol_context_t));
00044 }
00045 
00046 apol_context_t *apol_context_create_from_qpol_context(const apol_policy_t * p, const qpol_context_t * context)
00047 {
00048         apol_context_t *c = NULL;
00049         const qpol_user_t *user;
00050         const qpol_role_t *role;
00051         const qpol_type_t *type;
00052         const qpol_mls_range_t *range;
00053         const char *user_name, *role_name, *type_name;
00054         apol_mls_range_t *apol_range = NULL;
00055         if ((c = apol_context_create()) == NULL) {
00056                 ERR(p, "%s", strerror(ENOMEM));
00057                 goto err;
00058         }
00059         if (qpol_context_get_user(p->p, context, &user) < 0 ||
00060             qpol_context_get_role(p->p, context, &role) < 0 ||
00061             qpol_context_get_type(p->p, context, &type) < 0 || qpol_context_get_range(p->p, context, &range) < 0) {
00062                 goto err;
00063         }
00064         if (qpol_user_get_name(p->p, user, &user_name) < 0 ||
00065             qpol_role_get_name(p->p, role, &role_name) < 0 || qpol_type_get_name(p->p, type, &type_name) < 0) {
00066                 goto err;
00067         }
00068         if (qpol_policy_has_capability(p->p, QPOL_CAP_MLS)) {
00069                 /* if the policy is MLS then convert the range, else
00070                  * rely upon the default value of NULL */
00071                 if ((apol_range = apol_mls_range_create_from_qpol_mls_range(p, range)) == NULL) {
00072                         goto err;
00073                 }
00074         }
00075         if (apol_context_set_user(p, c, user_name) < 0 ||
00076             apol_context_set_role(p, c, role_name) < 0 ||
00077             apol_context_set_type(p, c, type_name) < 0 || apol_context_set_range(p, c, apol_range) < 0) {
00078                 goto err;
00079         }
00080         return c;
00081       err:
00082         apol_mls_range_destroy(&apol_range);
00083         apol_context_destroy(&c);
00084         return NULL;
00085 }
00086 
00087 apol_context_t *apol_context_create_from_literal(const char *context_string)
00088 {
00089         apol_context_t *c = NULL;
00090         bool is_context_compiled = false;
00091         regex_t context_regex;
00092         const size_t nmatch = 5;
00093         regmatch_t pmatch[nmatch];
00094 
00095         if ((c = apol_context_create()) == NULL) {
00096                 goto err;
00097         }
00098 
00099         if (regcomp(&context_regex, "^([^:]*):([^:]*):([^:]*):?(.*)$", REG_EXTENDED) != 0) {
00100                 goto err;
00101         }
00102         is_context_compiled = true;
00103 
00104         if (regexec(&context_regex, context_string, nmatch, pmatch, 0) != 0) {
00105                 errno = EIO;
00106                 goto err;
00107         }
00108 
00109         const char *s;
00110         size_t len;
00111 
00112         assert(pmatch[1].rm_so == 0);
00113         s = context_string + pmatch[1].rm_so;
00114         len = pmatch[1].rm_eo - pmatch[1].rm_so;        // no +1 to avoid copying colon
00115         if (len != 0 && *s != '*' && (c->user = strndup(s, len)) == NULL) {
00116                 goto err;
00117         }
00118 
00119         assert(pmatch[2].rm_so != -1);
00120         s = context_string + pmatch[2].rm_so;
00121         len = pmatch[2].rm_eo - pmatch[2].rm_so;        // no +1 to avoid copying colon
00122         if (len != 0 && *s != '*' && (c->role = strndup(s, len)) == NULL) {
00123                 goto err;
00124         }
00125 
00126         assert(pmatch[3].rm_so != -1);
00127         s = context_string + pmatch[3].rm_so;
00128         len = pmatch[3].rm_eo - pmatch[3].rm_so;        // no +1 to avoid copying colon
00129         if (len != 0 && *s != '*' && (c->type = strndup(s, len)) == NULL) {
00130                 goto err;
00131         }
00132 
00133         if (pmatch[4].rm_so != -1) {
00134                 s = context_string + pmatch[4].rm_so;
00135                 len = pmatch[4].rm_eo - pmatch[4].rm_so;
00136                 if (len != 0 && *s != '*' && (c->range = apol_mls_range_create_from_literal(s)) == NULL) {
00137                         goto err;
00138                 }
00139         }
00140 
00141         regfree(&context_regex);
00142         return c;
00143 
00144       err:
00145         apol_context_destroy(&c);
00146         if (is_context_compiled) {
00147                 regfree(&context_regex);
00148         }
00149         return NULL;
00150 }
00151 
00152 void apol_context_destroy(apol_context_t ** context)
00153 {
00154         if (*context != NULL) {
00155                 free((*context)->user);
00156                 free((*context)->role);
00157                 free((*context)->type);
00158                 apol_mls_range_destroy(&((*context)->range));
00159                 free(*context);
00160                 *context = NULL;
00161         }
00162 }
00163 
00164 int apol_context_set_user(const apol_policy_t * p, apol_context_t * context, const char *user)
00165 {
00166         if (context == NULL) {
00167                 ERR(p, "%s", strerror(EINVAL));
00168                 errno = EINVAL;
00169                 return -1;
00170         }
00171         if (user != context->user) {
00172                 free(context->user);
00173                 context->user = NULL;
00174                 if (user != NULL && (context->user = strdup(user)) == NULL) {
00175                         ERR(p, "%s", strerror(errno));
00176                         return -1;
00177                 }
00178         }
00179         return 0;
00180 }
00181 
00182 int apol_context_set_role(const apol_policy_t * p, apol_context_t * context, const char *role)
00183 {
00184         if (context == NULL) {
00185                 ERR(p, "%s", strerror(EINVAL));
00186                 errno = EINVAL;
00187                 return -1;
00188         }
00189         if (role != context->role) {
00190                 free(context->role);
00191                 context->role = NULL;
00192                 if (role != NULL && (context->role = strdup(role)) == NULL) {
00193                         ERR(p, "%s", strerror(errno));
00194                         return -1;
00195                 }
00196         }
00197         return 0;
00198 }
00199 
00200 int apol_context_set_type(const apol_policy_t * p, apol_context_t * context, const char *type)
00201 {
00202         if (context == NULL) {
00203                 ERR(p, "%s", strerror(EINVAL));
00204                 errno = EINVAL;
00205                 return -1;
00206         }
00207         if (type != context->type) {
00208                 free(context->type);
00209                 context->type = NULL;
00210                 if (type != NULL && (context->type = strdup(type)) == NULL) {
00211                         ERR(p, "%s", strerror(errno));
00212                         return -1;
00213                 }
00214         }
00215         return 0;
00216 }
00217 
00218 int apol_context_set_range(const apol_policy_t * p, apol_context_t * context, apol_mls_range_t * range)
00219 {
00220         if (context == NULL) {
00221                 ERR(p, "%s", strerror(EINVAL));
00222                 errno = EINVAL;
00223                 return -1;
00224         }
00225         if (range != context->range) {
00226                 apol_mls_range_destroy(&(context->range));
00227                 context->range = range;
00228         }
00229         return 0;
00230 }
00231 
00232 const char *apol_context_get_user(const apol_context_t * context)
00233 {
00234         if (context == NULL) {
00235                 errno = EINVAL;
00236                 return NULL;
00237         }
00238         return context->user;
00239 }
00240 
00241 const char *apol_context_get_role(const apol_context_t * context)
00242 {
00243         if (context == NULL) {
00244                 errno = EINVAL;
00245                 return NULL;
00246         }
00247         return context->role;
00248 }
00249 
00250 const char *apol_context_get_type(const apol_context_t * context)
00251 {
00252         if (context == NULL) {
00253                 errno = EINVAL;
00254                 return NULL;
00255         }
00256         return context->type;
00257 }
00258 
00259 const apol_mls_range_t *apol_context_get_range(const apol_context_t * context)
00260 {
00261         if (context == NULL) {
00262                 errno = EINVAL;
00263                 return NULL;
00264         }
00265         return context->range;
00266 }
00267 
00268 int apol_context_compare(const apol_policy_t * p, const apol_context_t * target, const apol_context_t * search,
00269                          unsigned int range_compare_type)
00270 {
00271         uint32_t value0, value1;
00272         if (p == NULL || target == NULL || search == NULL) {
00273                 ERR(p, "%s", strerror(EINVAL));
00274                 errno = EINVAL;
00275                 return -1;
00276         }
00277         if (target->user != NULL && search->user != NULL) {
00278                 const qpol_user_t *user0, *user1;
00279                 if (qpol_policy_get_user_by_name(p->p,
00280                                                  target->user, &user0) < 0 ||
00281                     qpol_policy_get_user_by_name(p->p,
00282                                                  search->user, &user1) < 0 ||
00283                     qpol_user_get_value(p->p, user0, &value0) < 0 || qpol_user_get_value(p->p, user1, &value1) < 0) {
00284                         return -1;
00285                 }
00286                 if (value0 != value1) {
00287                         return 0;
00288                 }
00289         }
00290         if (target->role != NULL && search->role != NULL) {
00291                 const qpol_role_t *role0, *role1;
00292                 if (qpol_policy_get_role_by_name(p->p,
00293                                                  target->role, &role0) < 0 ||
00294                     qpol_policy_get_role_by_name(p->p,
00295                                                  search->role, &role1) < 0 ||
00296                     qpol_role_get_value(p->p, role0, &value0) < 0 || qpol_role_get_value(p->p, role1, &value1) < 0) {
00297                         return -1;
00298                 }
00299                 if (value0 != value1) {
00300                         return 0;
00301                 }
00302         }
00303         if (target->type != NULL && search->type != NULL) {
00304                 const qpol_type_t *type0, *type1;
00305                 if (qpol_policy_get_type_by_name(p->p,
00306                                                  target->type, &type0) < 0 ||
00307                     qpol_policy_get_type_by_name(p->p,
00308                                                  search->type, &type1) < 0 ||
00309                     qpol_type_get_value(p->p, type0, &value0) < 0 || qpol_type_get_value(p->p, type1, &value1) < 0) {
00310                         return -1;
00311                 }
00312                 if (value0 != value1) {
00313                         return 0;
00314                 }
00315         }
00316         if (target->range != NULL && search->range != NULL) {
00317                 return apol_mls_range_compare(p, target->range, search->range, range_compare_type);
00318         }
00319         return 1;
00320 }
00321 
00322 int apol_context_validate(const apol_policy_t * p, const apol_context_t * context)
00323 {
00324         if (context == NULL ||
00325             context->user == NULL ||
00326             context->role == NULL || context->type == NULL || (apol_policy_is_mls(p) && context->range == NULL)) {
00327                 ERR(p, "%s", strerror(EINVAL));
00328                 errno = EINVAL;
00329                 return -1;
00330         }
00331         return apol_context_validate_partial(p, context);
00332 }
00333 
00334 int apol_context_validate_partial(const apol_policy_t * p, const apol_context_t * context)
00335 {
00336         apol_user_query_t *user_query = NULL;
00337         apol_role_query_t *role_query = NULL;
00338         apol_vector_t *user_v = NULL, *role_v = NULL;
00339         const qpol_user_t *user;
00340         const qpol_type_t *type;
00341         const qpol_mls_range_t *user_range;
00342         apol_mls_range_t *user_apol_range = NULL;
00343         int retval = -1, retval2;
00344 
00345         if (context == NULL) {
00346                 return 1;
00347         }
00348         if (context->user != NULL) {
00349                 if ((user_query = apol_user_query_create()) == NULL) {
00350                         ERR(p, "%s", strerror(ENOMEM));
00351                 }
00352                 if (apol_user_query_set_user(p, user_query, context->user) < 0 ||
00353                     (context->role != NULL && apol_user_query_set_role(p, user_query, context->role) < 0) ||
00354                     apol_user_get_by_query(p, user_query, &user_v) < 0) {
00355                         goto cleanup;
00356                 }
00357                 if (apol_vector_get_size(user_v) == 0) {
00358                         retval = 0;
00359                         goto cleanup;
00360                 }
00361         }
00362         if (context->role != NULL) {
00363                 if ((role_query = apol_role_query_create()) == NULL) {
00364                         ERR(p, "%s", strerror(ENOMEM));
00365                 }
00366                 if (apol_role_query_set_role(p, role_query, context->role) < 0 ||
00367                     (context->type != NULL && apol_role_query_set_type(p, role_query, context->type) < 0) ||
00368                     apol_role_get_by_query(p, role_query, &role_v) < 0) {
00369                         goto cleanup;
00370                 }
00371                 if (apol_vector_get_size(role_v) == 0) {
00372                         retval = 0;
00373                         goto cleanup;
00374                 }
00375         }
00376         if (context->type != NULL) {
00377                 if (qpol_policy_get_type_by_name(p->p, context->type, &type) < 0) {
00378                         retval = 0;
00379                         goto cleanup;
00380                 }
00381         }
00382         if (apol_policy_is_mls(p) && context->range != NULL) {
00383                 retval2 = apol_mls_range_validate(p, context->range);
00384                 if (retval2 != 1) {
00385                         retval = retval2;
00386                         goto cleanup;
00387                 }
00388                 /* next check that the user has access to this context */
00389                 if (context->user != NULL) {
00390                         if (qpol_policy_get_user_by_name(p->p, context->user, &user) < 0 ||
00391                             qpol_user_get_range(p->p, user, &user_range) < 0) {
00392                                 goto cleanup;
00393                         }
00394                         user_apol_range = apol_mls_range_create_from_qpol_mls_range(p, user_range);
00395                         if (user_apol_range == NULL) {
00396                                 ERR(p, "%s", strerror(ENOMEM));
00397                                 goto cleanup;
00398                         }
00399                         retval2 = apol_mls_range_compare(p, user_apol_range, context->range, APOL_QUERY_SUB);
00400                         if (retval2 != 1) {
00401                                 retval = retval2;
00402                                 goto cleanup;
00403                         }
00404                 }
00405         }
00406         retval = 1;
00407       cleanup:
00408         apol_user_query_destroy(&user_query);
00409         apol_role_query_destroy(&role_query);
00410         apol_vector_destroy(&user_v);
00411         apol_vector_destroy(&role_v);
00412         apol_mls_range_destroy(&user_apol_range);
00413         return retval;
00414 }
00415 
00416 char *apol_context_render(const apol_policy_t * p, const apol_context_t * context)
00417 {
00418         char *buf = NULL, *range_str = NULL;
00419         size_t buf_sz = 0;
00420 
00421         if (context == NULL) {
00422                 ERR(p, "%s", strerror(EINVAL));
00423                 errno = EINVAL;
00424                 return NULL;
00425         }
00426         if (p == NULL && !apol_mls_range_is_literal(context->range)) {
00427                 ERR(p, "%s", strerror(EINVAL));
00428                 errno = EINVAL;
00429                 return NULL;
00430         }
00431         if (apol_str_appendf(&buf, &buf_sz, "%s:", (context->user != NULL ? context->user : "*")) != 0) {
00432                 ERR(p, "%s", strerror(errno));
00433                 goto err_return;
00434         }
00435         if (apol_str_appendf(&buf, &buf_sz, "%s:", (context->role != NULL ? context->role : "*")) != 0) {
00436                 ERR(p, "%s", strerror(errno));
00437                 goto err_return;
00438         }
00439         if (apol_str_append(&buf, &buf_sz, (context->type != NULL ? context->type : "*")) != 0) {
00440                 ERR(p, "%s", strerror(errno));
00441                 goto err_return;
00442         }
00443         if ((p != NULL && apol_policy_is_mls(p)) || (p == NULL)) {
00444                 if (context->range == NULL) {
00445                         range_str = strdup("*");
00446                 } else {
00447                         range_str = apol_mls_range_render(p, context->range);
00448                 }
00449                 if (range_str == NULL) {
00450                         goto err_return;
00451                 }
00452                 if (apol_str_appendf(&buf, &buf_sz, ":%s", range_str) != 0) {
00453                         ERR(p, "%s", strerror(errno));
00454                         goto err_return;
00455                 }
00456                 free(range_str);
00457         }
00458         return buf;
00459 
00460       err_return:
00461         free(buf);
00462         free(range_str);
00463         return NULL;
00464 }
00465 
00466 int apol_context_convert(const apol_policy_t * p, apol_context_t * context)
00467 {
00468         if (p == NULL || context == NULL) {
00469                 ERR(p, "%s", strerror(EINVAL));
00470                 errno = EINVAL;
00471                 return -1;
00472         }
00473         if (context->range != NULL) {
00474                 return apol_mls_range_convert(p, context->range);
00475         }
00476         return 0;
00477 }