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