"Fossies" - the Fresh Open Source Software Archive

Member "inadyn-2.8.1/src/conf.c" (31 Jan 2021, 18413 Bytes) of package /linux/misc/dns/inadyn-2.8.1.tar.xz:


As a special service "Fossies" has tried to format the requested source page into HTML format using (guessed) C and C++ source code syntax highlighting (style: standard) with prefixed line numbers and code folding option. Alternatively you can here view or download the uninterpreted source code file. For more information about "conf.c" see the Fossies "Dox" file reference documentation and the latest Fossies "Diffs" side-by-side code changes report: 2.8_vs_2.8.1.

    1 /* libConfuse interface to parse inadyn.conf v2 format
    2  *
    3  * Copyright (C) 2014-2020  Joachim Nilsson <troglobit@gmail.com>
    4  *
    5  * Permission to use, copy, modify, and/or distribute this software for any
    6  * purpose with or without fee is hereby granted, provided that the above
    7  * copyright notice and this permission notice appear in all copies.
    8  *
    9  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
   10  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
   11  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
   12  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
   13  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
   14  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
   15  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
   16  */
   17 
   18 #include <errno.h>
   19 #include <string.h>
   20 #include <confuse.h>
   21 
   22 #include "cache.h"
   23 #include "ddns.h"
   24 #include "ssl.h"
   25 
   26 /*
   27  * period        = 600
   28  * forced-update = 604800
   29  *
   30  * provider default@freedns.afraid.org
   31  * {
   32  *   wildcard = false
   33  *   username = example
   34  *   password = secret
   35  *   hostname = { "example.homenet.org", "example.afraid.org" }
   36  * }
   37  *
   38  * provider default@dyndns.org
   39  * {
   40  *   ssl      = true
   41  *   username = admin
   42  *   password = supersecret
   43  *   hostname = example.dyndns.org
   44  * }
   45  */
   46 static LIST_HEAD(head, di) info_list = LIST_HEAD_INITIALIZER(info_list);
   47 
   48 static void conf_errfunc(cfg_t *cfg, const char *format, va_list args)
   49 {
   50     char fmt[80];
   51 
   52     if (cfg && cfg->filename && cfg->line)
   53         snprintf(fmt, sizeof(fmt), "%s:%d: %s", cfg->filename, cfg->line, format);
   54     else if (cfg && cfg->filename)
   55         snprintf(fmt, sizeof(fmt), "%s: %s", cfg->filename, format);
   56     else
   57         snprintf(fmt, sizeof(fmt), "%s", format);
   58 
   59     vlogit(LOG_ERR, fmt, args);
   60 }
   61 
   62 /*
   63  * Convert deprecated 'alias' setting to new 'hostname',
   64  * same functionality with new name.
   65  */
   66 static int deprecate_alias(cfg_t *cfg)
   67 {
   68     size_t i;
   69     cfg_opt_t *alias, *hostname;
   70 
   71     alias = cfg_getopt(cfg, "alias");
   72     if (!alias || cfg_opt_size(alias) <= 0)
   73         return 0;
   74 
   75     hostname = cfg_getopt(cfg, "hostname");
   76     if (cfg_opt_size(hostname) > 0) {
   77         cfg_error(cfg, "Both 'hostname' and 'alias' set, cannot convert deprecated 'alias' to 'hostname'");
   78         return -1;
   79     }
   80 
   81     cfg_error(cfg, "converting 'alias' to 'hostname'.");
   82     for (i = 0; i < cfg_opt_size(alias); i++)
   83         cfg_opt_setnstr(hostname, cfg_opt_getnstr(alias, i), i);
   84 
   85     cfg_free_value(alias);
   86 
   87     return 0;
   88 }
   89 
   90 static int validate_period(cfg_t *cfg, cfg_opt_t *opt)
   91 {
   92     int val = cfg_getint(cfg, opt->name);
   93 
   94     if (val < DDNS_MIN_PERIOD)
   95         cfg_setint(cfg, opt->name, DDNS_MIN_PERIOD);
   96     if (val > DDNS_MAX_PERIOD)
   97         cfg_setint(cfg, opt->name, DDNS_MAX_PERIOD);
   98 
   99     return 0;
  100 }
  101 
  102 static int validate_hostname(cfg_t *cfg, const char *provider, cfg_opt_t *hostname)
  103 {
  104     size_t i;
  105 
  106     if (!hostname) {
  107         cfg_error(cfg, "DDNS hostname setting is missing in provider %s", provider);
  108         return -1;
  109     }
  110 
  111     if (!cfg_opt_size(hostname)) {
  112         cfg_error(cfg, "No hostnames listed in DDNS provider %s", provider);
  113         return -1;
  114     }
  115 
  116     for (i = 0; i < cfg_opt_size(hostname); i++) {
  117         char *name = cfg_opt_getnstr(hostname, i);
  118         ddns_info_t info;
  119 
  120         if (sizeof(info.alias[0].name) < strlen(name)) {
  121             cfg_error(cfg, "Too long DDNS hostname (%s) in provider %s", name, provider);
  122             return -1;
  123         }
  124     }
  125 
  126     if (i >= DDNS_MAX_ALIAS_NUMBER) {
  127         cfg_error(cfg, "Too many hostname aliases, MAX %d supported!", DDNS_MAX_ALIAS_NUMBER);
  128         return -1;
  129     }
  130 
  131     return 0;
  132 }
  133 
  134 /* No need to validate username/password for custom providers */
  135 static int validate_common(cfg_t *cfg, const char *provider, int custom)
  136 {
  137     ddns_system_t *ds;
  138 
  139     ds = plugin_find(provider, 0);
  140     if (!ds) {
  141         ds = plugin_find(provider, 1);
  142         if (!ds) {
  143             cfg_error(cfg, "Invalid DDNS provider %s", provider);
  144             return -1;
  145         }
  146     }
  147 
  148     if (!custom) {
  149         if (!ds->nousername && !cfg_getstr(cfg, "username")) {
  150             cfg_error(cfg, "Missing username setting for DDNS provider %s", provider);
  151             return -1;
  152         }
  153 
  154         if (!cfg_getstr(cfg, "password")) {
  155             cfg_error(cfg, "Missing password setting for DDNS provider %s", provider);
  156             return -1;
  157         }
  158     }
  159 
  160     return deprecate_alias(cfg) ||
  161         validate_hostname(cfg, provider, cfg_getopt(cfg, "hostname"));
  162 }
  163 
  164 static int validate_provider(cfg_t *cfg, cfg_opt_t *opt)
  165 {
  166     const char *provider;
  167 
  168     cfg = cfg_opt_getnsec(opt, cfg_opt_size(opt) - 1);
  169     provider = cfg_title(cfg);
  170 
  171     if (!provider) {
  172         cfg_error(cfg, "Missing DDNS provider name");
  173         return -1;
  174     }
  175 
  176     return validate_common(cfg, provider, 0);
  177 }
  178 
  179 static int validate_custom(cfg_t *cfg, cfg_opt_t *opt)
  180 {
  181     cfg = cfg_opt_getnsec(opt, cfg_opt_size(opt) - 1);
  182     if (!cfg)
  183         return -1;
  184 
  185     if (!cfg_getstr(cfg, "ddns-server")) {
  186         cfg_error(cfg, "Missing 'ddns-server' for custom DDNS provider");
  187         return -1;
  188     }
  189 
  190     return validate_common(cfg, "custom", 1);
  191 }
  192 
  193 /* server:port => server:80 if port is not given */
  194 static int getserver(const char *server, ddns_name_t *name)
  195 {
  196     char *str, *ptr;
  197 
  198     if (strlen(server) > sizeof(name->name))
  199         return 1;
  200 
  201     str = strdup(server);
  202     if (!str)
  203         return 1;
  204 
  205     ptr = strchr(str, ':');
  206     if (ptr) {
  207         *ptr++ = 0;
  208         name->port = atonum(ptr);
  209         if (-1 == name->port)
  210             name->port = HTTP_DEFAULT_PORT;
  211     } else {
  212         name->port = HTTP_DEFAULT_PORT;
  213     }
  214 
  215     strlcpy(name->name, str, sizeof(name->name));
  216     free(str);
  217 
  218     return 0;
  219 }
  220 
  221 static int cfg_getserver(cfg_t *cfg, char *server, ddns_name_t *name)
  222 {
  223     const char *str;
  224 
  225     str = cfg_getstr(cfg, server);
  226     if (!str)
  227         return 1;
  228 
  229     return getserver(str, name);
  230 }
  231 
  232 #if 0
  233 /* TODO: Move to a separate file */
  234 #define string_startswith(string, prefix) strncasecmp(string, prefix, strlen(prefix)) == 0
  235 
  236 static int parseproxy(const char *proxy, tcp_proxy_type_t *type, ddns_name_t *name)
  237 {
  238     int ret = 0;
  239     char *tmp, *str, *host, *protocol;
  240     int len;
  241 
  242     tmp = str = strdup(proxy);
  243 
  244     do {
  245         tmp = strstr(str, "://");
  246         if (tmp) {
  247             host = tmp + 3;
  248             if (string_startswith(str, "socks5h"))
  249                 *type = PROXY_SOCKS5_HOSTNAME;
  250             else if (string_startswith(str, "socks5"))
  251                 *type = PROXY_SOCKS5;
  252             else if (string_startswith(str, "socks4a"))
  253                 *type = PROXY_SOCKS4A;
  254             else if (string_startswith(str, "socks4") || string_startswith(str, "socks"))
  255                 *type = PROXY_SOCKS4;
  256             else {
  257                 len = tmp - str;
  258                 protocol = malloc(len + 2);
  259                 strncpy(protocol, str, len);
  260                 protocol[len + 1] = 0;
  261                 logit(LOG_ERR, "Unsupported proxy protocol '%s'.", protocol);
  262                 free(protocol);
  263                 ret = 1;
  264                 break;
  265             }
  266 
  267             tmp = strchr(host, ':');
  268             if (tmp) {
  269                 *tmp++ = 0;
  270                 name->port = atonum(tmp);
  271                 if (-1 == name->port) {
  272                     logit(LOG_ERR, "Invalid proxy port.");
  273                     ret = 1;
  274                     break;
  275                 }
  276 
  277                 strlcpy(name->name, host, sizeof(name->name));
  278             } else {
  279                 logit(LOG_ERR, "No proxy port is specified.");
  280                 ret = 1;
  281                 break;
  282             }
  283         } else {
  284             /* Currently we do not support http proxy. */
  285 //          *type = PROXY_HTTP;
  286 //          logit(LOG_WARNING, "No proxy protocol is specified, use http proxy.");
  287 
  288             logit(LOG_WARNING, "No proxy protocol is specified.");
  289             ret = 1;
  290             break;
  291         }
  292     } while (0);
  293 
  294     free(str);
  295     return ret;
  296 }
  297 
  298 static int cfg_parseproxy(cfg_t *cfg, char *server, tcp_proxy_type_t *type, ddns_name_t *name)
  299 {
  300     const char *str;
  301 
  302     str = cfg_getstr(cfg, server);
  303     if (!str)
  304         return 1;
  305 
  306     return parseproxy(str, type, name);
  307 }
  308 #endif
  309 
  310 static int set_provider_opts(cfg_t *cfg, ddns_info_t *info, int custom)
  311 {
  312     ddns_system_t *system;
  313     const char *str;
  314     size_t j;
  315 
  316     if (custom)
  317         str = "custom";
  318     else
  319         str = cfg_title(cfg);
  320 
  321     system = plugin_find(str, 0);
  322     if (!system) {
  323         system = plugin_find(str, 1);
  324         if (!system) {
  325             logit(LOG_ERR, "Cannot find an DDNS plugin for provider '%s'", str);
  326             return 1;
  327         }
  328         logit(LOG_WARNING, "Guessing DDNS plugin '%s' from '%s'", system->name, str);
  329     }
  330 
  331     info->system = system;
  332 
  333     if (getserver(system->checkip_name, &info->checkip_name))
  334         goto error;
  335     if (strlen(system->checkip_url) > sizeof(info->checkip_url))
  336         goto error;
  337     strlcpy(info->checkip_url, system->checkip_url, sizeof(info->checkip_url));
  338 
  339     if (getserver(system->server_name, &info->server_name))
  340         goto error;
  341     if (strlen(system->server_url) > sizeof(info->server_url))
  342         goto error;
  343     strlcpy(info->server_url, system->server_url, sizeof(info->server_url));
  344 
  345     info->wildcard = cfg_getbool(cfg, "wildcard");
  346     info->ttl = cfg_getint(cfg, "ttl");
  347     info->proxied = cfg_getbool(cfg, "proxied");
  348     info->ssl_enabled = cfg_getbool(cfg, "ssl");
  349     str = cfg_getstr(cfg, "username");
  350     if (str && strlen(str) <= sizeof(info->creds.username))
  351         strlcpy(info->creds.username, str, sizeof(info->creds.username));
  352     str = cfg_getstr(cfg, "password");
  353     if (str && strlen(str) <= sizeof(info->creds.password))
  354         strlcpy(info->creds.password, str, sizeof(info->creds.password));
  355 
  356     for (j = 0; j < cfg_size(cfg, "hostname"); j++) {
  357         size_t pos = info->alias_count;
  358 
  359         str = cfg_getnstr(cfg, "hostname", j);
  360         if (!str)
  361             continue;
  362 
  363         if (info->alias_count == DDNS_MAX_ALIAS_NUMBER) {
  364             logit(LOG_WARNING, "Too many hostname aliases, skipping %s ...", str);
  365             continue;
  366         }
  367 
  368         strlcpy(info->alias[pos].name, str, sizeof(info->alias[pos].name));
  369         info->alias_count++;
  370     }
  371 
  372     if (custom) {
  373         info->append_myip = cfg_getbool(cfg, "append-myip");
  374 
  375         cfg_getserver(cfg, "ddns-server", &info->server_name);
  376         str = cfg_getstr(cfg, "ddns-path");
  377         if (str && strlen(str) <= sizeof(info->server_url))
  378             strlcpy(info->server_url, str, sizeof(info->server_url));
  379 
  380         for (j = 0; j < cfg_size(cfg, "ddns-response"); j++) {
  381             size_t pos = info->server_response_num;
  382 
  383             str = cfg_getnstr(cfg, "ddns-response", j);
  384             if (!str)
  385                 continue;
  386 
  387             if (info->server_response_num >= NELEMS(info->server_response)) {
  388                 logit(LOG_WARNING, "Skipping response '%s', only %zu custom responses supported",
  389                       str, NELEMS(info->server_response));
  390                 continue;
  391             }
  392 
  393             strlcpy(info->server_response[pos], str, sizeof(info->server_response[pos]));
  394             info->server_response_num++;
  395         }
  396 
  397         /* Default check, if no configured custom response string(s) */
  398         if (!cfg_size(cfg, "ddns-response")) {
  399             for (j = 0; j < NELEMS(info->server_response); j++) {
  400                 if (!generic_responses[j])
  401                     break;
  402 
  403                 strlcpy(info->server_response[j], generic_responses[j], sizeof(info->server_response[j]));
  404                 info->server_response_num++;
  405             }
  406         }
  407     }
  408 
  409     /*
  410      * Follows the ssl setting by default, except for providers
  411      * known to NOT support HTTPS for their checkip servers.
  412      *
  413      * This setting may only be disabled by the user, with the
  414      * custom provider section being the exeception to the rule.
  415      */
  416     info->checkip_ssl = info->ssl_enabled;
  417 
  418     /* Check known status of checkip server for provider */
  419     switch (system->checkip_ssl) {
  420     case DDNS_CHECKIP_SSL_UNSUPPORTED:
  421         info->checkip_ssl = 0;
  422         break;
  423 
  424     case DDNS_CHECKIP_SSL_REQUIRED:
  425         info->checkip_ssl = 1;
  426         break;
  427 
  428     default:
  429     case DDNS_CHECKIP_SSL_SUPPORTED:
  430         if (!cfg_getbool(cfg, "checkip-ssl"))
  431             info->checkip_ssl = 0;
  432     }
  433 
  434     /* The checkip server can be set for all provider types */
  435     if (!cfg_getserver(cfg, "checkip-server", &info->checkip_name)) {
  436         str = cfg_getstr(cfg, "checkip-path");
  437         if (str && strlen(str) <= sizeof(info->checkip_url))
  438             strlcpy(info->checkip_url, str, sizeof(info->checkip_url));
  439         else
  440             strlcpy(info->checkip_url, "/", sizeof(info->checkip_url));
  441 
  442         if (!strcasecmp(info->checkip_name.name, "default")) {
  443             strlcpy(info->checkip_name.name, DDNS_MY_IP_SERVER, sizeof(info->checkip_name.name));
  444             strlcpy(info->checkip_url, "/", sizeof(info->checkip_url));
  445             /* let local checkip-ssl decide HTTP/HTTPS for ipify */
  446         }
  447 
  448         /*
  449          * If a custom checkip server is defined, the
  450          * checkip-ssl setting is fully honored.
  451          */
  452         info->checkip_ssl = cfg_getbool(cfg, "checkip-ssl");
  453     }
  454 
  455     /* The checkip-command overrides any default or custom checkip-server */
  456     str = cfg_getstr(cfg, "checkip-command");
  457     if (str && strlen(str) > 0)
  458         info->checkip_cmd = strdup(str);
  459     else if (script_cmd)
  460         info->checkip_cmd = strdup(script_cmd);
  461 
  462     /* The per-provider user-agent setting, defaults to the global setting */
  463     info->user_agent = cfg_getstr(cfg, "user-agent");
  464     if (!info->user_agent)
  465         info->user_agent = user_agent;
  466 
  467     /* A per-proivder optional proxy server:port */
  468 #if 0
  469     cfg_parseproxy(cfg, "proxy", &info->proxy_type, &info->proxy_name);
  470 #endif
  471     return 0;
  472 
  473 error:
  474     logit(LOG_ERR, "Failed setting up %s DDNS provider, skipping.", str);
  475     return 1;
  476 }
  477 
  478 static int create_provider(cfg_t *cfg, int custom)
  479 {
  480     ddns_info_t *info;
  481 
  482     info = calloc(1, sizeof(*info));
  483     if (!info) {
  484         logit(LOG_ERR, "Failed allocating memory for provider %s", cfg_title(cfg));
  485         return 1;
  486     }
  487 
  488     http_construct(&info->checkip);
  489     http_construct(&info->server);
  490     if (set_provider_opts(cfg, info, custom)) {
  491         free(info);
  492         return 1;
  493     }
  494 
  495     LIST_INSERT_HEAD(&info_list, info, link);
  496     return 0;
  497 }
  498 
  499 ddns_info_t *conf_info_iterator(int first)
  500 {
  501     static ddns_info_t *ptr = NULL;
  502 
  503     if (first) {
  504         ptr = LIST_FIRST(&info_list);
  505         return ptr;
  506     }
  507 
  508     if (!ptr || ptr == LIST_END(&info_list))
  509         return NULL;
  510 
  511     ptr = LIST_NEXT(ptr, link);
  512     return ptr;
  513 }
  514 
  515 void conf_info_cleanup(void)
  516 {
  517     ddns_info_t *ptr, *tmp;
  518 
  519     LIST_FOREACH_SAFE(ptr, &info_list, link, tmp) {
  520         if (ptr->creds.encoded_password)
  521             free(ptr->creds.encoded_password);
  522         if (ptr->checkip_cmd)
  523             free(ptr->checkip_cmd);
  524         if (ptr->data)
  525             free(ptr->data);
  526         LIST_REMOVE(ptr, link);
  527         free(ptr);
  528     }
  529 }
  530 
  531 cfg_t *conf_parse_file(char *file, ddns_t *ctx)
  532 {
  533     int ret = 0;
  534     size_t i;
  535     cfg_opt_t provider_opts[] = {
  536         CFG_STR     ("username",     NULL, CFGF_NONE),
  537         CFG_STR     ("password",     NULL, CFGF_NONE),
  538         CFG_STR_LIST("hostname",     NULL, CFGF_NONE),
  539         CFG_STR_LIST("alias",        NULL, CFGF_DEPRECATED),
  540         CFG_BOOL    ("ssl",          cfg_true, CFGF_NONE),
  541         CFG_BOOL    ("wildcard",     cfg_false, CFGF_NONE),
  542         CFG_INT     ("ttl",          -1, CFGF_NODEFAULT),
  543         CFG_BOOL    ("proxied",      cfg_false, CFGF_NONE),
  544         CFG_STR     ("checkip-server", NULL, CFGF_NONE), /* Syntax:  name:port */
  545         CFG_STR     ("checkip-path",   NULL, CFGF_NONE), /* Default: "/" */
  546         CFG_BOOL    ("checkip-ssl",    cfg_true, CFGF_NONE),
  547         CFG_STR     ("checkip-command",NULL, CFGF_NONE), /* Syntax: /path/to/cmd [args] */
  548         CFG_STR     ("user-agent",     NULL, CFGF_NONE),
  549 //      CFG_STR     ("proxy",          NULL, CFGF_NONE), /* Syntax:  name:port */
  550         CFG_END()
  551     };
  552     cfg_opt_t custom_opts[] = {
  553         /* Same as a general provider */
  554         CFG_STR     ("username",     NULL, CFGF_NONE),
  555         CFG_STR     ("password",     NULL, CFGF_NONE),
  556         CFG_STR_LIST("hostname",     NULL, CFGF_NONE),
  557         CFG_STR_LIST("alias",        NULL, CFGF_DEPRECATED),
  558         CFG_BOOL    ("ssl",          cfg_true, CFGF_NONE),
  559         CFG_BOOL    ("wildcard",     cfg_false, CFGF_NONE),
  560         CFG_INT     ("ttl",          -1, CFGF_NODEFAULT),
  561         CFG_BOOL    ("proxied",      cfg_false, CFGF_NONE),
  562         CFG_STR     ("checkip-server", NULL, CFGF_NONE), /* Syntax:  name:port */
  563         CFG_STR     ("checkip-path",   NULL, CFGF_NONE), /* Default: "/" */
  564         CFG_BOOL    ("checkip-ssl",    cfg_true, CFGF_NONE),
  565         CFG_STR     ("checkip-command",NULL, CFGF_NONE), /* Syntax: /path/to/cmd [args] */
  566         CFG_STR     ("user-agent",     NULL, CFGF_NONE),
  567 //      CFG_STR     ("proxy",          NULL, CFGF_NONE), /* Syntax:  name:port */
  568         /* Custom settings */
  569         CFG_BOOL    ("append-myip",    cfg_false, CFGF_NONE),
  570         CFG_STR     ("ddns-server",    NULL, CFGF_NONE),
  571         CFG_STR     ("ddns-path",      NULL, CFGF_NONE),
  572         CFG_STR_LIST("ddns-response",  NULL, CFGF_NONE),
  573         CFG_END()
  574     };
  575     cfg_opt_t opts[] = {
  576         CFG_BOOL("verify-address", cfg_true, CFGF_NONE),
  577         CFG_BOOL("fake-address",  cfg_false, CFGF_NONE),
  578         CFG_BOOL("allow-ipv6",    cfg_false, CFGF_NONE),
  579         CFG_BOOL("secure-ssl",    cfg_true, CFGF_NONE),
  580         CFG_BOOL("broken-rtc",    cfg_false, CFGF_NONE),
  581         CFG_STR ("ca-trust-file", NULL, CFGF_NONE),
  582         CFG_STR ("cache-dir",     NULL, CFGF_DEPRECATED | CFGF_DROP),
  583         CFG_INT ("period",    DDNS_DEFAULT_PERIOD, CFGF_NONE),
  584         CFG_INT ("iterations",    DDNS_DEFAULT_ITERATIONS, CFGF_NONE),
  585         CFG_INT ("forced-update", DDNS_FORCED_UPDATE_PERIOD, CFGF_NONE),
  586         CFG_STR ("iface",         NULL, CFGF_NONE),
  587         CFG_STR ("user-agent",    NULL, CFGF_NONE),
  588         CFG_SEC ("provider",      provider_opts, CFGF_MULTI | CFGF_TITLE),
  589         CFG_SEC ("custom",        custom_opts, CFGF_MULTI | CFGF_TITLE),
  590         CFG_END()
  591     };
  592     cfg_t *cfg;
  593 
  594     cfg = cfg_init(opts, CFGF_NONE);
  595     if (!cfg) {
  596         logit(LOG_ERR, "Failed initializing configuration file parser: %s", strerror(errno));
  597         return NULL;
  598     }
  599 
  600     /* Custom logging, rather than default Confuse stderr logging */
  601     cfg_set_error_function(cfg, conf_errfunc);
  602 
  603     /* Validators */
  604     cfg_set_validate_func(cfg, "period", validate_period);
  605     cfg_set_validate_func(cfg, "provider", validate_provider);
  606     cfg_set_validate_func(cfg, "custom", validate_custom);
  607 
  608     switch (cfg_parse(cfg, file)) {
  609     case CFG_FILE_ERROR:
  610         logit(LOG_ERR, "Cannot read configuration file %s", file);
  611         return NULL;
  612 
  613     case CFG_PARSE_ERROR:
  614         logit(LOG_ERR, "Parse error in %s", file);
  615         return NULL;
  616 
  617     case CFG_SUCCESS:
  618         break;
  619     }
  620 
  621     /* Set global options */
  622     ctx->normal_update_period_sec = cfg_getint(cfg, "period");
  623     ctx->error_update_period_sec  = DDNS_ERROR_UPDATE_PERIOD;
  624     ctx->forced_update_period_sec = cfg_getint(cfg, "forced-update");
  625     if (once)
  626         ctx->total_iterations = 1;
  627     else
  628         ctx->total_iterations = cfg_getint(cfg, "iterations");
  629 
  630     verify_addr                   = cfg_getbool(cfg, "verify-address");
  631     ctx->forced_update_fake_addr  = cfg_getbool(cfg, "fake-address");
  632 
  633     /* Command line --iface=IFNAME takes precedence */
  634     if (!use_iface)
  635         iface                 = cfg_getstr(cfg, "iface");
  636     user_agent                    = cfg_getstr(cfg, "user-agent");
  637     if (!user_agent)
  638         user_agent            = DDNS_USER_AGENT;
  639     allow_ipv6                    = cfg_getbool(cfg, "allow-ipv6");
  640     secure_ssl                    = cfg_getbool(cfg, "secure-ssl");
  641     broken_rtc                    = cfg_getbool(cfg, "broken-rtc");
  642     ca_trust_file                 = cfg_getstr(cfg, "ca-trust-file");
  643     if (ca_trust_file && !fexist(ca_trust_file)) {
  644         logit(LOG_ERR, "Cannot find CA trust file %s", ca_trust_file);
  645         return NULL;
  646     }
  647 
  648     for (i = 0; i < cfg_size(cfg, "provider"); i++)
  649         ret |= create_provider(cfg_getnsec(cfg, "provider", i), 0);
  650 
  651     for (i = 0; i < cfg_size(cfg, "custom"); i++)
  652         ret |= create_provider(cfg_getnsec(cfg, "custom", i), 1);
  653 
  654     if (ret)
  655         return NULL;
  656 
  657     return cfg;
  658 }
  659 
  660 /**
  661  * Local Variables:
  662  *  indent-tabs-mode: t
  663  *  c-file-style: "linux"
  664  * End:
  665  */