fcfile.cc

Go to the documentation of this file.
00001 /**
00002  *  @file
00003  *  Implementation of the sefs_fcfile class.
00004  *
00005  *  @author Jeremy A. Mowery jmowery@tresys.com
00006  *  @author Jason Tang jtang@tresys.com
00007  *
00008  *  Copyright (C) 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 "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 /******************** public functions below ********************/
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(&regex, 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, &regex, true);
00267                                         free(anchored_path);
00268                                         regfree(&regex);
00269                                         if (compval)
00270                                         {
00271                                                 path_matched = true;
00272                                         }
00273                                 }
00274                                 if (!path_matched)
00275                                 {
00276                                         continue;
00277                                 }
00278                         }
00279 
00280                         // if reached this point, then all criteria passed, so
00281                         // invoke the mapping function
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                 // discard all entries that were read from this file_contexts
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 /******************** private functions below ********************/
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                         // no object class explicitly given
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 /******************** C functions below ********************/
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 }