LTP GCOV extension - code coverage report
Current view: directory - trunk/src - conf.c
Test: lcov.info
Date: 2007-05-09 Instrumented lines: 176
Code covered: 52.3 % Executed lines: 92

       1                 : /*
       2                 :  * conf.c - Configuration text file parsing definition
       3                 :  * $Id: conf.c 1810 2006-10-26 19:49:51Z remi $
       4                 :  */
       5                 : 
       6                 : /***********************************************************************
       7                 :  *  Copyright © 2004-2006 Rémi Denis-Courmont.                         *
       8                 :  *  This program is free software; you can redistribute and/or modify  *
       9                 :  *  it under the terms of the GNU General Public License as published  *
      10                 :  *  by the Free Software Foundation; version 2 of the license.         *
      11                 :  *                                                                     *
      12                 :  *  This program is distributed in the hope that it will be useful,    *
      13                 :  *  but WITHOUT ANY WARRANTY; without even the implied warranty of     *
      14                 :  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.               *
      15                 :  *  See the GNU General Public License for more details.               *
      16                 :  *                                                                     *
      17                 :  *  You should have received a copy of the GNU General Public License  *
      18                 :  *  along with this program; if not, you can get it from:              *
      19                 :  *  http://www.gnu.org/copyleft/gpl.html                               *
      20                 :  ***********************************************************************/
      21                 : 
      22                 : #ifdef HAVE_CONFIG_H
      23                 : # include <config.h>
      24                 : #endif
      25                 : 
      26                 : #include <gettext.h>
      27                 : #include <assert.h>
      28                 : 
      29                 : #include <stdio.h>
      30                 : #include <stdlib.h> // malloc(), free()
      31                 : #include <stdarg.h>
      32                 : #include <inttypes.h>
      33                 : #include <string.h>
      34                 : #include <stdbool.h>
      35                 : 
      36                 : #include <errno.h>
      37                 : #include <syslog.h>
      38                 : 
      39                 : #include <sys/types.h>
      40                 : #include <sys/socket.h> // AF_INET, SOCK_DGRAM
      41                 : #include <netinet/in.h>
      42                 : #include <netdb.h>
      43                 : #include <libteredo/teredo.h>
      44                 : 
      45                 : #include "miredo.h"
      46                 : #include "conf.h"
      47                 : 
      48                 : struct setting
      49                 : {
      50                 :         char *name;
      51                 :         char *value;
      52                 :         unsigned line;
      53                 :         struct setting *next;
      54                 : };
      55                 : 
      56                 : 
      57                 : struct miredo_conf
      58                 : {
      59                 :         struct setting *head, *tail;
      60                 :         miredo_conf_logger logger;
      61                 :         void *logger_data;
      62                 : };
      63                 : 
      64                 : 
      65                 : miredo_conf *miredo_conf_create (miredo_conf_logger logger, void *opaque)
      66               3 : {
      67               3 :         miredo_conf *conf = (miredo_conf *)malloc (sizeof (*conf));
      68               3 :         if (conf == NULL)
      69               0 :                 return NULL;
      70                 : 
      71               3 :         conf->head = conf->tail = NULL;
      72               3 :         conf->logger = logger;
      73               3 :         conf->logger_data = opaque;
      74               3 :         return conf;
      75                 : }
      76                 : 
      77                 : 
      78                 : void miredo_conf_destroy (miredo_conf *conf)
      79               3 : {
      80               3 :         assert (conf != NULL);
      81               3 :         miredo_conf_clear (conf, 0);
      82               3 :         free (conf);
      83               3 : }
      84                 : 
      85                 : 
      86                 : static
      87                 : #ifdef __GNUC__
      88                 : __attribute__ ((format (printf, 2, 3)))
      89                 : #endif
      90                 : void
      91                 : LogError (miredo_conf *conf, const char *fmt, ...)
      92               0 : {
      93               0 :         assert (conf != NULL);
      94               0 :         assert (fmt != NULL);
      95                 : 
      96               0 :         if (conf->logger == NULL)
      97               0 :                 return;
      98                 : 
      99                 :         va_list ap;
     100                 : 
     101               0 :         va_start (ap, fmt);
     102               0 :         conf->logger (conf->logger_data, true, fmt, ap);
     103               0 :         va_end (ap);
     104                 : }
     105                 : 
     106                 : 
     107                 : static void
     108                 : #ifdef __GNUC__
     109                 : __attribute__ ((format (printf, 2, 3)))
     110                 : #endif
     111                 : LogWarning (miredo_conf *conf, const char *fmt, ...)
     112               0 : {
     113               0 :         assert (conf != NULL);
     114               0 :         assert (fmt != NULL);
     115                 : 
     116               0 :         if (conf->logger == NULL)
     117               0 :                 return;
     118                 : 
     119                 :         va_list ap;
     120                 : 
     121               0 :         va_start (ap, fmt);
     122               0 :         conf->logger (conf->logger_data, false, fmt, ap);
     123               0 :         va_end (ap);
     124                 : }
     125                 : 
     126                 : 
     127                 : void miredo_conf_clear (miredo_conf *conf, int show)
     128               6 : {
     129                 :         /* lock here */
     130               6 :         struct setting *ptr = conf->head;
     131                 : 
     132               6 :         conf->head = NULL;
     133                 :         /* unlock here */
     134                 : 
     135              12 :         while (ptr != NULL)
     136                 :         {
     137               0 :                 struct setting *buf = ptr->next;
     138               0 :                 if (show > 0)
     139                 :                 {
     140               0 :                         LogWarning (conf, _("Superfluous directive %s at line %u"),
     141                 :                                     ptr->name, ptr->line);
     142               0 :                         show--;
     143                 :                 }
     144               0 :                 free (ptr->name);
     145               0 :                 free (ptr->value);
     146               0 :                 free (ptr);
     147               0 :                 ptr = buf;
     148                 :         }
     149               6 : }
     150                 : 
     151                 : 
     152                 : /**
     153                 :  * Adds a setting.
     154                 :  * @return false if memory is missing.
     155                 :  */
     156                 : static bool
     157                 : miredo_conf_set (miredo_conf *conf, const char *name, const char *value,
     158                 :                  unsigned line)
     159               6 : {
     160               6 :         assert (conf != NULL);
     161               6 :         assert (name != NULL);
     162               6 :         assert (value != NULL);
     163                 : 
     164                 :         struct setting *parm =
     165               6 :                 (struct setting *)malloc (sizeof (struct setting));
     166                 : 
     167               6 :         if (parm != NULL)
     168                 :         {
     169               6 :                 parm->name = strdup (name);
     170               6 :                 if (parm->name != NULL)
     171                 :                 {
     172               6 :                         parm->value = strdup (value);
     173               6 :                         if (parm->value != NULL)
     174                 :                         {
     175               6 :                                 parm->line = line;
     176               6 :                                 parm->next = NULL;
     177                 : 
     178                 :                                 /* lock here */
     179               6 :                                 if (conf->head == NULL)
     180               3 :                                         conf->head = parm;
     181                 :                                 else
     182                 :                                 {
     183               3 :                                         assert (conf->tail != NULL);
     184               3 :                                         conf->tail->next = parm;
     185                 :                                 }
     186               6 :                                 conf->tail = parm;
     187                 :                                 /* unlock here */
     188                 : 
     189               6 :                                 return true;
     190                 :                         }
     191               0 :                         free (parm->name);
     192                 :                 }
     193               0 :                 free (parm);
     194                 :         }
     195                 : 
     196               0 :         LogError (conf, _("Error (%s): %s"), "strdup", strerror (errno));
     197               0 :         return false;
     198                 : }
     199                 : 
     200                 : 
     201                 : /*
     202                 :  * Looks up a setting by name.
     203                 :  * @return NULL if not found.
     204                 :  * Otherwise, return value must be free()d by caller.
     205                 :  */
     206                 : char *miredo_conf_get (miredo_conf *conf, const char *name, unsigned *line)
     207              21 : {
     208              45 :         for (struct setting *p = conf->head, *prev = NULL; p != NULL; p = p->next)
     209                 :         {
     210              30 :                 if (strcasecmp (p->name, name) == 0)
     211                 :                 {
     212               6 :                         char *buf = p->value;
     213                 : 
     214               6 :                         if (line != NULL)
     215               3 :                                 *line = p->line;
     216                 : 
     217               6 :                         if (prev != NULL)
     218               3 :                                 prev->next = p->next;
     219                 :                         else
     220               3 :                                 conf->head = p->next;
     221                 : 
     222               6 :                         free (p->name);
     223               6 :                         free (p);
     224               6 :                         return buf;
     225                 :                 }
     226              24 :                 prev = p;
     227                 :         }
     228                 : 
     229              15 :         return NULL;
     230                 : }
     231                 : 
     232                 : 
     233                 : static bool miredo_conf_read_FILE (miredo_conf *conf, FILE *stream)
     234               3 : {
     235                 :         char lbuf[1056];
     236               3 :         unsigned line = 0;
     237                 : 
     238             105 :         while (fgets (lbuf, sizeof (lbuf), stream) != NULL)
     239                 :         {
     240              99 :                 size_t len = strlen (lbuf) - 1;
     241              99 :                 line++;
     242                 : 
     243              99 :                 if (lbuf[len] != '\n')
     244                 :                 {
     245               0 :                         while (fgetc (stream) != '\n')
     246               0 :                                 if (feof (stream) || ferror (stream))
     247                 :                                         break;
     248                 : 
     249               0 :                         LogWarning (conf, _("Skipped overly long line %u"), line);
     250               0 :                         continue;
     251                 :                 }
     252                 : 
     253              99 :                 lbuf[len] = '\0';
     254                 :                 char nbuf[32], vbuf[1024];
     255                 : 
     256              99 :                 switch (sscanf (lbuf, " %31s %1023s", nbuf, vbuf))
     257                 :                 {
     258                 :                         case 2:
     259              75 :                                 if ((*nbuf != '#') // comment
     260                 :                                  && !miredo_conf_set (conf, nbuf, vbuf, line))
     261               0 :                                         return false;
     262              75 :                                 break;
     263                 : 
     264                 :                         case 1:
     265               3 :                                 if (*nbuf != '#')
     266               0 :                                         LogWarning (conf, _("Ignoring line %u: %s"),
     267                 :                                                     line, nbuf);
     268                 :                                 break;
     269                 :                 }
     270                 :         }
     271                 : 
     272               3 :         if (ferror (stream))
     273                 :         {
     274               0 :                 LogError (conf, _("Error reading configuration file: %s"),
     275                 :                           strerror (errno));
     276               0 :                 return false;
     277                 :         }
     278               3 :         return true;
     279                 : }
     280                 : 
     281                 : 
     282                 : /* Parses a file.
     283                 :  *
     284                 :  * @return false on I/O error, true on success.
     285                 :  */
     286                 : bool miredo_conf_read_file (miredo_conf *conf, const char *path)
     287               3 : {
     288               3 :         assert (path != NULL);
     289                 : 
     290               3 :         FILE *stream = fopen (path, "r");
     291               3 :         if (stream != NULL)
     292                 :         {
     293               3 :                 bool ret = miredo_conf_read_FILE (conf, stream);
     294               3 :                 fclose (stream);
     295               3 :                 return ret;
     296                 :         }
     297                 : 
     298               0 :         LogError (conf, _("Error opening configuration file %s: %s"), path,
     299                 :                   strerror (errno));
     300               0 :         return false;
     301                 : }
     302                 : 
     303                 : 
     304                 : /**
     305                 :  * Looks up an unsigned 16-bits integer. Returns false if the
     306                 :  * setting was found but incorrectly formatted.
     307                 :  *
     308                 :  * If the setting was not found value, returns true and leave
     309                 :  * *value unchanged.
     310                 :  */
     311                 : bool miredo_conf_get_int16 (miredo_conf *conf, const char *name,
     312                 :                             uint16_t *value, unsigned *line)
     313               3 : {
     314               3 :         char *val = miredo_conf_get (conf, name, line);
     315                 : 
     316               3 :         if (val == NULL)
     317               3 :                 return true;
     318                 : 
     319                 :         char *end;
     320                 :         unsigned long l;
     321                 : 
     322               0 :         l = strtoul (val, &end, 0);
     323                 :         
     324               0 :         if ((*end) || (l > 65535))
     325                 :         {
     326               0 :                 LogError (conf, _("Invalid integer value \"%s\" for %s: %s"),
     327                 :                           val, name, strerror (errno));
     328               0 :                 free (val);
     329               0 :                 return false;
     330                 :         }
     331               0 :         *value = (uint16_t)l;
     332               0 :         free (val);
     333               0 :         return true;
     334                 : }
     335                 : 
     336                 : 
     337                 : #if 0
     338                 : /* This is supposedly bad for DSO (but we are not a DSO atm) */
     339                 : static const char *true_strings[] = { "yes", "true", "on", "enabled", NULL };
     340                 : static const char *false_strings[] =
     341                 :         { "no", "false", "off", "disabled", NULL };
     342                 : 
     343                 : bool miredo_conf_get_bool (miredo_conf *conf, const char *name,
     344                 :                            bool *value, unsigned *line)
     345                 : {
     346                 :         char *val = miredo_conf_get (conf, name, line);
     347                 : 
     348                 :         if (val == NULL)
     349                 :                 return true;
     350                 :         else
     351                 :         {
     352                 :                 // check if value is a number
     353                 :                 long l;
     354                 :                 char *end;
     355                 : 
     356                 :                 l = strtol (val, &end, 0);
     357                 : 
     358                 :                 if (*end == '\0') // success
     359                 :                 {
     360                 :                         *value = (l != 0);
     361                 :                         free (val);
     362                 :                         return true;
     363                 :                 }
     364                 :         }
     365                 : 
     366                 :         for (const char **ptr = true_strings; *ptr != NULL; ptr++)
     367                 :                 if (!strcasecmp (val, *ptr))
     368                 :                 {
     369                 :                         *value = true;
     370                 :                         free (val);
     371                 :                         return true;
     372                 :                 }
     373                 : 
     374                 :         for (const char **ptr = false_strings; *ptr != NULL; ptr++)
     375                 :                 if (!strcasecmp (val, *ptr))
     376                 :                 {
     377                 :                         *value = false;
     378                 :                         free (val);
     379                 :                         return true;
     380                 :                 }
     381                 : 
     382                 :         LogError (conf, _("Invalid boolean value \"%s\" for %s"), val, name);
     383                 :         free (val);
     384                 :         return false;
     385                 : }
     386                 : #endif
     387                 : 
     388                 : /* Utilities function */
     389                 : 
     390                 : /**
     391                 :  * Looks up an IPv4 address (network byte order) associated with hostname.
     392                 :  */
     393                 : int GetIPv4ByName (const char *hostname, uint32_t *ipv4)
     394               3 : {
     395                 :         struct addrinfo help =
     396                 :         {
     397                 :                 .ai_family = AF_INET,
     398                 :                 .ai_socktype = SOCK_DGRAM,
     399                 :                 .ai_protocol = IPPROTO_UDP
     400               3 :         }, *res;
     401                 : 
     402               3 :         int check = getaddrinfo (hostname, NULL, &help, &res);
     403               3 :         if (check)
     404               0 :                 return check;
     405                 : 
     406               3 :         *ipv4 = ((const struct sockaddr_in *)res->ai_addr)->sin_addr.s_addr;
     407               3 :         freeaddrinfo (res);
     408               3 :         return 0;
     409                 : }
     410                 : 
     411                 : 
     412                 : bool miredo_conf_parse_IPv4 (miredo_conf *conf, const char *name,
     413                 :                              uint32_t *ipv4)
     414               9 : {
     415                 :         unsigned line;
     416               9 :         char *val = miredo_conf_get (conf, name, &line);
     417                 : 
     418               9 :         if (val == NULL)
     419               6 :                 return true;
     420                 : 
     421               3 :         int check = GetIPv4ByName (val, ipv4);
     422                 : 
     423               3 :         if (check)
     424                 :         {
     425               0 :                 LogError (conf, _("Invalid hostname \"%s\" at line %u: %s"),
     426                 :                           val, line, gai_strerror (check));
     427               0 :                 free (val);
     428               0 :                 return false;
     429                 :         }
     430                 : 
     431               3 :         free (val);
     432               3 :         return true;
     433                 : }
     434                 : 
     435                 : 
     436                 : bool miredo_conf_parse_IPv6 (miredo_conf *conf, const char *name,
     437                 :                              struct in6_addr *value)
     438               0 : {
     439                 :         unsigned line;
     440               0 :         char *val = miredo_conf_get (conf, name, &line);
     441                 : 
     442               0 :         if (val == NULL)
     443               0 :                 return true;
     444                 : 
     445                 :         struct addrinfo help =
     446                 :         {
     447                 :                 .ai_family = AF_INET6,
     448                 :                 .ai_socktype = SOCK_DGRAM,
     449                 :                 .ai_protocol = IPPROTO_UDP
     450               0 :         }, *res;
     451                 : 
     452               0 :         int check = getaddrinfo (val, NULL, &help, &res);
     453                 : 
     454               0 :         if (check)
     455                 :         {
     456               0 :                 LogError (conf, _("Invalid hostname \"%s\" at line %u: %s"),
     457                 :                           val, line, gai_strerror (check));
     458               0 :                 free (val);
     459               0 :                 return false;
     460                 :         }
     461                 : 
     462               0 :         memcpy (value, &((const struct sockaddr_in6*)(res->ai_addr))->sin6_addr,
     463                 :                 sizeof (struct in6_addr));
     464                 : 
     465               0 :         freeaddrinfo (res);
     466               0 :         free (val);
     467               0 :         return true;
     468                 : }
     469                 : 
     470                 : 
     471                 : bool miredo_conf_parse_teredo_prefix (miredo_conf *conf, const char *name,
     472                 :                                       uint32_t *value)
     473               0 : {
     474                 :         union teredo_addr addr;
     475               0 :         memset (&addr, 0, sizeof (addr));
     476               0 :         addr.teredo.prefix = *value;
     477                 : 
     478               0 :         if (miredo_conf_parse_IPv6 (conf, name, &addr.ip6))
     479                 :         {
     480               0 :                 if (!is_valid_teredo_prefix (addr.teredo.prefix))
     481                 :                 {
     482               0 :                         LogError (conf, _("Invalid Teredo IPv6 prefix: %x::/32"),
     483                 :                                   addr.teredo.prefix);
     484               0 :                         return false;
     485                 :                 }
     486                 : 
     487               0 :                 *value = addr.teredo.prefix;
     488               0 :                 return true;
     489                 :         }
     490               0 :         return false;
     491                 : }
     492                 : 
     493                 : 
     494                 : static const struct miredo_conf_syslog_facility
     495                 : {
     496                 :         const char *str;
     497                 :         int facility;
     498                 : } facilities[] =
     499                 : {
     500                 : #ifdef LOG_AUTH
     501                 :         { "auth",     LOG_AUTH },
     502                 : #endif
     503                 : #ifdef LOG_AUTHPRIV
     504                 :         { "authpriv", LOG_AUTHPRIV },
     505                 : #endif
     506                 : #ifdef LOG_CRON
     507                 :         { "cron",     LOG_CRON },
     508                 : #endif
     509                 : #ifdef LOG_DAEMON
     510                 :         { "daemon",   LOG_DAEMON },
     511                 : #endif
     512                 : #ifdef LOG_FTP
     513                 :         { "ftp",      LOG_FTP },
     514                 : #endif
     515                 : #ifdef LOG_KERN
     516                 :         { "kern",     LOG_KERN },
     517                 : #endif
     518                 :         { "local0",   LOG_LOCAL0 },
     519                 :         { "local1",   LOG_LOCAL1 },
     520                 :         { "local2",   LOG_LOCAL2 },
     521                 :         { "local3",   LOG_LOCAL3 },
     522                 :         { "local4",   LOG_LOCAL4 },
     523                 :         { "local5",   LOG_LOCAL5 },
     524                 :         { "local6",   LOG_LOCAL6 },
     525                 :         { "local7",   LOG_LOCAL7 },
     526                 : #ifdef LOG_LPR
     527                 :         { "lpr",      LOG_LPR },
     528                 : #endif
     529                 : #ifdef LOG_MAIL
     530                 :         { "mail",     LOG_MAIL },
     531                 : #endif
     532                 : #ifdef LOG_NEWS
     533                 :         { "news",     LOG_NEWS },
     534                 : #endif
     535                 : #ifdef LOG_SYSLOG
     536                 :         { "syslog",   LOG_SYSLOG },
     537                 : #endif
     538                 :         { "user",     LOG_USER },
     539                 : #ifdef LOG_UUCP
     540                 :         { "uucp",     LOG_UUCP },
     541                 : #endif
     542                 :         { NULL,         0 }
     543                 : };
     544                 : 
     545                 : 
     546                 : bool miredo_conf_parse_syslog_facility (miredo_conf *conf, const char *name,
     547                 :                                         int *facility)
     548               3 : {
     549                 :         unsigned line;
     550               3 :         char *str = miredo_conf_get (conf, name, &line);
     551                 : 
     552               3 :         if (str == NULL)
     553               3 :                 return true;
     554                 : 
     555               0 :         for (const struct miredo_conf_syslog_facility *ptr = facilities;
     556               0 :              ptr->str != NULL; ptr++)
     557                 :         {
     558               0 :                 if (!strcasecmp (str, ptr->str))
     559                 :                 {
     560               0 :                         *facility = ptr->facility;
     561               0 :                         free (str);
     562               0 :                         return true;
     563                 :                 }
     564                 :         }
     565                 : 
     566               0 :         LogError (conf, _("Unknown syslog facility \"%s\" at line %u"), str,
     567                 :                   line);
     568               0 :         free (str);
     569               0 :         return false;
     570                 : }

Generated by: LTP GCOV extension version 1.5