LCOV - code coverage report
Current view: top level - lib/util - tiniparser.c (source / functions) Hit Total Coverage
Test: coverage report for master 2f515e9b Lines: 4 165 2.4 %
Date: 2024-04-21 15:09:00 Functions: 1 10 10.0 %

          Line data    Source code
       1             : /*
       2             :  * Trivial smb.conf parsing code
       3             :  * iniparser compatibility layer.
       4             :  *
       5             :  * Copyright Jeremy Allison <jra@samba.org> 2014
       6             :  *
       7             :  * Redistribution and use in source and binary forms, with or without
       8             :  * modification, are permitted provided that the following conditions
       9             :  * are met:
      10             :  * 1. Redistributions of source code must retain the above copyright
      11             :  *    notice, and the entire permission notice in its entirety,
      12             :  *    including the disclaimer of warranties.
      13             :  * 2. Redistributions in binary form must reproduce the above copyright
      14             :  *    notice, this list of conditions and the following disclaimer in the
      15             :  *    documentation and/or other materials provided with the distribution.
      16             :  * 3. The name of the author may not be used to endorse or promote
      17             :  *    products derived from this software without specific prior
      18             :  *    written permission.
      19             :  *
      20             :  * ALTERNATIVELY, this product may be distributed under the terms of
      21             :  * the GNU Public License Version 3 or later, in which case the provisions
      22             :  * of the GPL are required INSTEAD OF the above restrictions.  (This clause is
      23             :  * necessary due to a potential bad interaction between the GPL and
      24             :  * the restrictions contained in a BSD-style copyright.)
      25             :  *
      26             :  * THIS SOFTWARE IS PROVIDED `AS IS'' AND ANY EXPRESS OR IMPLIED
      27             :  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
      28             :  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
      29             :  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
      30             :  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
      31             :  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
      32             :  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
      33             :  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
      34             :  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
      35             :  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
      36             :  * OF THE POSSIBILITY OF SUCH DAMAGE.
      37             :  */
      38             : 
      39             : #include <stdio.h>
      40             : #include <stdlib.h>
      41             : #include <stdbool.h>
      42             : #include <ctype.h>
      43             : #include <errno.h>
      44             : #include <string.h>
      45             : #include <stddef.h>
      46             : #include "tini.h"
      47             : #include "tiniparser.h"
      48             : 
      49             : struct tiniparser_entry {
      50             :         struct tiniparser_entry *next_entry;
      51             :         char *key;
      52             :         char *value;
      53             : };
      54             : 
      55             : struct tiniparser_section {
      56             :         struct tiniparser_section *next_section;
      57             :         struct tiniparser_entry *entry_list;
      58             :         char section_name[];
      59             : };
      60             : 
      61             : struct tiniparser_dictionary {
      62             :         struct tiniparser_section *section_list;
      63             : };
      64             : 
      65             : /*
      66             :  * Find a section from a given key.
      67             :  * Also return start of subkey.
      68             :  * Return NULL if section name can't be found,
      69             :  * if no section name given, or no subkey given.
      70             :  */
      71             : 
      72           0 : static struct tiniparser_section *find_section(struct tiniparser_dictionary *d,
      73             :                                         const char *key,
      74             :                                         const char **subkey)
      75             : {
      76           0 :         struct tiniparser_section *curr_section;
      77           0 :         const char *p;
      78           0 :         size_t section_len;
      79             : 
      80           0 :         if (key == NULL) {
      81           0 :                 return NULL;
      82             :         }
      83           0 :         p = strchr(key, ':');
      84           0 :         if (p == NULL) {
      85             :                 /* No section. */
      86           0 :                 return NULL;
      87             :         }
      88             : 
      89           0 :         section_len = p - key;
      90             :         /* Ensure we have at least one character of section name. */
      91           0 :         if (section_len == 0) {
      92           0 :                 return NULL;
      93             :         }
      94             :         /* Ensure we have at least one character of subkey. */
      95           0 :         if (p[1] == '\0') {
      96           0 :                 return NULL;
      97             :         }
      98             : 
      99           0 :         for (curr_section = d->section_list;
     100           0 :                         curr_section;
     101           0 :                         curr_section = curr_section->next_section) {
     102             :                 /*
     103             :                  * Check if the key section matches the
     104             :                  * section name *exactly* (with terminating
     105             :                  * null after section_len characters.
     106             :                  */
     107           0 :                 if ((strncasecmp(key, curr_section->section_name, section_len) == 0) &&
     108           0 :                                 (curr_section->section_name[section_len] == '\0')) {
     109           0 :                         *subkey = p+1;
     110           0 :                         return curr_section;
     111             :                 }
     112             :         }
     113           0 :         return NULL;
     114             : }
     115             : 
     116           0 : static struct tiniparser_entry *find_entry(struct tiniparser_section *section,
     117             :                                         const char *key)
     118             : {
     119           0 :         struct tiniparser_entry *curr_entry;
     120             : 
     121           0 :         for (curr_entry = section->entry_list;
     122           0 :                         curr_entry;
     123           0 :                         curr_entry = curr_entry->next_entry) {
     124           0 :                 if (strcasecmp(key,
     125           0 :                                 curr_entry->key) == 0) {
     126           0 :                         return curr_entry;
     127             :                 }
     128             :         }
     129           0 :         return NULL;
     130             : }
     131             : 
     132           0 : const char *tiniparser_getstring(struct tiniparser_dictionary *d,
     133             :                         const char *key,
     134             :                         const char *default_value)
     135             : {
     136           0 :         struct tiniparser_section *section;
     137           0 :         struct tiniparser_entry *entry;
     138           0 :         const char *subkey;
     139             : 
     140           0 :         section = find_section(d, key, &subkey);
     141           0 :         if (section == NULL) {
     142           0 :                 return default_value;
     143             :         }
     144             : 
     145           0 :         entry = find_entry(section, subkey);
     146           0 :         if (entry == NULL) {
     147           0 :                 return default_value;
     148             :         }
     149             : 
     150           0 :         return entry->value;
     151             : }
     152             : 
     153             : 
     154           0 : bool tiniparser_getboolean(struct tiniparser_dictionary *d,
     155             :                         const char *key,
     156             :                         bool default_value)
     157             : {
     158           0 :         const char *value = tiniparser_getstring(d, key, NULL);
     159             : 
     160           0 :         if (value == NULL) {
     161           0 :                 return default_value;
     162             :         }
     163             : 
     164           0 :         switch(value[0]) {
     165           0 :                 case '1':
     166             :                 case 'T':
     167             :                 case 't':
     168             :                 case 'y':
     169             :                 case 'Y':
     170           0 :                         return true;
     171           0 :                 case '0':
     172             :                 case 'F':
     173             :                 case 'f':
     174             :                 case 'n':
     175             :                 case 'N':
     176           0 :                         return false;
     177           0 :                 default:
     178           0 :                         break;
     179             :         }
     180             : 
     181           0 :         return default_value;
     182             : }
     183             : 
     184           0 : int tiniparser_getint(struct tiniparser_dictionary *d,
     185             :                         const char *key,
     186             :                         int default_value)
     187             : {
     188           0 :         const char *value = tiniparser_getstring(d, key, NULL);
     189             : 
     190           0 :         if (value == NULL) {
     191           0 :                 return default_value;
     192             :         }
     193             : 
     194           0 :         return (int)strtol(value, NULL, 0);
     195             : }
     196             : 
     197           0 : static bool value_parser(const char *key,
     198             :                         const char *value,
     199             :                         void *private_data)
     200             : {
     201           0 :         struct tiniparser_dictionary *d =
     202             :                 (struct tiniparser_dictionary *)private_data;
     203           0 :         struct tiniparser_section *section = d->section_list;
     204           0 :         struct tiniparser_entry *entry = NULL;
     205           0 :         size_t val_len;
     206           0 :         size_t key_len;
     207             : 
     208           0 :         if (section == NULL) {
     209           0 :                 return false;
     210             :         }
     211           0 :         if (key == NULL) {
     212           0 :                 return false;
     213             :         }
     214           0 :         if (value == NULL) {
     215           0 :                 return false;
     216             :         }
     217             : 
     218           0 :         key_len = strlen(key) + 1;
     219           0 :         val_len = strlen(value) + 1;
     220             : 
     221           0 :         entry = find_entry(section, key);
     222           0 :         if (entry) {
     223             :                 /* Replace current value. */
     224           0 :                 char *new_val = malloc(val_len);
     225           0 :                 if (new_val == NULL) {
     226           0 :                         return false;
     227             :                 }
     228           0 :                 memcpy(new_val, value, val_len);
     229           0 :                 free(entry->value);
     230           0 :                 entry->value = new_val;
     231           0 :                 return true;
     232             :         }
     233             : 
     234             :         /* Create a new entry. */
     235           0 :         entry = malloc(sizeof(struct tiniparser_entry));
     236           0 :         if (entry == NULL) {
     237           0 :                 return false;
     238             :         }
     239           0 :         entry->key = malloc(key_len);
     240           0 :         if (entry->key == NULL) {
     241           0 :                 free(entry);
     242           0 :                 return false;
     243             :         }
     244           0 :         memcpy(entry->key, key, key_len);
     245             : 
     246           0 :         entry->value = malloc(val_len);
     247           0 :         if (entry->value == NULL) {
     248           0 :                 free(entry->key);
     249           0 :                 free(entry);
     250           0 :                 return false;
     251             :         }
     252           0 :         memcpy(entry->value, value, val_len);
     253             : 
     254           0 :         entry->next_entry = section->entry_list;
     255           0 :         section->entry_list = entry;
     256           0 :         return true;
     257             : }
     258             : 
     259           0 : static bool section_parser(const char *section_name,
     260             :                         void *private_data)
     261             : {
     262           0 :         struct tiniparser_section **pp_section;
     263           0 :         struct tiniparser_section *new_section;
     264           0 :         struct tiniparser_dictionary *d =
     265             :                 (struct tiniparser_dictionary *)private_data;
     266           0 :         size_t section_name_len;
     267             : 
     268           0 :         if (section_name == NULL) {
     269           0 :                 return false;
     270             :         }
     271             : 
     272             :         /* Section names can't contain ':' */
     273           0 :         if (strchr(section_name, ':') != NULL) {
     274           0 :                 return false;
     275             :         }
     276             : 
     277             :         /* Do we already have this section ? */
     278           0 :         for (pp_section = &d->section_list;
     279           0 :                         *pp_section;
     280           0 :                         pp_section = &(*pp_section)->next_section) {
     281           0 :                 if (strcasecmp(section_name,
     282           0 :                                 (*pp_section)->section_name) == 0) {
     283             :                         /*
     284             :                          * Move to the front of the list for
     285             :                          * value_parser() to find it.
     286             :                          */
     287             : 
     288             :                         /* First save current entry. */
     289           0 :                         struct tiniparser_section *curr_section = *pp_section;
     290             : 
     291             :                         /* Now unlink current entry from list. */
     292           0 :                         *pp_section = curr_section->next_section;
     293             : 
     294             :                         /* Make current entry next point to whole list. */
     295           0 :                         curr_section->next_section = d->section_list;
     296             : 
     297             :                         /* And replace list with current entry at start. */
     298           0 :                         d->section_list = curr_section;
     299             : 
     300           0 :                         return true;
     301             :                 }
     302             :         }
     303             : 
     304           0 :         section_name_len = strlen(section_name) + 1;
     305             : 
     306             :         /* Create new section. */
     307           0 :         new_section = malloc(
     308             :                 offsetof(struct tiniparser_section, section_name) +
     309             :                 section_name_len);
     310           0 :         if (new_section == NULL) {
     311           0 :                 return false;
     312             :         }
     313             : 
     314           0 :         memcpy(new_section->section_name, section_name, section_name_len);
     315             : 
     316           0 :         new_section->entry_list = NULL;
     317             : 
     318             :         /* Add it to the head of the singly linked list. */
     319           0 :         new_section->next_section = d->section_list;
     320           0 :         d->section_list = new_section;
     321           0 :         return true;
     322             : }
     323             : 
     324           0 : struct tiniparser_dictionary *tiniparser_load_stream(FILE *fp)
     325             : {
     326           0 :         bool ret;
     327           0 :         struct tiniparser_dictionary *d = NULL;
     328             : 
     329           0 :         d = malloc(sizeof(struct tiniparser_dictionary));
     330           0 :         if (d == NULL) {
     331           0 :                 return NULL;
     332             :         }
     333           0 :         d->section_list = NULL;
     334             : 
     335           0 :         ret = tini_parse(fp,
     336             :                         false,
     337             :                         section_parser,
     338             :                         value_parser,
     339             :                         d);
     340           0 :         if (ret == false) {
     341           0 :                 tiniparser_freedict(d);
     342           0 :                 d = NULL;
     343             :         }
     344           0 :         return d;
     345             : }
     346             : 
     347         468 : struct tiniparser_dictionary *tiniparser_load(const char *filename)
     348             : {
     349           0 :         struct tiniparser_dictionary *d;
     350         468 :         FILE *fp = fopen(filename, "r");
     351             : 
     352         468 :         if (fp == NULL) {
     353         468 :                 return NULL;
     354             :         }
     355             : 
     356           0 :         d = tiniparser_load_stream(fp);
     357             : 
     358           0 :         fclose(fp);
     359             : 
     360           0 :         return d;
     361             : }
     362             : 
     363           0 : void tiniparser_freedict(struct tiniparser_dictionary *d)
     364             : {
     365           0 :         struct tiniparser_section *curr_section, *next_section;
     366             : 
     367           0 :         if (d == NULL) {
     368           0 :                 return;
     369             :         }
     370             : 
     371           0 :         for (curr_section = d->section_list;
     372           0 :                         curr_section;
     373           0 :                         curr_section = next_section) {
     374           0 :                 struct tiniparser_entry *curr_entry, *next_entry;
     375             : 
     376           0 :                 next_section = curr_section->next_section;
     377             : 
     378           0 :                 for (curr_entry = curr_section->entry_list;
     379           0 :                                 curr_entry;
     380           0 :                                 curr_entry = next_entry) {
     381           0 :                         next_entry = curr_entry->next_entry;
     382             : 
     383           0 :                         free(curr_entry->key);
     384           0 :                         free(curr_entry->value);
     385           0 :                         free(curr_entry);
     386             :                 }
     387           0 :                 free(curr_section);
     388             :         }
     389           0 :         free(d);
     390             : }

Generated by: LCOV version 1.14