1 /*
2  *  Copyright (C) 2004-2008 Christos Tsantilas
3  *
4  *  This program is free software; you can redistribute it and/or
5  *  modify it under the terms of the GNU Lesser General Public
6  *  License as published by the Free Software Foundation; either
7  *  version 2.1 of the License, or (at your option) any later version.
8  *
9  *  This program is distributed in the hope that it will be useful,
10  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
11  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  *  Lesser General Public License for more details.
13  *
14  *  You should have received a copy of the GNU Lesser General Public
15  *  License along with this library; if not, write to the Free Software
16  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
17  *  MA  02110-1301  USA.
18  */
19 
20 #include "common.h"
21 #include "c-icap.h"
22 #include <stdio.h>
23 #include <ctype.h>
24 #include <errno.h>
25 #include <assert.h>
26 #include "service.h"
27 #include "debug.h"
28 #include "module.h"
29 #include "filetype.h"
30 #include "cfg_param.h"
31 #include "commands.h"
32 #include "acl.h"
33 #include "txtTemplate.h"
34 #include "proc_mutex.h"
35 #include "port.h"
36 #include "registry.h"
37 #include "shared_mem.h"
38 #ifdef USE_OPENSSL
39 #include "net_io_ssl.h"
40 #endif
41 
42 #define MAX_INCLUDE_LEVEL 5
43 #define LINESIZE 8192
44 #define MAX_DIRECTIVE_SIZE 80
45 #define MAX_ARGS 50
46 int ARGC;
47 char **ARGV;
48 
49 struct ci_server_conf CI_CONF = {
50     NULL,
51 #ifdef _WIN32
52     "c:\\TEMP", /*TMPDIR*/ "c:\\TEMP\\c-icap.pid", /*PIDFILE*/ "\\\\.\\pipe\\c-icap",  /*COMMANDS_SOCKET; */
53 #else
54     "/var/tmp/", /*TMPDIR*/ "/var/run/c-icap/c-icap.pid", /*PIDFILE*/ "/var/run/c-icap/c-icap.ctl",   /*COMMANDS_SOCKET; */
55 #endif
56     NULL,                      /* RUN_USER */
57     NULL,                      /* RUN_GROUP */
58 #ifdef _WIN32
59     CONFDIR "\\c-icap.conf",   /*cfg_file */
60     CONFDIR "\\c-icap.magic",  /*magics_file */
61 #else
62     CONFDIR "/c-icap.conf",    /*cfg_file */
63     CONFDIR "/c-icap.magic",   /*magics_file */
64 #endif
65     NULL,                      /*MAGIC_DB */
66     SERVDIR,                   /*SERVICES_DIR */
67     MODSDIR,                   /*MODULES_DIR */
68     NULL,                      /*SERVER_ADMIN*/
69     NULL,                      /*SERVER_NAME*/
70     5,                         /*START_SERVERS*/
71     10,                        /*MAX_SERVERS*/
72     30,                        /*THREADS_PER_CHILD*/
73     30,                        /*MIN_SPARE_THREADS*/
74     60                         /*MAX_SPARE_THREADS*/
75 
76 #ifdef USE_OPENSSL
77     ,
78     0                         /*TLS_ENABLED, set by TLSPort*/
79 #endif
80 };
81 
82 
83 int TIMEOUT = 300;
84 int KEEPALIVE_TIMEOUT = 15;
85 int MAX_KEEPALIVE_REQUESTS = 100;
86 int MAX_SECS_TO_LINGER = 5;
87 int MAX_REQUESTS_BEFORE_REALLOCATE_MEM = 100;
88 int MAX_REQUESTS_PER_CHILD = 0;
89 int DAEMON_MODE = 1;
90 int VERSION_MODE = 0;
91 int HELP_MODE = 0;
92 int DebugLevelSetFromCmd = 0;
93 const char *DEFAULT_SERVICE = NULL; /*Default service if not defined in ICAP URI*/
94 int PIPELINING = 1;
95 int CHECK_FOR_BUGGY_CLIENT = 0;
96 int ALLOW204_AS_200OK_ZERO_ENCAPS = 0;
97 int FAKE_ALLOW204 = 1;
98 
99 
100 /* txtTemplate stuff */
101 extern const char *TEMPLATE_DIR;
102 extern const char *TEMPLATE_DEF_LANG;
103 extern int TEMPLATE_RELOAD_TIME; // Default time is one hour, this variable is in seconds
104 extern int TEMPLATE_CACHE_SIZE; // How many templates can be cached
105 extern int TEMPLATE_MEMBUF_SIZE; // Max memory for txtTemplate to expand template into txt
106 
107 extern char *SERVER_LOG_FILE;
108 extern char *ACCESS_LOG_FILE;
109 extern char *ACCESS_LOG_FORMAT;
110 /*extern char *LOGS_DIR;*/
111 
112 extern logger_module_t *default_logger;
113 extern access_control_module_t **used_access_controllers;
114 
115 extern char *REMOTE_PROXY_USER_HEADER;
116 extern int ALLOW_REMOTE_PROXY_USERS;
117 extern int REMOTE_PROXY_USER_HEADER_ENCODED;
118 
119 
120 /*Functions declaration */
121 int parse_file(const char *conf_file);
122 
123 /*config table functions*/
124 int cfg_load_magicfile(const char *directive, const char **argv, void *setdata);
125 int cfg_load_service(const char *directive, const char **argv, void *setdata);
126 int cfg_service_alias(const char *directive, const char **argv, void *setdata);
127 int cfg_load_module(const char *directive, const char **argv, void *setdata);
128 int cfg_set_logformat(const char *directive, const char **argv, void *setdata);
129 int cfg_set_logger(const char *directive, const char **argv, void *setdata);
130 int cfg_set_accesslog(const char *directive, const char **argv, void *setdata);
131 int cfg_set_debug_level(const char *directive, const char **argv, void *setdata);
132 int cfg_set_debug_stdout(const char *directive, const char **argv, void *setdata);
133 int cfg_set_body_maxmem(const char *directive, const char **argv, void *setdata);
134 int cfg_set_tmp_dir(const char *directive, const char **argv, void *setdata);
135 int cfg_set_acl_controllers(const char *directive, const char **argv, void *setdata);
136 int cfg_set_auth_method(const char *directive, const char **argv, void *setdata);
137 int cfg_include_config_file(const char *directive, const char **argv, void *setdata);
138 int cfg_group_source_by_group(const char *directive, const char **argv, void *setdata);
139 int cfg_group_source_by_user(const char *directive, const char **argv, void *setdata);
140 int cfg_shared_mem_scheme(const char *directive, const char **argv, void *setdata);
141 int cfg_proc_lock_scheme(const char *directive, const char **argv, void *setdata);
142 int cfg_set_port(const char *directive, const char **argv, void *setdata);
143 
144 /*The following 2 functions defined in access.c file*/
145 int cfg_acl_add(const char *directive, const char **argv, void *setdata);
146 int cfg_default_acl_access(const char *directive, const char **argv, void *setdata);
147 /****/
148 
149 struct sub_table {
150     const char *name;
151     int type;
152     struct ci_conf_entry *conf_table;
153 };
154 
155 static struct ci_conf_entry conf_variables[] = {
156 //     {"ListenAddress", &CI_CONF.ADDRESS, intl_cfg_set_str, NULL},
157     {"PidFile", &CI_CONF.PIDFILE, intl_cfg_set_str, NULL},
158     {"CommandsSocket", &CI_CONF.COMMANDS_SOCKET, intl_cfg_set_str, NULL},
159     {"Timeout", (void *) (&TIMEOUT), intl_cfg_set_int, NULL},
160     {"KeepAlive", NULL, NULL, NULL},
161     {"MaxKeepAliveRequests", &MAX_KEEPALIVE_REQUESTS, intl_cfg_set_int, NULL},
162     {"KeepAliveTimeout", &KEEPALIVE_TIMEOUT, intl_cfg_set_int, NULL},
163     {"StartServers", &CI_CONF.START_SERVERS, intl_cfg_set_int, NULL},
164     {"MaxServers", &CI_CONF.MAX_SERVERS, intl_cfg_set_int, NULL},
165     {"MinSpareThreads", &CI_CONF.MIN_SPARE_THREADS, intl_cfg_set_int, NULL},
166     {"MaxSpareThreads", &CI_CONF.MAX_SPARE_THREADS, intl_cfg_set_int, NULL},
167     {"ThreadsPerChild", &CI_CONF.THREADS_PER_CHILD, intl_cfg_set_int, NULL},
168     {"MaxRequestsPerChild", &MAX_REQUESTS_PER_CHILD, intl_cfg_set_int, NULL},
169     {"MaxRequestsReallocateMem", &MAX_REQUESTS_BEFORE_REALLOCATE_MEM, intl_cfg_set_int, NULL},
170     {"Port", &CI_CONF.PORTS, cfg_set_port, NULL},
171 #ifdef USE_OPENSSL
172     {"TlsPort", &CI_CONF.PORTS, cfg_set_port, NULL},
173     {"TlsPassphrase", &CI_CONF.TLS_PASSPHRASE, intl_cfg_set_str, NULL},
174     /*The Ssl* alias of Tls* cfg params*/
175     {"SslPort", &CI_CONF.PORTS, cfg_set_port, NULL},
176     {"SslPassphrase", &CI_CONF.TLS_PASSPHRASE, intl_cfg_set_str, NULL},
177 #endif
178     {"User", &CI_CONF.RUN_USER, intl_cfg_set_str, NULL},
179     {"Group", &CI_CONF.RUN_GROUP, intl_cfg_set_str, NULL},
180     {"ServerAdmin", &CI_CONF.SERVER_ADMIN, intl_cfg_set_str, NULL},
181     {"ServerName", &CI_CONF.SERVER_NAME, intl_cfg_set_str, NULL},
182     {"LoadMagicFile", NULL, cfg_load_magicfile, NULL},
183     {"Logger", &default_logger, cfg_set_logger, NULL},
184     {"ServerLog", &SERVER_LOG_FILE, intl_cfg_set_str, NULL},
185     {"AccessLog", NULL, cfg_set_accesslog, NULL},
186     {"LogFormat", NULL, cfg_set_logformat, NULL},
187     {"DebugLevel", NULL, cfg_set_debug_level, NULL},   /*Set library's debug level */
188     {"ServicesDir", &CI_CONF.SERVICES_DIR, intl_cfg_set_str, NULL},
189     {"ModulesDir", &CI_CONF.MODULES_DIR, intl_cfg_set_str, NULL},
190     {"Service", NULL, cfg_load_service, NULL},
191     {"ServiceAlias", NULL, cfg_service_alias, NULL},
192     {"Module", NULL, cfg_load_module, NULL},
193     {"TmpDir", NULL, cfg_set_tmp_dir, NULL},
194     {"MaxMemObject", NULL, cfg_set_body_maxmem, NULL}, /*Set library's body max mem */
195     {"AclControllers", NULL, cfg_set_acl_controllers, NULL},
196     {"acl", NULL, cfg_acl_add, NULL},
197     {"icap_access", NULL, cfg_default_acl_access, NULL},
198     {"client_access", NULL, cfg_default_acl_access, NULL},
199     {"AuthMethod", NULL, cfg_set_auth_method, NULL},
200     {"Include", NULL, cfg_include_config_file, NULL},
201     {"RemoteProxyUserHeader", &REMOTE_PROXY_USER_HEADER, intl_cfg_set_str, NULL},
202     {"RemoteProxyUserHeaderEncoded", &REMOTE_PROXY_USER_HEADER_ENCODED, intl_cfg_onoff, NULL},
203     {"RemoteProxyUsers", &ALLOW_REMOTE_PROXY_USERS, intl_cfg_onoff, NULL},
204     {"TemplateDir", &TEMPLATE_DIR, intl_cfg_set_str, NULL},
205     {"TemplateDefaultLanguage", &TEMPLATE_DEF_LANG, intl_cfg_set_str, NULL},
206     {"TemplateReloadTime", &TEMPLATE_RELOAD_TIME, intl_cfg_set_int, NULL},
207     {"TemplateCacheSize", &TEMPLATE_CACHE_SIZE, intl_cfg_set_int, NULL},
208     {"TemplateMemBufSize", &TEMPLATE_MEMBUF_SIZE, intl_cfg_set_int, NULL},
209     {"GroupSourceByGroup", NULL, cfg_group_source_by_group, NULL},
210     {"GroupSourceByUser", NULL, cfg_group_source_by_user, NULL},
211     {"InterProcessSharedMemScheme", NULL, cfg_shared_mem_scheme, NULL},
212     {"InterProcessLockingScheme", NULL, cfg_proc_lock_scheme, NULL},
213     {"DefaultService", &DEFAULT_SERVICE, intl_cfg_set_str, NULL},
214     {"Pipelining", &PIPELINING, intl_cfg_onoff, NULL},
215     {"SupportBuggyClients", &CHECK_FOR_BUGGY_CLIENT, intl_cfg_onoff, NULL},
216     {"Allow204As200okZeroEncaps", &ALLOW204_AS_200OK_ZERO_ENCAPS, intl_cfg_enable, NULL},
217     {"FakeAllow204", &FAKE_ALLOW204, intl_cfg_onoff, NULL},
218     {NULL, NULL, NULL, NULL}
219 };
220 
221 #define STEPSIZE 10
222 static struct sub_table *extra_conf_tables = NULL;
223 int conf_tables_list_size = 0;
224 int conf_tables_num = 0;
225 
226 
search_conf_table(struct ci_conf_entry * table,char * varname)227 struct ci_conf_entry *search_conf_table(struct ci_conf_entry *table, char *varname)
228 {
229     int i;
230     for (i = 0; table[i].name != NULL; i++) {
231         if (0 == strcmp(varname, table[i].name))
232             return &table[i];
233     }
234     return NULL;
235 }
236 
init_conf_tables()237 void init_conf_tables()
238 {
239     if ((extra_conf_tables =
240                 malloc(STEPSIZE * sizeof(struct sub_table))) == NULL) {
241         ci_debug_printf(1, "Error allocating memory...\n");
242         return;
243     }
244     conf_tables_list_size = STEPSIZE;
245 }
246 
reset_conf_tables()247 void reset_conf_tables()
248 {
249     conf_tables_num = 0;
250 }
251 
register_conf_table(const char * name,struct ci_conf_entry * table,int type)252 int register_conf_table(const char *name, struct ci_conf_entry *table, int type)
253 {
254     struct sub_table *new;
255     int i, insert_pos;
256     if (!extra_conf_tables)
257         return 0;
258 
259     insert_pos = -1;
260     for (i = 0; insert_pos < 0 && i < conf_tables_num; i++) {
261         if (extra_conf_tables[i].name && strcmp(name, extra_conf_tables[i].name) == 0) {
262             ci_debug_printf(1,"Config table :%s already exists!\n", name);
263             return 0;
264         } else if (extra_conf_tables[i].name == NULL) { /*empty pos use this one*/
265             insert_pos = i;
266         }
267     }
268 
269     if (insert_pos < 0) { /*if not empry pos found add it to the end*/
270         insert_pos = conf_tables_num;
271 
272         if (conf_tables_num == conf_tables_list_size) {
273             /*tables list is full, reallocating space ...... */
274             if (NULL ==
275                     (new =
276                          realloc(extra_conf_tables, sizeof(struct sub_table)*(conf_tables_list_size + STEPSIZE))))
277                 return 0;
278             extra_conf_tables = new;
279             conf_tables_list_size += STEPSIZE;
280         }
281         conf_tables_num++;
282     }
283 
284     ci_debug_printf(10, "Registering conf table: %s\n", name);
285 
286     extra_conf_tables[insert_pos].name = name;    /*It works. Points to the modules.name. (????) */
287     extra_conf_tables[insert_pos].type = type;
288     extra_conf_tables[insert_pos].conf_table = table;
289     return 1;
290 }
291 
unregister_conf_table(const char * name)292 struct ci_conf_entry *unregister_conf_table(const char *name)
293 {
294     int i;
295     struct ci_conf_entry *table;
296 
297     if (extra_conf_tables) {   /*Not really needed........ */
298         for (i = 0; i < conf_tables_num; i++) {
299             if (extra_conf_tables[i].name && strcmp(name, extra_conf_tables[i].name) == 0) {
300                 table = extra_conf_tables[i].conf_table;
301                 extra_conf_tables[i].name = NULL;
302                 extra_conf_tables[i].type = 0;
303                 extra_conf_tables[i].conf_table = NULL;
304                 return table;
305             }
306         }
307     }
308     ci_debug_printf(1, "Table %s not found!\n", name);
309     return NULL;
310 }
311 
search_variables(char * table,char * varname)312 struct ci_conf_entry *search_variables(char *table, char *varname)
313 {
314     int i;
315     if (table == NULL)
316         return search_conf_table(conf_variables, varname);
317 
318     ci_debug_printf(3, "Going to search variable %s in table %s\n", varname,
319                     table);
320 
321     if (!extra_conf_tables)    /*Not really needed........ */
322         return NULL;
323 
324     for (i = 0; i < conf_tables_num; i++) {
325         if (extra_conf_tables[i].name && strcmp(table, extra_conf_tables[i].name) == 0) {
326             return search_conf_table(extra_conf_tables[i].conf_table,
327                                      varname);
328         }
329     }
330     ci_debug_printf(1, "Variable %s or table %s not found!\n", varname, table);
331     return NULL;
332 }
333 
print_conf_variables(struct ci_conf_entry * table)334 void print_conf_variables(struct ci_conf_entry *table)
335 {
336     int i;
337     for (i = 0; table[i].name != NULL; i++) {
338         ci_debug_printf(9, "%s=", table[i].name);
339         if (!table[i].data) {
340             ci_debug_printf(9, "\n");
341         } else if (table[i].action == intl_cfg_set_str) {
342             if (*(char *) table[i].data) {
343                 ci_debug_printf(9, "%s\n", *(char **) table[i].data)
344             } else {
345                 ci_debug_printf(9, "\n");
346             }
347         } else if (table[i].action == intl_cfg_set_int) {
348             ci_debug_printf(9, "%d\n", *(int *) table[i].data);
349         } else if (table[i].action == intl_cfg_size_off) {
350             ci_debug_printf(9, "%" PRINTF_OFF_T "\n",
351                             (CAST_OFF_T) *(ci_off_t *) table[i].data);
352         } else if (table[i].action == intl_cfg_size_long) {
353             ci_debug_printf(9, "%ld\n", *(long *) table[i].data);
354         } else if (table[i].action == intl_cfg_onoff) {
355             ci_debug_printf(9, "%d\n", *(int *) table[i].data);
356         } else if (table[i].action == intl_cfg_enable) {
357             ci_debug_printf(9, "%d\n", *(int *) table[i].data);
358         } else if (table[i].action == intl_cfg_disable) {
359             ci_debug_printf(9, "%d\n", *(int *) table[i].data);
360         } else if (table[i].data) {
361             ci_debug_printf(9, "%p\n", table[i].data);
362         }
363     }
364 }
365 
print_variables()366 int print_variables()
367 {
368     int i;
369     ci_debug_printf(9, "\n\nPrinting variables\n");
370     print_conf_variables(conf_variables);
371     if (!extra_conf_tables)    /*Not really needed........ */
372         return 1;
373 
374     for (i = 0; i < conf_tables_num; i++) {
375         if ( extra_conf_tables[i].name) {
376             ci_debug_printf(9, "Printing variables in table %s\n",
377                             extra_conf_tables[i].name);
378             print_conf_variables(extra_conf_tables[i].conf_table);
379         }
380     }
381     return 1;
382 }
383 
384 
385 /************************************************************************/
386 /*  Set variables functions                                             */
387 /*
388    The following tree functions refered to non constant variables so
389    the compilers in Win32 have problem to appeared in static arrays
390 */
cfg_set_port(const char * directive,const char ** argv,void * setdata)391 int cfg_set_port(const char *directive, const char **argv, void *setdata)
392 {
393     int i;
394     char *s, *addr, *connect_port;
395     ci_port_t *pcfg = NULL;
396     ci_port_t tmpP;
397     ci_vector_t **port_configs = (ci_vector_t **)setdata;
398     if (argv == NULL || argv[0] == NULL) {
399         ci_debug_printf(1, "Missing arguments in %s directive\n", directive);
400         return 0;
401     }
402     if (!*port_configs)
403         *port_configs = ci_vector_create(2048);
404 
405     memset(&tmpP, 0, sizeof(ci_port_t));
406 
407     pcfg = (ci_port_t *)ci_vector_add(*port_configs, (void *)&tmpP, sizeof(ci_port_t));
408     if (!pcfg) {
409         ci_debug_printf(1, "Maximum number of configured ports is reached\n");
410         return 0;
411     }
412 
413     connect_port = strdup(argv[0]);
414     if ((s = strrchr(connect_port, ':'))) {
415         *s = '\0';
416         addr = connect_port;
417         if (*addr == '[') {
418             if (addr[strlen(addr) - 1] != ']') {
419                 ci_debug_printf(1, "Failed to parse listen address: %s\n", addr);
420                 free(connect_port);
421                 return 0;
422             }
423             ++addr;
424             addr[strlen(addr) - 1] = '\0';
425         }
426         pcfg->address = strdup(addr);
427         s++;
428     } else
429         s = connect_port;
430 
431     pcfg->port = atoi(s);
432     free(connect_port);
433     connect_port = s = NULL;
434     if (pcfg->port <= 0) {
435         ci_debug_printf(1, "Failed to parse %s (parsed port number:%d)\n", directive, pcfg->port);
436         return 0;
437     }
438 
439     if (!argv[1])
440         return 1;
441 
442 #ifdef USE_OPENSSL
443     int isTls = (strcmp(directive, "TlsPort") == 0 || strcmp(directive, "SslPort") == 0) ? 1 : 0;
444     CI_CONF.TLS_ENABLED = 1;
445     pcfg->tls_enabled = 1;
446 #endif
447 
448     for (i = 1; argv[i] != NULL; ++i) {
449 #ifdef USE_OPENSSL
450         if (isTls && icap_port_tls_option(argv[i], pcfg, CONFDIR)) {
451         } else
452 #endif
453         {
454             ci_debug_printf(1, "Unknown %s option: '%s'", directive, argv[i]);
455             return 0;
456         }
457     }
458 
459     return 1;
460 }
461 
cfg_set_debug_level(const char * directive,const char ** argv,void * setdata)462 int cfg_set_debug_level(const char *directive, const char **argv, void *setdata)
463 {
464     if (!DebugLevelSetFromCmd)
465         return intl_cfg_set_int(directive, argv, &CI_DEBUG_LEVEL);
466     /*else ignore ....*/
467     return 1;
468 }
469 
cfg_set_debug_level_cmd(const char * directive,const char ** argv,void * setdata)470 int cfg_set_debug_level_cmd(const char *directive, const char **argv, void *setdata)
471 {
472     DebugLevelSetFromCmd = 1;
473     return intl_cfg_set_int(directive, argv, &CI_DEBUG_LEVEL);
474 }
475 
cfg_set_debug_stdout(const char * directive,const char ** argv,void * setdata)476 int cfg_set_debug_stdout(const char *directive, const char **argv, void *setdata)
477 {
478     return intl_cfg_enable(directive, argv, &CI_DEBUG_STDOUT);
479 }
480 
cfg_set_body_maxmem(const char * directive,const char ** argv,void * setdata)481 int cfg_set_body_maxmem(const char *directive, const char **argv, void *setdata)
482 {
483     return intl_cfg_size_long(directive, argv, &CI_BODY_MAX_MEM);
484 }
485 
cfg_load_service(const char * directive,const char ** argv,void * setdata)486 int cfg_load_service(const char *directive, const char **argv, void *setdata)
487 {
488     ci_service_module_t *service = NULL;
489     if (argv == NULL || argv[0] == NULL || argv[1] == NULL) {
490         ci_debug_printf(1, "Missing arguments in LoadService directive\n");
491         return 0;
492     }
493     ci_debug_printf(2, "Loading service: %s path %s\n", argv[0], argv[1]);
494 
495     if (!(service = register_service(argv[1], argv + 2))) {
496         ci_debug_printf(1, "Error loading service %s\n", argv[1]);
497         return 0;
498     }
499     add_service_alias(argv[0], service->mod_name, NULL);
500     return 1;
501 }
502 
cfg_service_alias(const char * directive,const char ** argv,void * setdata)503 int cfg_service_alias(const char *directive, const char **argv, void *setdata)
504 {
505     char *service_args = NULL;
506     if (argv == NULL || argv[0] == NULL || argv[1] == NULL) {
507         ci_debug_printf(1, "Missing arguments in ServiceAlias directive\n");
508         return 0;
509     }
510     if ((service_args = strchr(argv[1], '?'))) {
511         *service_args = '\0';
512         service_args++;
513     }
514 
515     ci_debug_printf(2, "Alias: %s of service %s\n", argv[0], argv[1]);
516     add_service_alias(argv[0], argv[1], service_args);
517     return 1;
518 }
519 
cfg_load_module(const char * directive,const char ** argv,void * setdata)520 int cfg_load_module(const char *directive, const char **argv, void *setdata)
521 {
522     if (argv == NULL || argv[0] == NULL || argv[1] == NULL) {
523         ci_debug_printf(1, "Missing arguments in LoadModule directive\n");
524         return 0;
525     }
526     ci_debug_printf(2, "Loading service: %s path %s\n", argv[0], argv[1]);
527 
528     if (!register_module(argv[1], argv[0], argv + 2)) {
529         ci_debug_printf(1, "Error loading module %s, module path %s\n", argv[1], argv[0]);
530         return 0;
531     }
532     return 1;
533 }
534 
cfg_load_magicfile(const char * directive,const char ** argv,void * setdata)535 int cfg_load_magicfile(const char *directive, const char **argv, void *setdata)
536 {
537     const char *db_file;
538     struct ci_magics_db *ndb;
539     if (argv == NULL || argv[0] == NULL) {
540         return 0;
541     }
542 
543     db_file = argv[0];
544     if (strcmp(CI_CONF.magics_file, db_file) == 0) {
545         ci_debug_printf(2, "The db file %s is the same as default. Ignoring...\n", db_file);
546         return 1;
547     }
548     ci_debug_printf(2, "Going to load magic file %s\n", db_file);
549     ndb = ci_magic_db_load(db_file);
550     if (!ndb) {
551         ci_debug_printf(1, "Can not load magic file %s!!!\n", db_file);
552         return 0;
553     }
554     if (!CI_CONF.MAGIC_DB)
555         CI_CONF.MAGIC_DB = ndb;
556 
557     return 1;
558 }
559 
560 int logformat_add(const char *name, const char *format);
cfg_set_logformat(const char * directive,const char ** argv,void * setdata)561 int cfg_set_logformat(const char *directive, const char **argv, void *setdata)
562 {
563     if (argv == NULL || argv[0] == NULL || argv[1] == NULL) {
564         ci_debug_printf(1, "Missing arguments in directive %s\n", directive);
565         return 0;
566     }
567     ci_debug_printf(2, "Adding the logformat %s: %s\n",argv[0],argv[1]);
568     return logformat_add(argv[0], argv[1]);
569 }
570 
571 int file_log_addlogfile(const char *file, const char *format, const char **acls);
cfg_set_accesslog(const char * directive,const char ** argv,void * setdata)572 int cfg_set_accesslog(const char *directive, const char **argv, void *setdata)
573 {
574     const char **acls = NULL;
575     if (argv == NULL || argv[0] == NULL ) {
576         ci_debug_printf(1, "Missing arguments in directive %s\n", directive);
577         return 0;
578     }
579     if (argv[1] != NULL && argv[2] !=NULL) {
580         acls = argv+2;
581     }
582     ci_debug_printf(2, "Adding the access logfile %s\n",argv[0]);
583     return file_log_addlogfile(argv[0], argv[1], acls);
584 }
585 
586 
587 extern logger_module_t file_logger;
cfg_set_logger(const char * directive,const char ** argv,void * setdata)588 int cfg_set_logger(const char *directive, const char **argv, void *setdata)
589 {
590     logger_module_t *logger;
591     if (argv == NULL || argv[0] == NULL) {
592         ci_debug_printf(1, "Missing arguments in directive\n");
593         return 0;
594     }
595 
596     if (!(logger = find_logger(argv[0])))
597         return 0;
598     default_logger = logger;
599     ci_debug_printf(2, "Setting parameter: %s=%s\n", directive, argv[0]);
600     return 1;
601 }
602 
cfg_set_tmp_dir(const char * directive,const char ** argv,void * setdata)603 int cfg_set_tmp_dir(const char *directive, const char **argv, void *setdata)
604 {
605     int len;
606     if (argv == NULL || argv[0] == NULL) {
607         return 0;
608     }
609 
610     cfg_default_value_store(&CI_CONF.TMPDIR, &CI_CONF.TMPDIR, sizeof(char *));
611     len = strlen(argv[0]);
612 
613     CI_CONF.TMPDIR = ci_cfg_alloc_mem((len + 2) * sizeof(char));
614     strcpy(CI_CONF.TMPDIR, argv[0]);
615 #ifdef _WIN32
616     if (CI_CONF.TMPDIR[len] != '\\') {
617         CI_CONF.TMPDIR[len] = '\\';
618         CI_CONF.TMPDIR[len + 1] = '\0';
619     }
620 #else
621     if (CI_CONF.TMPDIR[len] != '/') {
622         CI_CONF.TMPDIR[len] = '/';
623         CI_CONF.TMPDIR[len + 1] = '\0';
624     }
625 #endif
626     /*Check if tmpdir exists. If no try to build it , report an error and uses the default... */
627     CI_TMPDIR = CI_CONF.TMPDIR;   /*Sets the library's temporary dir to .... */
628     ci_debug_printf(2, "Setting parameter: %s=%s\n", directive, argv[0]);
629     return 1;
630 }
631 
cfg_set_acl_controllers(const char * directive,const char ** argv,void * setdata)632 int cfg_set_acl_controllers(const char *directive, const char **argv, void *setdata)
633 {
634     int i, k, argc, ret;
635     access_control_module_t *acl_mod;
636     if (argv == NULL || argv[0] == NULL) {
637         return 0;
638     }
639 
640     if (strncasecmp(argv[0], "none", 4) == 0) {
641         used_access_controllers = NULL;
642         return 1;
643     }
644 
645     for (argc = 0; argv[argc] != NULL; argc++);        /*Find the number of acl controllers */
646     used_access_controllers =
647         ci_cfg_alloc_mem((argc+1) * sizeof(access_control_module_t *));
648     k = 0;
649     ret = 1;
650     for (i = 0; i < argc; i++) {
651         if ((acl_mod = find_access_controller(argv[i])) != NULL) {
652             used_access_controllers[k++] = acl_mod;
653         } else {
654             ci_debug_printf(1, "No access controller with name :%s\n",
655                             argv[i]);
656             ret = 0;
657         }
658     }
659     used_access_controllers[k] = NULL;
660     return ret;
661 
662 }
663 
664 
cfg_set_auth_method(const char * directive,const char ** argv,void * setdata)665 int cfg_set_auth_method(const char *directive, const char **argv, void *setdata)
666 {
667     const char *method = NULL;
668     if (argv == NULL || argv[0] == NULL || argv[1] == NULL) {
669         return 0;
670     }
671     method = argv[0];
672 
673     if (strncasecmp(argv[1], "none", 4) == 0) {
674         return set_method_authenticators(method, NULL);
675     }
676     return set_method_authenticators(method, (const char **)argv + 1);
677 }
678 
cfg_acl_add(const char * directive,const char ** argv,void * setdata)679 int cfg_acl_add(const char *directive, const char **argv, void *setdata)
680 {
681     const char *acl_name, *acl_type;
682     int argc, ok;
683 
684     if (!argv[0] || !argv[1] || !argv[2]) /* at least an argument */
685         return 0;
686 
687 
688     acl_name = argv[0];
689     acl_type = argv[1];
690     for (argc = 2, ok =1; argv[argc] != NULL && ok; argc++) {
691         ci_debug_printf(2, "Adding to acl %s the data %s\n", acl_name, argv[argc]);
692         ok = ci_acl_add_data(acl_name, acl_type, argv[argc]);
693     }
694     ci_debug_printf(2, "New ACL with name:%s and  ACL Type: %s\n", argv[0], argv[1]);
695     return ok;
696 }
697 
cfg_include_config_file(const char * directive,const char ** argv,void * setdata)698 int cfg_include_config_file(const char *directive, const char **argv, void *setdata)
699 {
700     char path[CI_MAX_PATH];
701     const char *cfg_file;
702 
703     if (argv == NULL || argv[0] == NULL) {
704         return 0;
705     }
706     cfg_file = argv[0];
707     if (cfg_file[0] != '/') {  /*Win32 code? */
708         snprintf(path, CI_MAX_PATH, CONFDIR "/%s", cfg_file);
709         cfg_file = path;
710     }
711 
712     ci_debug_printf(2, "\n*** Going to open config file %s ***\n", cfg_file);
713     return parse_file(cfg_file);
714 }
715 
716 int group_source_add_by_group(const char *table_name);
717 int group_source_add_by_user(const char *table_name);
718 
cfg_group_source_by_group(const char * directive,const char ** argv,void * setdata)719 int cfg_group_source_by_group(const char *directive, const char **argv, void *setdata)
720 {
721     const char *group_table = NULL;
722     if (argv == NULL || argv[0] == NULL) {
723         return 0;
724     }
725     group_table = argv[0];
726     return group_source_add_by_group(group_table);
727 }
728 
cfg_group_source_by_user(const char * directive,const char ** argv,void * setdata)729 int cfg_group_source_by_user(const char *directive, const char **argv, void *setdata)
730 {
731     const char *group_table = NULL;
732     if (argv == NULL || argv[0] == NULL) {
733         return 0;
734     }
735     group_table = argv[0];
736     return group_source_add_by_user(group_table);
737 }
738 
cfg_shared_mem_scheme(const char * directive,const char ** argv,void * setdata)739 int cfg_shared_mem_scheme(const char *directive, const char **argv, void *setdata)
740 {
741     if (argv == NULL || argv[0] == NULL) {
742         return 0;
743     }
744     return ci_shared_mem_set_scheme(argv[0]);
745 }
746 
cfg_proc_lock_scheme(const char * directive,const char ** argv,void * setdata)747 int cfg_proc_lock_scheme(const char *directive, const char **argv, void *setdata)
748 {
749     if (argv == NULL || argv[0] == NULL) {
750         return 0;
751     }
752     return ci_proc_mutex_set_scheme(argv[0]);
753 }
754 
755 /**************************************************************************/
756 /* Parse file functions                                                   */
757 
fread_line(FILE * f_conf,char * line)758 int fread_line(FILE * f_conf, char *line)
759 {
760     if (!fgets(line, LINESIZE, f_conf)) {
761         if (feof(f_conf)) {
762             line[0] = '\0';
763             return -1;
764         } else
765             return 0;
766     }
767     if (strlen(line) >= LINESIZE - 2 && line[LINESIZE - 2] != '\n') {  //Size of line > LINESIZE
768         while (!feof(f_conf)) {
769             if (fgetc(f_conf) == '\n')
770                 return 1;
771         }
772         return 0;
773     }
774     return 1;
775 }
776 
777 
find_action(char * str,char ** arg)778 struct ci_conf_entry *find_action(char *str, char **arg)
779 {
780     char *end, *table, *s;
781     end = str;
782     while (*end != '\0' && !isspace(*end))
783         end++;
784     *end = '\0';               /*Mark the end of Variable...... */
785     end++;                     /*... and continue.... */
786     while (*end != '\0' && isspace(*end))      /*Find the start of arguments ...... */
787         end++;
788     *arg = end;
789     if ((s = strchr(str, '.')) != NULL) {
790         table = str;
791         str = s + 1;
792         *s = '\0';
793     } else
794         table = NULL;
795 
796 //     return search_conf_table(conf_variables,str);
797     return search_variables(table, str);
798 }
799 
split_args(char * args)800 char **split_args(char *args)
801 {
802     int len, i = 0, brkt;
803     char **argv = NULL, *str, *end, *p;
804     argv = malloc((MAX_ARGS + 1) * sizeof(char *));
805     end = args;
806     do {
807         str = end;
808         if (*end == '"') {
809             end++;
810             str = end;
811             while (*end != '\0' && *end != '"') {
812                 /*support escaped \" */
813                 if (*end == '\\' && *(end+1) == '"') {
814                     for (p = end; *p != '\0'; p++)
815                         *p = *(p+1);
816                 }
817                 end++;
818             }
819         } else {
820             /*Support arguments in the form arg{a, b...}*/
821             brkt = 0;
822             while (*end != '\0' && (!isspace(*end) || brkt)) {
823                 if (*end == '{') brkt = 1;
824                 else if (brkt && *end == '}') brkt = 0;
825                 end++;
826             }
827         }
828         len = end - str;
829 
830         argv[i] = malloc((len + 1) * sizeof(char));
831 
832         memcpy(argv[i], str, len);    /*copy until len or end of string */
833         argv[i][len] = '\0';
834         ++i;
835 
836         if (i >= MAX_ARGS)
837             break;
838 
839         if (*end == '"')
840             end++;
841         while (*end != '\0' && isspace(*end))
842             end++;
843 
844     } while (*end != '\0');
845     argv[i] = NULL;
846 
847     return argv;
848 }
849 
free_args(char ** argv)850 void free_args(char **argv)
851 {
852     int i;
853     if (argv == NULL)
854         return;
855     for (i = 0; argv[i] != NULL; i++) {
856         free(argv[i]);
857         argv[i] = NULL;
858     }
859     free(argv);
860 }
861 
process_line(char * orig_line)862 int process_line(char *orig_line)
863 {
864     char *str, *args, **argv = NULL;
865     int ret = 1;
866     struct ci_conf_entry *entry;
867     char line[LINESIZE];
868 
869     strncpy(line, orig_line, LINESIZE);
870     line[LINESIZE-1] = '\0';
871 
872     str = line;
873     while (*str != '\0' && isspace(*str))      /*Eat the spaces in the begging */
874         str++;
875     if (*str == '\0' || *str == '#')   /*Empty line or comment */
876         return 1;
877 
878     entry = find_action(str, &args);
879 //   ci_debug_printf(10,"Line %s (Args:%s)\n",entry->name,args);
880 
881     if (entry && entry->action) {
882         argv = split_args(args);
883         if ((*(entry->action)) (entry->name, (const char **)argv, entry->data) == 0)
884             ret = 0;
885         free_args(argv);
886         return ret;
887     }
888     /*OK*/
889     /*Else parse error.......
890        Log an error..... */
891     return 0;
892 }
893 
894 static int PARSE_LEVEL = 0;
895 
parse_file(const char * conf_file)896 int parse_file(const char *conf_file)
897 {
898     FILE *f_conf;
899     char line[LINESIZE];
900     int line_count, ret_value;
901 
902     if (PARSE_LEVEL >= MAX_INCLUDE_LEVEL) {
903         ci_debug_printf(1, "Include level > %d. I will not parse file:%s\n",
904                         MAX_INCLUDE_LEVEL,
905                         conf_file);
906         return 0;
907     }
908 
909     if ((f_conf = fopen(conf_file, "r")) == NULL) {
910         //or log_server better........
911         ci_debug_printf(1, "Can not open configuration file %s\n", conf_file);
912         return 0;
913     }
914     line_count = 0;
915     ret_value = 1;
916     PARSE_LEVEL++;
917     while (!feof(f_conf)) {
918         line_count++;
919         if (!fread_line(f_conf, line) || !process_line(line)) {
920             ci_debug_printf(1, "Fatal error while parsing config file: \"%s\" line: %d\n",
921                             conf_file, line_count);
922             ci_debug_printf(1, "The line is: %s\n", line);
923             ret_value = 0;
924         }
925     }
926 
927     fclose(f_conf);
928     PARSE_LEVEL--;
929     return ret_value;
930 }
931 
932 
933 /****************************************************************/
934 /* Command line options implementation, function and structures */
935 
936 
937 /* #ifdef _WIN32 */
938 /* #define opt_pre "/"  */
939 /* #else */
940 #define opt_pre "-"
941 /* #endif */
942 
943 static struct ci_options_entry options[] = {
944     {opt_pre "V", NULL, &VERSION_MODE, ci_cfg_version, "Print c-icap version and exits"},
945     {opt_pre "VV", NULL, &VERSION_MODE, ci_cfg_build_info, "Print c-icap version and build informations and exits"},
946     {
947         opt_pre "f", "filename", &CI_CONF.cfg_file, ci_cfg_set_str,
948         "Specify the configuration file"
949     },
950     {opt_pre "N", NULL, &DAEMON_MODE, ci_cfg_disable, "Do not run as daemon"},
951     {
952         opt_pre "d", "level", NULL, cfg_set_debug_level_cmd,
953         "Specify the debug level"
954     },
955     {
956         opt_pre "D", NULL, NULL, cfg_set_debug_stdout,
957         "Print debug info to stdout"
958     },
959     {opt_pre "h", NULL, &HELP_MODE, ci_cfg_enable, "Show this help"},
960     {NULL, NULL, NULL, NULL}
961 };
962 
963 
964 
config(int argc,char ** argv)965 int config(int argc, char **argv)
966 {
967     ARGC = argc;
968     ARGV = argv;
969     ci_cfg_lib_init();
970     if (!ci_args_apply(argc, argv, options)) {
971         ci_debug_printf(1, "Error in command line options\n");
972         ci_args_usage(argv[0], options);
973         exit(-1);
974     }
975     if (VERSION_MODE)
976         exit(0);
977     if (HELP_MODE) {
978         ci_args_usage(argv[0], options);
979         exit(0);
980     }
981     if (!parse_file(CI_CONF.cfg_file)) {
982         ci_debug_printf(1, "Error opening/parsing config file\n");
983         exit(0);
984     }
985     return 1;
986 }
987 
config_destroy()988 void config_destroy()
989 {
990     ci_cfg_lib_destroy();
991 }
992 
993 void cfg_default_value_restore_all();
reconfig()994 int reconfig()
995 {
996     /*reseting all parameters to default values ... */
997     cfg_default_value_restore_all();
998     /*reseting cfg_lib */
999     ci_cfg_lib_reset();
1000     if (!ci_args_apply(ARGC, ARGV, options)) {
1001         ci_debug_printf(1,
1002                         "Error in command line options, while reconfiguring!\n");
1003         return 0;
1004     }
1005     if (!parse_file(CI_CONF.cfg_file)) {
1006         ci_debug_printf(1,
1007                         "Error opening/parsing config file, while reconfiguring!\n");
1008         return 0;
1009     }
1010     return 1;
1011 
1012 }
1013 
1014 
1015 int init_server();
1016 void release_modules();
1017 void ci_dlib_closeall();
1018 int log_open();
1019 void ci_magic_db_free();
1020 void reset_http_auth();
1021 
system_shutdown()1022 void system_shutdown()
1023 {
1024     /*
1025       - reset commands table
1026     */
1027     commands_reset();
1028 
1029     /*
1030      - clean registry
1031     */
1032     ci_registry_clean();
1033 
1034     /*
1035       - close/release services and modules
1036     */
1037     release_services();
1038     release_modules();
1039     ci_dlib_closeall();
1040 
1041     /*
1042         Release other subsystems
1043      */
1044     ci_magic_db_free();
1045     CI_CONF.MAGIC_DB = NULL;
1046     ci_txt_template_close();
1047 #ifdef USE_OPENSSL
1048     ci_tls_cleanup();
1049 #endif
1050 }
1051 
system_reconfigure()1052 int system_reconfigure()
1053 {
1054     ci_vector_t *old_ports;
1055     ci_debug_printf(1, "Going to reconfigure system!\n");
1056 
1057     old_ports = CI_CONF.PORTS;
1058     CI_CONF.PORTS = NULL;
1059 
1060     system_shutdown();
1061     reset_conf_tables();
1062     ci_acl_reset();
1063     reset_http_auth();
1064 
1065     ci_debug_printf(1, "All resources released. Going to reload!\n");
1066     ci_txt_template_init();
1067     if (!(CI_CONF.MAGIC_DB = ci_magic_db_load(CI_CONF.magics_file))) {
1068         ci_debug_printf(1, "Can not load magic file %s!!!\n",
1069                         CI_CONF.magics_file);
1070     }
1071     init_modules();
1072     init_services();
1073 
1074     /*
1075        - Freeing all memory and resources used by configuration parameters (is it possible???)
1076        - reopen and read config file. Now the monitor process has now the new config parameters.
1077      */
1078     if (!reconfig())
1079         return 0;
1080 
1081     /*Check the ports, to not close and reopen ports unchanged ports.*/
1082     ci_port_handle_reconfigure(CI_CONF.PORTS, old_ports);
1083     ci_port_list_release(old_ports);
1084 
1085     /*
1086        - reinit listen socket if needed
1087      */
1088     if (!init_server())
1089         return 0;
1090 
1091     log_open();
1092 
1093     /*
1094        - post_init services and modules
1095      */
1096     post_init_modules();
1097     post_init_services();
1098     return 1;
1099 }
1100 
1101 /**************************************************************************/
1102 /*         Library functions                                              */
1103 
1104 /*********************************************************************/
1105 /* Implementation of a mechanism to keep default values of parameters*/
1106 
1107 struct cfg_default_value *default_values = NULL;
1108 
1109 /*We does not care about memory managment here.  Default values list created only
1110   once at the beggining of c-icap and does not needed to free or reallocate memory... I think ...
1111 */
cfg_default_value_store(void * param,void * value,int size)1112 struct cfg_default_value *cfg_default_value_store(void *param, void *value,
1113         int size)
1114 {
1115     struct cfg_default_value *dval, *dval_search;
1116 
1117     if ((dval = cfg_default_value_search(param)))
1118         return dval;
1119 
1120     if (!(dval = malloc(sizeof(struct cfg_default_value))))
1121         return 0;
1122     dval->param = param;       /*Iam sure we can just set it to param_name, but..... */
1123     dval->size = size;
1124     if (!(dval->value = malloc(size))) {
1125         free(dval);
1126         return NULL;
1127     }
1128     memcpy(dval->value, value, size);
1129     dval->next = NULL;
1130     if (default_values == NULL) {
1131         default_values = dval;
1132         return dval;
1133     }
1134     dval_search = default_values;
1135     while (dval_search->next != NULL)
1136         dval_search = dval_search->next;
1137     dval_search->next = dval;
1138     return dval;
1139 }
1140 
cfg_default_value_replace(void * param,void * value)1141 struct cfg_default_value *cfg_default_value_replace(void *param, void *value)
1142 {
1143     struct cfg_default_value *dval;
1144     dval = default_values;
1145     while (dval != NULL && dval->param != param)
1146         dval = dval->next;
1147 
1148     if (!dval)
1149         return NULL;
1150 
1151     memcpy(dval->value, value, dval->size);
1152     return dval;
1153 }
1154 
cfg_default_value_search(void * param)1155 struct cfg_default_value *cfg_default_value_search(void *param)
1156 {
1157     struct cfg_default_value *dval;
1158     dval = default_values;
1159     ci_debug_printf(8, "Searching %p for default value\n", param);
1160     while (dval != NULL && dval->param != param)
1161         dval = dval->next;
1162     return dval;
1163 }
1164 
cfg_default_value_restore(void * param)1165 void *cfg_default_value_restore(void *param)
1166 {
1167     struct cfg_default_value *dval;
1168     dval = default_values;
1169     ci_debug_printf(8, "Geting default value for %p\n", param);
1170     while (dval != NULL && dval->param != param)
1171         dval = dval->next;
1172 
1173     if (!dval)
1174         return NULL;
1175     ci_debug_printf(8, "Found: %p\n", dval->value);
1176     memcpy(param, dval->value, dval->size);
1177     return param;
1178 }
1179 
cfg_default_value_restore_all()1180 void cfg_default_value_restore_all()
1181 {
1182     struct cfg_default_value *dval;
1183     dval = default_values;
1184     while (dval != NULL) {
1185         memcpy(dval->param, dval->value, dval->size);
1186         dval = dval->next;
1187     }
1188 }
1189 
1190 /********************************************************************/
1191 /* functions for setting parameters and saving the default values   */
1192 
intl_cfg_set_str(const char * directive,const char ** argv,void * setdata)1193 int intl_cfg_set_str(const char *directive, const char **argv, void *setdata)
1194 {
1195     if (!setdata)
1196         return 0;
1197     cfg_default_value_store(setdata, setdata, sizeof(char *));
1198     /*or better keep all string not just the pointer to default value? */
1199     return ci_cfg_set_str(directive, argv, setdata);
1200 }
1201 
intl_cfg_set_int(const char * directive,const char ** argv,void * setdata)1202 int intl_cfg_set_int(const char *directive, const char **argv, void *setdata)
1203 {
1204     if (!setdata)
1205         return 0;
1206     cfg_default_value_store(setdata, setdata, sizeof(int));
1207     return ci_cfg_set_int(directive, argv, setdata);
1208 }
1209 
intl_cfg_onoff(const char * directive,const char ** argv,void * setdata)1210 int intl_cfg_onoff(const char *directive, const char **argv, void *setdata)
1211 {
1212     if (!setdata)
1213         return 0;
1214     cfg_default_value_store(setdata, setdata, sizeof(int));
1215     return ci_cfg_onoff(directive, argv, setdata);
1216 }
1217 
intl_cfg_disable(const char * directive,const char ** argv,void * setdata)1218 int intl_cfg_disable(const char *directive, const char **argv, void *setdata)
1219 {
1220     if (!setdata)
1221         return 0;
1222     cfg_default_value_store(setdata, setdata, sizeof(int));
1223     return ci_cfg_disable(directive, argv, setdata);
1224 }
1225 
intl_cfg_enable(const char * directive,const char ** argv,void * setdata)1226 int intl_cfg_enable(const char *directive, const char **argv, void *setdata)
1227 {
1228     if (!setdata)
1229         return 0;
1230     cfg_default_value_store(setdata, setdata, sizeof(int));
1231     return ci_cfg_enable(directive, argv, setdata);
1232 }
1233 
intl_cfg_size_off(const char * directive,const char ** argv,void * setdata)1234 int intl_cfg_size_off(const char *directive, const char **argv, void *setdata)
1235 {
1236     if (!setdata)
1237         return 0;
1238     cfg_default_value_store(setdata, setdata, sizeof(ci_off_t));
1239     return ci_cfg_size_off(directive, argv, setdata);
1240 }
1241 
intl_cfg_size_long(const char * directive,const char ** argv,void * setdata)1242 int intl_cfg_size_long(const char *directive, const char **argv, void *setdata)
1243 {
1244     if (!setdata)
1245         return 0;
1246     cfg_default_value_store(setdata, setdata, sizeof(long int));
1247     return ci_cfg_size_long(directive, argv, setdata);
1248 }
1249