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 "sefs_internal.hh"
00028
00029 #include <sefs/entry.hh>
00030 #include <sefs/fcfile.hh>
00031 #include <apol/util.h>
00032 #include <qpol/genfscon_query.h>
00033 #include <assert.h>
00034 #include <ctype.h>
00035 #include <errno.h>
00036 #include <regex.h>
00037 #include <stdio.h>
00038
00039
00040
00041 static void fcfile_entry_free(void *elem)
00042 {
00043 if (elem != NULL)
00044 {
00045 sefs_entry *entry = static_cast < sefs_entry * >(elem);
00046 delete entry;
00047 }
00048 }
00049
00050 sefs_fcfile::sefs_fcfile(sefs_callback_fn_t msg_callback, void *varg) throw(std::bad_alloc):sefs_fclist(SEFS_FCLIST_TYPE_FCFILE,
00051 msg_callback, varg)
00052 {
00053 _files = _entries = NULL;
00054 _mls_set = false;
00055 try
00056 {
00057 if ((_files = apol_vector_create(free)) == NULL)
00058 {
00059 SEFS_ERR(this, "%s", strerror(errno));
00060 throw std::bad_alloc();
00061 }
00062 if ((_entries = apol_vector_create(fcfile_entry_free)) == NULL)
00063 {
00064 SEFS_ERR(this, "%s", strerror(errno));
00065 throw std::bad_alloc();
00066 }
00067 }
00068 catch(...)
00069 {
00070 apol_vector_destroy(&_files);
00071 apol_vector_destroy(&_entries);
00072 throw;
00073 }
00074 }
00075
00076 sefs_fcfile::sefs_fcfile(const char *file, sefs_callback_fn_t msg_callback, void *varg) throw(std::bad_alloc, std::invalid_argument,
00077 std::
00078 runtime_error):sefs_fclist
00079 (SEFS_FCLIST_TYPE_FCFILE, msg_callback, varg)
00080 {
00081 _files = _entries = NULL;
00082 _mls_set = false;
00083 try
00084 {
00085 if ((_files = apol_vector_create_with_capacity(1, free)) == NULL)
00086 {
00087 SEFS_ERR(this, "%s", strerror(errno));
00088 throw std::bad_alloc();
00089 }
00090 if ((_entries = apol_vector_create(fcfile_entry_free)) == NULL)
00091 {
00092 SEFS_ERR(this, "%s", strerror(errno));
00093 throw std::bad_alloc();
00094 }
00095 if (appendFile(file) < 0)
00096 {
00097 SEFS_ERR(this, "%s", strerror(errno));
00098 throw std::runtime_error("Could not construct fcfile with the given file.");
00099 }
00100 }
00101 catch(...)
00102 {
00103 apol_vector_destroy(&_files);
00104 apol_vector_destroy(&_entries);
00105 throw;
00106 }
00107 }
00108
00109 sefs_fcfile::sefs_fcfile(const apol_vector_t * files, sefs_callback_fn_t msg_callback, void *varg) throw(std::bad_alloc,
00110 std::invalid_argument,
00111 std::
00112 runtime_error):sefs_fclist
00113 (SEFS_FCLIST_TYPE_FCFILE, msg_callback, varg)
00114 {
00115 _files = _entries = NULL;
00116 _mls_set = false;
00117 try
00118 {
00119 if (files == NULL)
00120 {
00121 SEFS_ERR(this, "%s", strerror(EINVAL));
00122 errno = EINVAL;
00123 throw std::invalid_argument(strerror(EINVAL));
00124 }
00125 if ((_files = apol_vector_create_with_capacity(apol_vector_get_size(files), free)) == NULL)
00126 {
00127 SEFS_ERR(this, "%s", strerror(errno));
00128 throw std::bad_alloc();
00129 }
00130 if ((_entries = apol_vector_create(fcfile_entry_free)) == NULL)
00131 {
00132 SEFS_ERR(this, "%s", strerror(errno));
00133 throw std::bad_alloc();
00134 }
00135 if (appendFileList(files) != apol_vector_get_size(files))
00136 {
00137 SEFS_ERR(this, "%s", strerror(errno));
00138 throw std::runtime_error("Could not construct fcfile with the given vector.");
00139 }
00140 }
00141 catch(...)
00142 {
00143 apol_vector_destroy(&_files);
00144 apol_vector_destroy(&_entries);
00145 throw;
00146 }
00147 }
00148
00149 sefs_fcfile::~sefs_fcfile()
00150 {
00151 apol_vector_destroy(&_files);
00152 apol_vector_destroy(&_entries);
00153 }
00154
00155 int sefs_fcfile::runQueryMap(sefs_query * query, sefs_fclist_map_fn_t fn, void *data) throw(std::runtime_error,
00156 std::invalid_argument)
00157 {
00158 apol_vector_t *type_list = NULL;
00159 apol_mls_range_t *range = NULL;
00160 int retval = 0;
00161 try
00162 {
00163 if (query != NULL)
00164 {
00165 query->compile();
00166 if (policy != NULL)
00167 {
00168 if (query->_type != NULL && query->_indirect &&
00169 (type_list =
00170 query_create_candidate_type(policy, query->_type, query->_retype, query->_regex,
00171 query->_indirect)) == NULL)
00172 {
00173 SEFS_ERR(this, "%s", strerror(errno));
00174 throw std::runtime_error(strerror(errno));
00175 }
00176 if (query->_range != NULL && query->_rangeMatch != 0 &&
00177 (range = apol_mls_range_create_from_string(policy, query->_range)) == NULL)
00178 {
00179 SEFS_ERR(this, "%s", strerror(errno));
00180 throw std::runtime_error(strerror(errno));
00181 }
00182 }
00183 }
00184
00185 for (size_t i = 0; i < apol_vector_get_size(_entries); i++)
00186 {
00187 sefs_entry *e = static_cast < sefs_entry * >(apol_vector_get_element(_entries, i));
00188 if (query != NULL)
00189 {
00190 const struct sefs_context_node *context = e->_context;
00191 if (!query_str_compare(context->user, query->_user, query->_reuser, query->_regex))
00192 {
00193 continue;
00194 }
00195 if (!query_str_compare(context->role, query->_role, query->_rerole, query->_regex))
00196 {
00197 continue;
00198 }
00199
00200 bool str_matched = false, pol_matched = false;
00201 str_matched = query_str_compare(context->type, query->_type, query->_retype, query->_regex);
00202 if (type_list != NULL && !str_matched)
00203 {
00204 size_t index;
00205 pol_matched =
00206 (apol_vector_get_index(type_list, context->type, apol_str_strcmp, NULL, &index) <
00207 0);
00208 }
00209 if (!str_matched && !pol_matched)
00210 {
00211 continue;
00212 }
00213
00214 if (isMLS())
00215 {
00216 if (range == NULL)
00217 {
00218 if (!query_str_compare
00219 (context->range, query->_range, query->_rerange, query->_regex))
00220 {
00221 continue;
00222 }
00223 }
00224 else
00225 {
00226 const apol_mls_range_t *context_range = apol_context_get_range(context->context);
00227 int ret;
00228 ret = apol_mls_range_compare(policy, context_range, range, query->_rangeMatch);
00229 if (ret <= 0)
00230 {
00231 continue;
00232 }
00233 }
00234 }
00235
00236 if (e->_objectClass != QPOL_CLASS_ALL && query->_objclass != QPOL_CLASS_ALL &&
00237 e->_objectClass != query->_objclass)
00238 {
00239 continue;
00240 }
00241
00242 bool path_matched;
00243
00244 if (query->_path == NULL || query->_path[0] == '\0')
00245 {
00246 path_matched = true;
00247 }
00248 else
00249 {
00250 path_matched = false;
00251 char *anchored_path = NULL;
00252 if (asprintf(&anchored_path, "^%s$", e->_path) < 0)
00253 {
00254 SEFS_ERR(this, "%s", strerror(errno));
00255 throw std::runtime_error(strerror(errno));
00256 }
00257
00258 regex_t regex;
00259 if (regcomp(®ex, anchored_path, REG_EXTENDED | REG_NOSUB) != 0)
00260 {
00261 free(anchored_path);
00262 SEFS_ERR(this, "%s", strerror(errno));
00263 throw std::runtime_error(strerror(errno));
00264 }
00265
00266 bool compval = query_str_compare(query->_path, anchored_path, ®ex, true);
00267 free(anchored_path);
00268 regfree(®ex);
00269 if (compval)
00270 {
00271 path_matched = true;
00272 }
00273 }
00274 if (!path_matched)
00275 {
00276 continue;
00277 }
00278 }
00279
00280
00281
00282
00283 if ((retval = fn(this, e, data)) < 0)
00284 {
00285 return retval;
00286 }
00287 }
00288 }
00289 catch(...)
00290 {
00291 apol_vector_destroy(&type_list);
00292 apol_mls_range_destroy(&range);
00293 throw;
00294 }
00295 apol_vector_destroy(&type_list);
00296 return retval;
00297 }
00298
00299 bool sefs_fcfile::isMLS() const
00300 {
00301 if (_mls_set)
00302 {
00303 return _mls;
00304 }
00305 return false;
00306 }
00307
00308 int sefs_fcfile::appendFile(const char *file) throw(std::bad_alloc, std::invalid_argument, std::runtime_error)
00309 {
00310 FILE *fc_file = NULL;
00311 char *line = NULL, *name_dup = NULL;
00312 size_t line_len = 0;
00313 size_t last_entry = apol_vector_get_size(_entries);
00314 int retval, error = 0;
00315
00316 regex_t line_regex, context_regex;
00317 bool is_line_compiled = false;
00318 bool is_context_compiled = false;
00319
00320 try
00321 {
00322 if (file == NULL)
00323 {
00324 errno = EINVAL;
00325 SEFS_ERR(this, "%s", strerror(EINVAL));
00326 throw std::invalid_argument(strerror(EINVAL));
00327 }
00328
00329 fc_file = fopen(file, "r");
00330 if (!fc_file)
00331 {
00332 SEFS_ERR(this, "Unable to open file %s", file);
00333 throw std::runtime_error(strerror(error));
00334 }
00335
00336 if ((name_dup = strdup(file)) == NULL)
00337 {
00338 SEFS_ERR(this, "%s", strerror(error));
00339 throw std::bad_alloc();
00340 }
00341
00342 if (regcomp(&line_regex, "^([^[:blank:]]+)[[:blank:]]+(-.[[:blank:]]+)?([^-].+)$", REG_EXTENDED) != 0)
00343 {
00344 SEFS_ERR(this, "%s", strerror(error));
00345 throw std::bad_alloc();
00346 }
00347 is_line_compiled = true;
00348
00349 if (regcomp(&context_regex, "^([^:]+):([^:]+):([^:]+):?(.*)$", REG_EXTENDED) != 0)
00350 {
00351 SEFS_ERR(this, "%s", strerror(error));
00352 throw std::bad_alloc();
00353 }
00354 is_context_compiled = true;
00355
00356 while (!feof(fc_file))
00357 {
00358 if (getline(&line, &line_len, fc_file) == -1)
00359 {
00360 if (feof(fc_file))
00361 {
00362 break;
00363 }
00364 else
00365 {
00366 SEFS_ERR(this, "%s", strerror(error));
00367 throw std::bad_alloc();
00368 }
00369 }
00370 parse_line(name_dup, line, &line_regex, &context_regex);
00371 }
00372
00373 if (apol_vector_append(_files, name_dup) < 0)
00374 {
00375 SEFS_ERR(this, "%s", strerror(error));
00376 throw std::bad_alloc();
00377 }
00378 name_dup = NULL;
00379
00380 retval = 0;
00381 }
00382 catch(...)
00383 {
00384 error = errno;
00385
00386 size_t i = apol_vector_get_size(_entries);
00387 for (; i > last_entry; i--)
00388 {
00389 sefs_entry *e = static_cast < sefs_entry * >(apol_vector_get_element(_entries, i - 1));
00390 fcfile_entry_free(e);
00391 apol_vector_remove(_entries, i - 1);
00392 }
00393 retval = -1;
00394 }
00395
00396 if (fc_file != NULL)
00397 {
00398 fclose(fc_file);
00399 }
00400 if (is_line_compiled)
00401 {
00402 regfree(&line_regex);
00403 }
00404 if (is_context_compiled)
00405 {
00406 regfree(&context_regex);
00407 }
00408 free(name_dup);
00409 free(line);
00410 errno = error;
00411 return retval;
00412 }
00413
00414 size_t sefs_fcfile::appendFileList(const apol_vector_t * files)throw(std::bad_alloc, std::invalid_argument, std::runtime_error)
00415 {
00416 size_t i;
00417 if (files == NULL)
00418 {
00419 SEFS_ERR(this, "%s", strerror(EINVAL));
00420 errno = EINVAL;
00421 throw new std::invalid_argument(strerror(EINVAL));
00422 }
00423 for (i = 0; i < apol_vector_get_size(files); i++)
00424 {
00425 if (appendFile(static_cast < char *>(apol_vector_get_element(files, i))) < 0)
00426 {
00427 return i;
00428 }
00429 }
00430 return i;
00431 }
00432
00433 const apol_vector_t *sefs_fcfile::fileList() const
00434 {
00435 return _files;
00436 }
00437
00438
00439
00440 void sefs_fcfile::parse_line(const char *origin, const char *line, regex_t * line_regex,
00441 regex_t * context_regex) throw(std::bad_alloc, std::runtime_error)
00442 {
00443 int error = 0;
00444
00445 char *s = strdup(line);
00446 char *path;
00447
00448 if (s == NULL)
00449 {
00450 error = errno;
00451 SEFS_ERR(this, "%s", strerror(error));
00452 throw std::bad_alloc();
00453 }
00454
00455 apol_str_trim(s);
00456 if (s[0] == '#' || s[0] == '\0')
00457 {
00458 free(s);
00459 return;
00460 }
00461
00462 try
00463 {
00464 const size_t nmatch = 5;
00465 regmatch_t pmatch[nmatch];
00466
00467 if (regexec(line_regex, s, nmatch, pmatch, 0) != 0)
00468 {
00469 error = EIO;
00470 SEFS_ERR(this, "fcfile line is not legal:\n%s", s);
00471 throw std::runtime_error(strerror(error));
00472 }
00473
00474 assert(pmatch[1].rm_so == 0);
00475 s[pmatch[1].rm_eo] = '\0';
00476 if ((path = strdup(s)) == NULL)
00477 {
00478 SEFS_ERR(this, "%s", strerror(errno));
00479 throw std::runtime_error(strerror(error));
00480 }
00481 if (apol_bst_insert_and_get(path_tree, (void **)&path, NULL) < 0)
00482 {
00483 free(path);
00484 SEFS_ERR(this, "%s", strerror(errno));
00485 throw std::runtime_error(strerror(error));
00486 }
00487
00488 uint32_t objclass;
00489 if (pmatch[2].rm_so != -1)
00490 {
00491 switch (s[pmatch[2].rm_so + 1])
00492 {
00493 case '-':
00494 objclass = QPOL_CLASS_FILE;
00495 break;
00496 case 'd':
00497 objclass = QPOL_CLASS_DIR;
00498 break;
00499 case 'c':
00500 objclass = QPOL_CLASS_CHR_FILE;
00501 break;
00502 case 'b':
00503 objclass = QPOL_CLASS_BLK_FILE;
00504 break;
00505 case 'p':
00506 objclass = QPOL_CLASS_FIFO_FILE;
00507 break;
00508 case 'l':
00509 objclass = QPOL_CLASS_LNK_FILE;
00510 break;
00511 case 's':
00512 objclass = QPOL_CLASS_SOCK_FILE;
00513 break;
00514 default:
00515 error = EIO;
00516 SEFS_ERR(this, "%s", "Invalid file context object class.");
00517 throw std::runtime_error(strerror(error));
00518 }
00519 }
00520 else
00521 {
00522
00523 objclass = QPOL_CLASS_ALL;
00524 }
00525
00526 assert(pmatch[3].rm_so != -1);
00527 char *context_str = s + pmatch[3].rm_so;
00528 char *user, *role, *type, *range;
00529
00530 if (strcmp(context_str, "<<none>>") == 0)
00531 {
00532 user = role = type = range = "";
00533 }
00534 else
00535 {
00536 if (regexec(context_regex, context_str, nmatch, pmatch, 0) != 0)
00537 {
00538 error = EIO;
00539 SEFS_ERR(this, "fcfile context is not legal:\n%s", context_str);
00540 throw std::runtime_error(strerror(error));
00541 }
00542
00543 assert(pmatch[1].rm_so == 0);
00544 context_str[pmatch[1].rm_eo] = '\0';
00545 user = context_str;
00546
00547 assert(pmatch[2].rm_so != -1);
00548 context_str[pmatch[2].rm_eo] = '\0';
00549 role = context_str + pmatch[2].rm_so;
00550
00551 assert(pmatch[3].rm_so != -1);
00552 context_str[pmatch[3].rm_eo] = '\0';
00553 type = context_str + pmatch[3].rm_so;
00554
00555 range = NULL;
00556 if (pmatch[4].rm_so != -1)
00557 {
00558 range = context_str + pmatch[4].rm_so;
00559 }
00560 }
00561 if (range != NULL & range[0] != '\0')
00562 {
00563 if (_mls_set && !_mls)
00564 {
00565 error = EIO;
00566 SEFS_ERR(this, "fcfile context is MLS, but fcfile is not:\n%s", context_str);
00567 throw std::runtime_error(strerror(error));
00568 }
00569 _mls = true;
00570 _mls_set = true;
00571 }
00572 else
00573 {
00574 if (_mls_set && !_mls && strcmp(context_str, "<<none>>") != 0)
00575 {
00576 error = EIO;
00577 SEFS_ERR(this, "fcfile context is not MLS, but fcfile is:\n%s", context_str);
00578 throw std::runtime_error(strerror(error));
00579 }
00580 _mls = true;
00581 _mls_set = false;
00582 }
00583 struct sefs_context_node *context = getContext(user, role, type, range);
00584 sefs_entry *entry = new sefs_entry(this, context, objclass, path, origin);
00585
00586 if (apol_vector_append(_entries, static_cast < void *>(entry)) < 0)
00587 {
00588 error = errno;
00589 delete entry;
00590 SEFS_ERR(this, "%s", strerror(error));
00591 throw std::bad_alloc();
00592 }
00593 }
00594
00595 catch(...)
00596 {
00597 free(s);
00598 errno = error;
00599 throw;
00600 }
00601
00602 free(s);
00603 }
00604
00605
00606
00607 sefs_fclist_t *sefs_fcfile_create(sefs_callback_fn_t msg_callback, void *varg)
00608 {
00609 sefs_fclist *fclist;
00610 try
00611 {
00612 fclist = new sefs_fcfile(msg_callback, varg);
00613 }
00614 catch(...)
00615 {
00616 errno = ENOMEM;
00617 return NULL;
00618 }
00619 return fclist;
00620 }
00621
00622 sefs_fclist_t *sefs_fcfile_create_from_file(const char *file, sefs_callback_fn_t msg_callback, void *varg)
00623 {
00624 sefs_fclist *fclist;
00625 try
00626 {
00627 fclist = new sefs_fcfile(file, msg_callback, varg);
00628 }
00629 catch(...)
00630 {
00631 errno = ENOMEM;
00632 return NULL;
00633 }
00634 return fclist;
00635 }
00636
00637 sefs_fclist_t *sefs_fcfile_create_from_file_list(const apol_vector_t * files, sefs_callback_fn_t msg_callback, void *varg)
00638 {
00639 sefs_fclist *fclist;
00640 try
00641 {
00642 fclist = new sefs_fcfile(files, msg_callback, varg);
00643 }
00644 catch(...)
00645 {
00646 errno = ENOMEM;
00647 return NULL;
00648 }
00649 return fclist;
00650 }
00651
00652 int sefs_fcfile_append_file(sefs_fcfile_t * fcfile, const char *file)
00653 {
00654 if (fcfile == NULL)
00655 {
00656 SEFS_ERR(fcfile, "%s", strerror(EINVAL));
00657 errno = EINVAL;
00658 return -1;
00659 }
00660 try
00661 {
00662 fcfile->appendFile(file);
00663 }
00664 catch(...)
00665 {
00666 return -1;
00667 }
00668 return 0;
00669 }
00670
00671 size_t sefs_fcfile_append_file_list(sefs_fcfile_t * fcfile, const apol_vector_t * files)
00672 {
00673 if (fcfile == NULL)
00674 {
00675 SEFS_ERR(fcfile, "%s", strerror(EINVAL));
00676 errno = EINVAL;
00677 return 0;
00678 }
00679 return fcfile->appendFileList(files);
00680 }
00681
00682 const apol_vector_t *sefs_fcfile_get_file_list(const sefs_fcfile_t * fcfile)
00683 {
00684 if (fcfile == NULL)
00685 {
00686 SEFS_ERR(fcfile, "%s", strerror(EINVAL));
00687 errno = EINVAL;
00688 return NULL;
00689 }
00690 return fcfile->fileList();
00691 }