LCOV - code coverage report
Current view: top level - ini - ini_metadata.c (source / functions) Hit Total Coverage
Test: coverage.info Lines: 97 143 67.8 %
Date: 2014-04-01 Functions: 6 7 85.7 %

          Line data    Source code
       1             : /*
       2             :     INI LIBRARY
       3             : 
       4             :     Functions to process metadata.
       5             : 
       6             :     Copyright (C) Dmitri Pal <dpal@redhat.com> 2010
       7             : 
       8             :     INI Library is free software: you can redistribute it and/or modify
       9             :     it under the terms of the GNU Lesser General Public License as published by
      10             :     the Free Software Foundation, either version 3 of the License, or
      11             :     (at your option) any later version.
      12             : 
      13             :     INI Library is distributed in the hope that it will be useful,
      14             :     but WITHOUT ANY WARRANTY; without even the implied warranty of
      15             :     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      16             :     GNU Lesser General Public License for more details.
      17             : 
      18             :     You should have received a copy of the GNU Lesser General Public License
      19             :     along with INI Library.  If not, see <http://www.gnu.org/licenses/>.
      20             : */
      21             : 
      22             : #include "config.h"
      23             : #include <sys/types.h>
      24             : #include <sys/stat.h>
      25             : #include <unistd.h>
      26             : #include <errno.h>
      27             : #include "collection.h"
      28             : #include "collection_tools.h"
      29             : #include "trace.h"
      30             : #include "ini_config.h"
      31             : #include "ini_metadata.h"
      32             : 
      33             : #define INI_METADATA    "meta"
      34             : 
      35             : /* Beffer length used for int to string conversions */
      36             : #define CONVERSION_BUFFER 80
      37             : 
      38             : /* Invalid file mode */
      39             : #define WRONG_FMODE 0x80000000
      40             : 
      41             : /* Prepare metadata */
      42          19 : int prepare_metadata(uint32_t metaflags,
      43             :                      struct collection_item **metadata,
      44             :                      int *save_error)
      45             : {
      46          19 :     int error = EOK;
      47          19 :     struct collection_item *metasec = NULL;
      48             : 
      49             :     TRACE_FLOW_STRING("prepare_metadata", "Entry");
      50             : 
      51             :     /* Are we supposed to collect or process meta data ? */
      52          19 :     if (!metadata) {
      53             :         TRACE_FLOW_STRING("No meta data", "Exit");
      54             :         return EOK;
      55             :     }
      56             : 
      57             :     /* Allocate metadata */
      58           5 :     error = col_create_collection(metadata,
      59             :                                   INI_METADATA,
      60             :                                   COL_CLASS_INI_META);
      61           5 :     if (error) {
      62             :         TRACE_ERROR_NUMBER("Failed to create meta data", error);
      63             :         return error;
      64             :     }
      65             : 
      66             :     /* Check and create section for file error if needed */
      67           5 :     if (metaflags & INI_META_SEC_ERROR_FLAG) {
      68             :         /* Create ERROR collection */
      69           3 :         if ((error = col_create_collection(&metasec,
      70             :                                            INI_META_SEC_ERROR,
      71           3 :                                            COL_CLASS_INI_SECTION)) ||
      72           3 :             (error = col_add_collection_to_collection(
      73             :                                            *metadata,
      74             :                                            NULL,
      75             :                                            NULL,
      76             :                                            metasec,
      77             :                                            COL_ADD_MODE_REFERENCE))) {
      78             :             TRACE_ERROR_NUMBER("Failed to create error section", error);
      79           0 :             col_destroy_collection(metasec);
      80           0 :             col_destroy_collection(*metadata);
      81           0 :             *metadata = NULL;
      82           0 :             return error;
      83             :         }
      84             :         /* If we are here we would have to save file open error */
      85           3 :         *save_error = 1;
      86           3 :         col_destroy_collection(metasec);
      87             :     }
      88             : 
      89             :     TRACE_FLOW_STRING("prepare_metadata", "Exit");
      90           5 :     return error;
      91             : }
      92             : 
      93             : 
      94             : 
      95             : /* Collect metadata for the file */
      96           5 : int collect_metadata(uint32_t metaflags,
      97             :                      struct collection_item **metadata,
      98             :                      FILE *config_file,
      99             :                      const char *config_filename)
     100             : {
     101           5 :     int error = EOK;
     102           5 :     struct collection_item *metasec = NULL;
     103             :     int filedes;
     104             :     struct stat file_stats;
     105             :     char buff[CONVERSION_BUFFER];
     106             : 
     107             :     TRACE_FLOW_STRING("collect_metadata", "Entry");
     108             :     /* Check and create section for file error if needed */
     109           5 :     if (metaflags & INI_META_SEC_ACCESS_FLAG) {
     110             :         /* Create ACCESS collection */
     111           5 :         error = col_create_collection(&metasec,
     112             :                                       INI_META_SEC_ACCESS,
     113             :                                       COL_CLASS_INI_SECTION);
     114           5 :         if (error) {
     115             :             TRACE_ERROR_NUMBER("Failed to create access section.", error);
     116           0 :             col_destroy_collection(metasec);
     117           0 :             return error;
     118             :         }
     119             : 
     120           5 :         filedes = fileno(config_file);
     121             : 
     122             :         /* Collect statistics */
     123           5 :         errno = 0;
     124           5 :         if (fstat(filedes, &file_stats) < 0) {
     125           0 :             error = errno;
     126             :             TRACE_ERROR_NUMBER("Failed to get statistics.", error);
     127           0 :             col_destroy_collection(metasec);
     128           0 :             return error;
     129             :         }
     130             : 
     131             :         /* Record statistics */
     132             :         /* UID */
     133           5 :         snprintf(buff, CONVERSION_BUFFER, "%lu",
     134           5 :                  (unsigned long)file_stats.st_uid);
     135           5 :         error = col_add_str_property(metasec,
     136             :                                      NULL,
     137             :                                      INI_META_KEY_UID,
     138             :                                      buff,
     139             :                                      0);
     140           5 :         if (error) {
     141             :             TRACE_ERROR_NUMBER("Failed to save uid", error);
     142           0 :             col_destroy_collection(metasec);
     143           0 :             return error;
     144             :         }
     145             : 
     146             :         /* GID */
     147           5 :         snprintf(buff, CONVERSION_BUFFER, "%lu",
     148           5 :                  (unsigned long)file_stats.st_gid);
     149           5 :         error = col_add_str_property(metasec,
     150             :                                      NULL,
     151             :                                      INI_META_KEY_GID,
     152             :                                      buff,
     153             :                                      0);
     154           5 :         if (error) {
     155             :             TRACE_ERROR_NUMBER("Failed to save gid", error);
     156           0 :             col_destroy_collection(metasec);
     157           0 :             return error;
     158             :         }
     159             : 
     160             :         /* PERMISSIONS */
     161           5 :         snprintf(buff, CONVERSION_BUFFER, "%lu",
     162           5 :                  (unsigned long)file_stats.st_mode);
     163           5 :         error = col_add_str_property(metasec,
     164             :                                      NULL,
     165             :                                      INI_META_KEY_PERM,
     166             :                                      buff,
     167             :                                      0);
     168           5 :         if (error) {
     169             :             TRACE_ERROR_NUMBER("Failed to save permissions", error);
     170           0 :             col_destroy_collection(metasec);
     171           0 :             return error;
     172             :         }
     173             : 
     174             :         /* Modification time stamp */
     175           5 :         snprintf(buff, CONVERSION_BUFFER, "%ld",
     176             :                  (long int)file_stats.st_mtime);
     177           5 :         error = col_add_str_property(metasec,
     178             :                                      NULL,
     179             :                                      INI_META_KEY_MODIFIED,
     180             :                                      buff,
     181             :                                      0);
     182           5 :         if (error) {
     183             :             TRACE_ERROR_NUMBER("Failed to save modification time", error);
     184           0 :             col_destroy_collection(metasec);
     185           0 :             return error;
     186             :         }
     187             : 
     188             :         /* Name */
     189           5 :         error = col_add_str_property(metasec,
     190             :                                      NULL,
     191             :                                      INI_META_KEY_NAME,
     192             :                                      config_filename,
     193             :                                      0);
     194           5 :         if (error) {
     195             :             TRACE_ERROR_NUMBER("Failed to save file name", error);
     196           0 :             col_destroy_collection(metasec);
     197           0 :             return error;
     198             :         }
     199             : 
     200             :         /* The device ID can actualy be bigger than
     201             :          * 32-bits according to the type sizes.
     202             :          * However it is probaly not going to happen
     203             :          * on a real system.
     204             :          * Add a check for this case.
     205             :          */
     206             :         if (file_stats.st_dev > ULONG_MAX) {
     207             :             TRACE_ERROR_NUMBER("Device is out of range", ERANGE);
     208             :             col_destroy_collection(metasec);
     209             :             return ERANGE;
     210             :         }
     211             : 
     212             :         /* Device  ID */
     213             :         TRACE_INFO_LNUMBER("Device ID", file_stats.st_dev);
     214             : 
     215           5 :         snprintf(buff, CONVERSION_BUFFER, "%lu",
     216             :                  (unsigned long)file_stats.st_dev);
     217           5 :         error = col_add_str_property(metasec,
     218             :                                      NULL,
     219             :                                      INI_META_KEY_DEV,
     220             :                                      buff,
     221             :                                      0);
     222           5 :         if (error) {
     223             :             TRACE_ERROR_NUMBER("Failed to save inode", error);
     224           0 :             col_destroy_collection(metasec);
     225           0 :             return error;
     226             :         }
     227             : 
     228             :         /* i-node */
     229           5 :         snprintf(buff, CONVERSION_BUFFER, "%lu",
     230             :                 (unsigned long)file_stats.st_ino);
     231           5 :         error = col_add_str_property(metasec,
     232             :                                      NULL,
     233             :                                      INI_META_KEY_INODE,
     234             :                                      buff,
     235             :                                      0);
     236           5 :         if (error) {
     237             :             TRACE_ERROR_NUMBER("Failed to save inode", error);
     238           0 :             col_destroy_collection(metasec);
     239           0 :             return error;
     240             :         }
     241             : 
     242             :         /* Add section to metadata */
     243           5 :         error = col_add_collection_to_collection(
     244             :                                     *metadata,
     245             :                                     NULL,
     246             :                                     NULL,
     247             :                                     metasec,
     248             :                                     COL_ADD_MODE_REFERENCE);
     249             : 
     250           5 :         col_destroy_collection(metasec);
     251             : 
     252           5 :         if (error) {
     253             :             TRACE_ERROR_NUMBER("Failed to save file name", error);
     254             :             return error;
     255             :         }
     256             :     }
     257             : 
     258             :     TRACE_FLOW_STRING("collect_metadata", "Exit");
     259           5 :     return error;
     260             : }
     261             : 
     262             : /* Function to free metadata */
     263           5 : void free_ini_config_metadata(struct collection_item *metadata)
     264             : {
     265             :     TRACE_FLOW_STRING("free_ini_config_metadata", "Entry");
     266           5 :     col_destroy_collection(metadata);
     267             :     TRACE_FLOW_STRING("free_ini_config_metadata", "Exit");
     268           5 : }
     269             : 
     270             : /* Function to check uid or gid */
     271           0 : static int check_id(struct collection_item *metadata,
     272             :                     unsigned long id,
     273             :                     const char *key)
     274             : {
     275           0 :     int error = EOK;
     276           0 :     struct collection_item *item = NULL;
     277             :     unsigned long fid;
     278             : 
     279             :     TRACE_FLOW_STRING("check_id", "Entry");
     280             :     TRACE_INFO_STRING("Key", key);
     281             : 
     282           0 :     error = get_config_item(INI_META_SEC_ACCESS,
     283             :                             key,
     284             :                             metadata,
     285             :                             &item);
     286           0 :     if (error) {
     287             :         TRACE_ERROR_NUMBER("Internal collection error.", error);
     288             :         return error;
     289             :     }
     290             : 
     291             :     /* Entry is supposed to be there so it is an error
     292             :         * is the item is not found.
     293             :         */
     294           0 :     if (item == NULL) {
     295             :         TRACE_ERROR_NUMBER("Expected item is not found.", ENOENT);
     296             :         return ENOENT;
     297             :     }
     298             : 
     299           0 :     fid = get_ulong_config_value(item, 1, -1, &error);
     300           0 :     if ((error) || (fid == -1)) {
     301             :         TRACE_ERROR_NUMBER("Conversion failed", EINVAL);
     302             :         return EINVAL;
     303             :     }
     304             : 
     305           0 :     if (id != fid) {
     306             :         TRACE_ERROR_NUMBER("File ID:", fid);
     307             :         TRACE_ERROR_NUMBER("ID passed in.", id);
     308             :         TRACE_ERROR_NUMBER("Access denied.", EACCES);
     309             :         return EACCES;
     310             :     }
     311             : 
     312             :     TRACE_FLOW_STRING("check_id", "Exit");
     313           0 :     return EOK;
     314             : }
     315             : 
     316             : /* Function to check access */
     317           2 : int config_access_check(struct collection_item *metadata,
     318             :                         uint32_t flags,
     319             :                         uid_t uid,
     320             :                         gid_t gid,
     321             :                         mode_t mode,
     322             :                         mode_t mask)
     323             : {
     324           2 :     int error = EOK;
     325           2 :     struct collection_item *item = NULL;
     326             :     mode_t f_mode;
     327             : 
     328             :     TRACE_FLOW_STRING("config_access_check", "Entry");
     329             : 
     330           2 :     flags &= INI_ACCESS_CHECK_MODE |
     331             :              INI_ACCESS_CHECK_GID |
     332             :              INI_ACCESS_CHECK_UID;
     333             : 
     334           2 :     if ((metadata == NULL) || (flags == 0)) {
     335             :         TRACE_ERROR_NUMBER("Invalid parameter.", EINVAL);
     336             :         return EINVAL;
     337             : 
     338             :     }
     339             : 
     340             :     /* Check that metadata is actually metadata */
     341           2 :     if(!col_is_of_class(metadata, COL_CLASS_INI_META)) {
     342             :         TRACE_ERROR_NUMBER("Invalid collection.", EINVAL);
     343             :         return EINVAL;
     344             :     }
     345             : 
     346             :     /* Check mode */
     347           2 :     if (flags & INI_ACCESS_CHECK_MODE) {
     348             : 
     349           2 :         error = get_config_item(INI_META_SEC_ACCESS,
     350             :                                 INI_META_KEY_PERM,
     351             :                                 metadata,
     352             :                                 &item);
     353           2 :         if (error) {
     354             :             TRACE_ERROR_NUMBER("Internal collection error.", error);
     355             :             return error;
     356             :         }
     357             : 
     358             :         /* Entry is supposed to be there so it is an error
     359             :             * is the item is not found.
     360             :             */
     361           2 :         if (item == NULL) {
     362             :             TRACE_ERROR_NUMBER("Expected item is not found.", ENOENT);
     363             :             return ENOENT;
     364             :         }
     365             : 
     366           2 :         f_mode = (mode_t)get_ulong_config_value(item, 1, WRONG_FMODE, &error);
     367           2 :         if ((error) || (f_mode == WRONG_FMODE)) {
     368             :             TRACE_ERROR_NUMBER("Conversion failed", error);
     369             :             return ENOENT;
     370             :         }
     371             : 
     372             :         TRACE_INFO_NUMBER("File mode as saved.", f_mode);
     373           2 :         f_mode &= S_IRWXU | S_IRWXG | S_IRWXO;
     374             :         TRACE_INFO_NUMBER("File mode adjusted.", f_mode);
     375             : 
     376             :         TRACE_INFO_NUMBER("Mode as provided.", mode);
     377           2 :         mode &= S_IRWXU | S_IRWXG | S_IRWXO;
     378             :         TRACE_INFO_NUMBER("Mode adjusted.", mode);
     379             : 
     380             :         /* Adjust mask */
     381           2 :         if (mask == 0) mask = S_IRWXU | S_IRWXG | S_IRWXO;
     382           0 :         else mask &= S_IRWXU | S_IRWXG | S_IRWXO;
     383             : 
     384           2 :         if ((mode & mask) != (f_mode & mask)) {
     385             :             TRACE_INFO_NUMBER("File mode:", (mode & mask));
     386             :             TRACE_INFO_NUMBER("Mode adjusted.", (f_mode & mask));
     387             :             TRACE_ERROR_NUMBER("Access denied.", EACCES);
     388             :             return EACCES;
     389             :         }
     390             :     }
     391             : 
     392             :     /* Check uid */
     393           1 :     if (flags & INI_ACCESS_CHECK_UID) {
     394             : 
     395           0 :         error = check_id(metadata, (unsigned long)uid, INI_META_KEY_UID);
     396           0 :         if (error) {
     397             :             TRACE_ERROR_NUMBER("Check for UID failed.", error);
     398             :             return error;
     399             :         }
     400             :     }
     401             : 
     402             :     /* Check gid */
     403           1 :     if (flags & INI_ACCESS_CHECK_GID) {
     404             : 
     405           0 :         error = check_id(metadata, (unsigned long)gid, INI_META_KEY_GID);
     406           0 :         if (error) {
     407             :             TRACE_ERROR_NUMBER("Check for UID failed.", error);
     408             :             return error;
     409             :         }
     410             :     }
     411             : 
     412             :     TRACE_FLOW_STRING("config_access_check", "Exit");
     413           1 :     return error;
     414             : 
     415             : }
     416             : 
     417           6 : static unsigned long get_checked_value(struct collection_item *metadata,
     418             :                                        const char *key,
     419             :                                        int *err)
     420             : {
     421             : 
     422           6 :     int error = EOK;
     423           6 :     struct collection_item *item = NULL;
     424             :     unsigned long value;
     425             : 
     426             :     TRACE_FLOW_STRING("get_checked_value", "Entry");
     427             :     TRACE_INFO_STRING("Key", key);
     428             : 
     429           6 :     error = get_config_item(INI_META_SEC_ACCESS,
     430             :                             key,
     431             :                             metadata,
     432             :                             &item);
     433           6 :     if (error) {
     434             :         TRACE_ERROR_NUMBER("Internal collection error.", error);
     435           0 :         *err = error;
     436           0 :         return 0;
     437             :     }
     438             : 
     439             :     /* Entry is supposed to be there so it is an error
     440             :      * is the item is not found.
     441             :      */
     442           6 :     if (item == NULL) {
     443             :         TRACE_ERROR_NUMBER("Expected item is not found.", ENOENT);
     444           0 :         *err = ENOENT;
     445           0 :         return 0;
     446             :     }
     447             : 
     448           6 :     value = get_ulong_config_value(item, 1, -1, &error);
     449           6 :     if ((error) || (value == -1)) {
     450             :         TRACE_ERROR_NUMBER("Conversion failed", EINVAL);
     451           0 :         *err = EINVAL;
     452           0 :         return 0;
     453             :     }
     454             : 
     455           6 :     *err = 0;
     456             : 
     457             :     TRACE_FLOW_NUMBER("get_checked_value Returning", value);
     458           6 :     return value;
     459             : 
     460             : }
     461             : 
     462             : 
     463             : /* Function to check whether the configuration is different */
     464           1 : int config_changed(struct collection_item *metadata,
     465             :                    struct collection_item *saved_metadata,
     466             :                    int *changed)
     467             : {
     468           1 :     int error = EOK;
     469             :     struct collection_item *md[2];
     470             :     unsigned long value[3][2];
     471           1 :     const char *key[] = { INI_META_KEY_MODIFIED,
     472             :                           INI_META_KEY_DEV,
     473             :                           INI_META_KEY_INODE };
     474             :     int i, j;
     475             : 
     476             : 
     477             :     TRACE_FLOW_STRING("config_changed", "Entry");
     478             : 
     479           2 :     if ((!metadata) ||
     480           2 :         (!saved_metadata) ||
     481           1 :         (!changed) ||
     482           2 :         (!col_is_of_class(metadata, COL_CLASS_INI_META)) ||
     483           1 :         (!col_is_of_class(saved_metadata, COL_CLASS_INI_META))) {
     484             :         TRACE_ERROR_NUMBER("Invalid argument.", EINVAL);
     485             :         return EINVAL;
     486             :     }
     487             : 
     488           1 :     md[0] = metadata;
     489           1 :     md[1] = saved_metadata;
     490             : 
     491             :     /* Get three values from each collection and compare them */
     492           4 :     for (i = 0; i < 3; i++) {
     493           6 :         for (j = 0; j < 2; j++) {
     494           6 :             value[i][j] = get_checked_value(md[j], key[i] , &error);
     495           6 :             if (error) {
     496             :                 TRACE_ERROR_NUMBER("Failed to get section.", error);
     497             :                 return error;
     498             :             }
     499             :         }
     500           3 :         if (value[i][0] != value[i][1]) {
     501           0 :             *changed = 1;
     502           0 :             break;
     503             :         }
     504             :     }
     505             : 
     506             :     TRACE_FLOW_STRING("config_changed", "Exit");
     507           1 :     return error;
     508             : 
     509             : }

Generated by: LCOV version 1.10