]> git.ipfire.org Git - thirdparty/squid.git/blame - src/cache_cf.cc
Bug #1057: New options to refresh-pattern configuration
[thirdparty/squid.git] / src / cache_cf.cc
CommitLineData
be335c22 1
30a4f2a8 2/*
38f9c547 3 * $Id: cache_cf.cc,v 1.456 2004/11/06 22:20:47 hno Exp $
30a4f2a8 4 *
5 * DEBUG: section 3 Configuration File Parsing
6 * AUTHOR: Harvest Derived
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 9 * ----------------------------------------------------------
30a4f2a8 10 *
2b6662ba 11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
30a4f2a8 19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
cbdec147 32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 33 *
30a4f2a8 34 */
cf5fd929 35
44a47c6e 36#include "squid.h"
e6ccf245 37#include "authenticate.h"
f5691f9c 38#include "AuthConfig.h"
39#include "AuthScheme.h"
e6ccf245 40#include "Store.h"
d3b3ab85 41#include "SwapDir.h"
a80a77cf 42#include "ConfigParser.h"
8000a965 43#include "ACL.h"
59b2d47f 44#include "StoreFileSystem.h"
1df370e3 45
46#if SQUID_SNMP
a97cfa48 47#include "snmp.h"
1df370e3 48#endif
43ae1d95 49#if ESI
50#include "ESIParser.h"
51#endif
090089c4 52
f5691f9c 53CBDATA_TYPE(peer);
54
8813e606 55static const char *const T_SECOND_STR = "second";
56static const char *const T_MINUTE_STR = "minute";
57static const char *const T_HOUR_STR = "hour";
58static const char *const T_DAY_STR = "day";
59static const char *const T_WEEK_STR = "week";
60static const char *const T_FORTNIGHT_STR = "fortnight";
61static const char *const T_MONTH_STR = "month";
62static const char *const T_YEAR_STR = "year";
63static const char *const T_DECADE_STR = "decade";
aa0a0c7c 64
9906e724 65static const char *const B_BYTES_STR = "bytes";
66static const char *const B_KBYTES_STR = "KB";
67static const char *const B_MBYTES_STR = "MB";
68static const char *const B_GBYTES_STR = "GB";
69
4db43fab 70static const char *const list_sep = ", \t\n\r";
b0e7d2d5 71
7684c4b1 72static void parse_logformat(logformat ** logformat_definitions);
73static void parse_access_log(customlog ** customlog_definitions);
d64bef4c 74static int check_null_access_log(customlog *customlog_definitions);
75
7684c4b1 76static void dump_logformat(StoreEntry * entry, const char *name, logformat * definitions);
77static void dump_access_log(StoreEntry * entry, const char *name, customlog * definitions);
78static void free_logformat(logformat ** definitions);
79static void free_access_log(customlog ** definitions);
80
62e76326 81
b0e7d2d5 82
97474590 83
cd748f27 84static void update_maxobjsize(void);
f5b8bbc4 85static void configDoConfigure(void);
86static void parse_refreshpattern(refresh_t **);
87static int parseTimeUnits(const char *unit);
88static void parseTimeLine(time_t * tptr, const char *units);
59715b38 89static void parse_ushort(u_short * var);
f5b8bbc4 90static void parse_string(char **);
f5b8bbc4 91static void default_all(void);
92static void defaults_if_none(void);
93static int parse_line(char *);
94static void parseBytesLine(size_t * bptr, const char *units);
95static size_t parseBytesUnits(const char *unit);
f5b8bbc4 96static void free_all(void);
94439e4e 97void requirePathnameExists(const char *name, const char *path);
ed7f5615 98static OBJH dump_config;
c26ffae9 99#if HTTP_VIOLATIONS
6bccf575 100static void dump_http_header_access(StoreEntry * entry, const char *name, header_mangler header[]);
101static void parse_http_header_access(header_mangler header[]);
102static void free_http_header_access(header_mangler header[]);
103static void dump_http_header_replace(StoreEntry * entry, const char *name, header_mangler header[]);
104static void parse_http_header_replace(header_mangler * header);
105static void free_http_header_replace(header_mangler * header);
9e8b2f1c 106#endif
6bccf575 107static void parse_denyinfo(acl_deny_info_list ** var);
108static void dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var);
109static void free_denyinfo(acl_deny_info_list ** var);
3f38a55e 110#if CURRENTLY_UNUSED
7e3ce7b9 111static void parse_sockaddr_in_list(sockaddr_in_list **);
112static void dump_sockaddr_in_list(StoreEntry *, const char *, const sockaddr_in_list *);
113static void free_sockaddr_in_list(sockaddr_in_list **);
114static int check_null_sockaddr_in_list(const sockaddr_in_list *);
3f38a55e 115#endif /* CURRENTLY_UNUSED */
116static void parse_http_port_list(http_port_list **);
117static void dump_http_port_list(StoreEntry *, const char *, const http_port_list *);
118static void free_http_port_list(http_port_list **);
119#if UNUSED_CODE
120static int check_null_http_port_list(const http_port_list *);
52f772de 121#endif
d193a436 122#if USE_SSL
123static void parse_https_port_list(https_port_list **);
124static void dump_https_port_list(StoreEntry *, const char *, const https_port_list *);
125static void free_https_port_list(https_port_list **);
126#if 0
127static int check_null_https_port_list(const https_port_list *);
128#endif
129#endif /* USE_SSL */
ef1955a5 130static void parse_b_size_t(size_t * var);
270b86af 131
0e4e0e7d 132void
0673c0ba 133self_destruct(void)
090089c4 134{
137ee196 135 fatalf("Bungled %s line %d: %s",
62e76326 136 cfg_filename, config_lineno, config_input_line);
090089c4 137}
138
8203a132 139void
140wordlistDestroy(wordlist ** list)
0ffd22bc 141{
142 wordlist *w = NULL;
62e76326 143
79d39a72 144 while ((w = *list) != NULL) {
62e76326 145 *list = w->next;
146 safe_free(w->key);
147 memFree(w, MEM_WORDLIST);
0ffd22bc 148 }
62e76326 149
0ffd22bc 150 *list = NULL;
151}
152
858783c9 153const char *
fe4e214f 154wordlistAdd(wordlist ** list, const char *key)
090089c4 155{
c68e9c6b 156 while (*list)
62e76326 157 list = &(*list)->next;
158
e6ccf245 159 *list = static_cast<wordlist *>(memAllocate(MEM_WORDLIST));
62e76326 160
c68e9c6b 161 (*list)->key = xstrdup(key);
62e76326 162
c68e9c6b 163 (*list)->next = NULL;
62e76326 164
858783c9 165 return (*list)->key;
166}
167
168void
a4b8110e 169wordlistJoin(wordlist ** list, wordlist ** wl)
858783c9 170{
171 while (*list)
62e76326 172 list = &(*list)->next;
173
858783c9 174 *list = *wl;
62e76326 175
858783c9 176 *wl = NULL;
177}
178
179void
a4b8110e 180wordlistAddWl(wordlist ** list, wordlist * wl)
858783c9 181{
182 while (*list)
62e76326 183 list = &(*list)->next;
184
a4b8110e 185 for (; wl; wl = wl->next, list = &(*list)->next) {
62e76326 186 *list = static_cast<wordlist *>(memAllocate(MEM_WORDLIST));
187 (*list)->key = xstrdup(wl->key);
188 (*list)->next = NULL;
858783c9 189 }
090089c4 190}
191
137ee196 192void
eeb423fb 193wordlistCat(const wordlist * w, MemBuf * mb)
5da06f20 194{
5da06f20 195 while (NULL != w) {
62e76326 196 memBufPrintf(mb, "%s\n", w->key);
197 w = w->next;
5da06f20 198 }
5da06f20 199}
200
6b8e7481 201wordlist *
202wordlistDup(const wordlist * w)
203{
204 wordlist *D = NULL;
62e76326 205
6b8e7481 206 while (NULL != w) {
62e76326 207 wordlistAdd(&D, w->key);
208 w = w->next;
6b8e7481 209 }
62e76326 210
6b8e7481 211 return D;
212}
213
3c5557f9 214/*
5c20d6fa 215 * These functions is the same as atoi/l/f, except that they check for errors
3c5557f9 216 */
090089c4 217
59b2d47f 218long
5c20d6fa 219xatol(const char *token)
220{
221 char *end;
222 long ret = strtol(token, &end, 10);
62e76326 223
5c20d6fa 224 if (ret == 0 && end == token)
62e76326 225 self_destruct();
226
5c20d6fa 227 return ret;
228}
229
59b2d47f 230int
5c20d6fa 231xatoi(const char *token)
232{
233 return xatol(token);
234}
235
236static double
237xatof(const char *token)
238{
239 char *end;
240 double ret = strtod(token, &end);
62e76326 241
5c20d6fa 242 if (ret == 0 && end == token)
62e76326 243 self_destruct();
244
5c20d6fa 245 return ret;
246}
247
0e4e0e7d 248int
249GetInteger(void)
250{
251 char *token = strtok(NULL, w_space);
252 int i;
62e76326 253
0e4e0e7d 254 if (token == NULL)
62e76326 255 self_destruct();
256
0e4e0e7d 257 if (sscanf(token, "%d", &i) != 1)
62e76326 258 self_destruct();
259
0e4e0e7d 260 return i;
261}
090089c4 262
cd748f27 263static void
264update_maxobjsize(void)
265{
266 int i;
e8dbac8b 267 ssize_t ms = -1;
cd748f27 268
269 for (i = 0; i < Config.cacheSwap.n_configured; i++) {
62e76326 270 assert (Config.cacheSwap.swapDirs[i]);
271
272 if (Config.cacheSwap.swapDirs[i]->max_objsize > ms)
273 ms = Config.cacheSwap.swapDirs[i]->max_objsize;
cd748f27 274 }
62e76326 275
cd748f27 276 store_maxobjsize = ms;
277}
278
76b9daa5 279static void
280SetConfigFilename(char const *file_name, bool is_pipe)
281{
282 cfg_filename = file_name;
283
284 char const *token;
285
286 if (is_pipe)
287 cfg_filename = file_name + 1;
288 else if ((token = strrchr(cfg_filename, '/')))
289 cfg_filename = token + 1;
290}
291
270b86af 292int
293parseConfigFile(const char *file_name)
2546fcb3 294{
270b86af 295 FILE *fp = NULL;
296 char *token = NULL;
72121e8b 297 char *tmp_line;
e13ee7ad 298 int err_count = 0;
1741cbad 299 int is_pipe = 0;
42bf7c64 300 configFreeMemory();
0153d498 301 default_all();
62e76326 302
1741cbad 303 if (file_name[0] == '!' || file_name[0] == '|') {
62e76326 304 fp = popen(file_name + 1, "r");
305 is_pipe = 1;
1741cbad 306 } else {
62e76326 307 fp = fopen(file_name, "r");
1741cbad 308 }
62e76326 309
1741cbad 310 if (fp == NULL)
62e76326 311 fatalf("Unable to open configuration file: %s: %s",
312 file_name, xstrerror());
313
ec4daaa5 314#ifdef _SQUID_WIN32_
62e76326 315
c4aefe96 316 setmode(fileno(fp), O_TEXT);
62e76326 317
c4aefe96 318#endif
62e76326 319
76b9daa5 320 SetConfigFilename(file_name, bool(is_pipe));
62e76326 321
270b86af 322 memset(config_input_line, '\0', BUFSIZ);
62e76326 323
270b86af 324 config_lineno = 0;
62e76326 325
270b86af 326 while (fgets(config_input_line, BUFSIZ, fp)) {
62e76326 327 config_lineno++;
328
329 if ((token = strchr(config_input_line, '\n')))
330 *token = '\0';
331
332 if (strncmp(config_input_line, "#line ", 6) == 0) {
333 static char new_file_name[1024];
334 static char *file;
335 static char new_lineno;
336 token = config_input_line + 6;
337 new_lineno = strtol(token, &file, 0) - 1;
338
339 if (file == token)
340 continue; /* Not a valid #line directive, may be a comment */
341
342 while (*file && isspace((unsigned char) *file))
343 file++;
344
345 if (*file) {
346 if (*file != '"')
347 continue; /* Not a valid #line directive, may be a comment */
348
349 xstrncpy(new_file_name, file + 1, sizeof(new_file_name));
350
351 if ((token = strchr(new_file_name, '"')))
352 *token = '\0';
353
354 cfg_filename = new_file_name;
355
1741cbad 356#if PROBABLY_NOT_WANTED_HERE
62e76326 357
76b9daa5 358 SetConfigFilename(cfg_filename, false);
62e76326 359
1741cbad 360#endif
62e76326 361
362 }
363
364 config_lineno = new_lineno;
365 }
366
367 if (config_input_line[0] == '#')
368 continue;
369
370 if (config_input_line[0] == '\0')
371 continue;
372
373 debug(3, 5) ("Processing: '%s'\n", config_input_line);
374
375 tmp_line = xstrdup(config_input_line);
376
377 if (!parse_line(tmp_line)) {
378 debug(3, 0) ("parseConfigFile: '%s' line %d unrecognized: '%s'\n",
379 cfg_filename,
380 config_lineno,
381 config_input_line);
382 err_count++;
383 }
384
385 safe_free(tmp_line);
270b86af 386 }
62e76326 387
1741cbad 388 if (is_pipe) {
62e76326 389 int ret = pclose(fp);
390
391 if (ret != 0)
392 fatalf("parseConfigFile: '%s' failed with exit code %d\n", file_name, ret);
1741cbad 393 } else {
62e76326 394 fclose(fp);
1741cbad 395 }
62e76326 396
f0b19334 397 defaults_if_none();
398 configDoConfigure();
22f3fd98 399 cachemgrRegister("config",
62e76326 400 "Current Squid Configuration",
401 dump_config,
402 1, 1);
e13ee7ad 403 return err_count;
f0b19334 404}
270b86af 405
f0b19334 406static void
407configDoConfigure(void)
408{
f0b19334 409 memset(&Config2, '\0', sizeof(SquidConfig2));
7021844c 410 /* init memory as early as possible */
411 memConfigure();
270b86af 412 /* Sanity checks */
62e76326 413
a95856a0 414 if (Config.cacheSwap.swapDirs == NULL)
62e76326 415 fatal("No cache_dir's specified in config file");
416
9fa8263f 417 /* calculate Config.Swap.maxSize */
f4e3fa54 418 storeDirConfigure();
62e76326 419
82e2afd9 420 if (0 == Config.Swap.maxSize)
62e76326 421 /* people might want a zero-sized cache on purpose */
422 (void) 0;
82e2afd9 423 else if (Config.Swap.maxSize < (Config.memMaxSize >> 10))
62e76326 424 debug(3, 0) ("WARNING cache_mem is larger than total disk cache space!\n");
425
84f42bac 426 if (Config.Announce.period > 0) {
62e76326 427 Config.onoff.announce = 1;
84f42bac 428 } else if (Config.Announce.period < 1) {
62e76326 429 Config.Announce.period = 86400 * 365; /* one year */
430 Config.onoff.announce = 0;
270b86af 431 }
62e76326 432
6b53c392 433#if USE_DNSSERVERS
f0b19334 434 if (Config.dnsChildren < 1)
62e76326 435 fatal("No dnsservers allocated");
436
efd900cb 437#endif
62e76326 438
270b86af 439 if (Config.Program.redirect) {
62e76326 440 if (Config.redirectChildren < 1) {
441 Config.redirectChildren = 0;
442 wordlistDestroy(&Config.Program.redirect);
443 }
fea2e6e0 444 }
62e76326 445
f1dc9b30 446 if (Config.appendDomain)
62e76326 447 if (*Config.appendDomain != '.')
448 fatal("append_domain must begin with a '.'");
449
270b86af 450 if (Config.errHtmlText == NULL)
62e76326 451 Config.errHtmlText = xstrdup(null_string);
452
270b86af 453 storeConfigure();
62e76326 454
52f772de 455 snprintf(ThisCache, sizeof(ThisCache), "%s (%s)",
62e76326 456 uniqueHostname(),
457 full_appname_string);
fbdba7c4 458
38a6c74e 459 /*
460 * the extra space is for loop detection in client_side.c -- we search
461 * for substrings in the Via header.
462 */
52f772de 463 snprintf(ThisCache2, sizeof(ThisCache), " %s (%s)",
62e76326 464 uniqueHostname(),
465 full_appname_string);
466
270b86af 467 if (!Config.udpMaxHitObjsz || Config.udpMaxHitObjsz > SQUID_UDP_SO_SNDBUF)
62e76326 468 Config.udpMaxHitObjsz = SQUID_UDP_SO_SNDBUF;
469
270b86af 470 if (Config.appendDomain)
62e76326 471 Config.appendDomainLen = strlen(Config.appendDomain);
270b86af 472 else
62e76326 473 Config.appendDomainLen = 0;
474
f1dc9b30 475 safe_free(debug_options)
62e76326 476 debug_options = xstrdup(Config.debugOptions);
477
22c653cd 478 if (Config.retry.maxtries > 10)
62e76326 479 fatal("maximum_single_addr_tries cannot be larger than 10");
480
22c653cd 481 if (Config.retry.maxtries < 1) {
62e76326 482 debug(3, 0) ("WARNING: resetting 'maximum_single_addr_tries to 1\n");
483 Config.retry.maxtries = 1;
5210854d 484 }
62e76326 485
f0b19334 486 requirePathnameExists("MIME Config Table", Config.mimeTablePathname);
6b53c392 487#if USE_DNSSERVERS
62e76326 488
f0b19334 489 requirePathnameExists("cache_dns_program", Config.Program.dnsserver);
efd900cb 490#endif
a3d0a19d 491#if USE_UNLINKD
62e76326 492
f0b19334 493 requirePathnameExists("unlinkd_program", Config.Program.unlinkd);
a3d0a19d 494#endif
62e76326 495
f0b19334 496 if (Config.Program.redirect)
62e76326 497 requirePathnameExists("redirect_program", Config.Program.redirect->key);
498
f0b19334 499 requirePathnameExists("Icon Directory", Config.icons.directory);
62e76326 500
f0b19334 501 requirePathnameExists("Error Directory", Config.errorDirectory);
62e76326 502
9f60cfdf 503#if HTTP_VIOLATIONS
62e76326 504
9f60cfdf 505 {
62e76326 506 const refresh_t *R;
507
508 for (R = Config.Refresh; R; R = R->next)
509 {
510 if (!R->flags.override_expire)
511 continue;
512
513 debug(22, 1) ("WARNING: use of 'override-expire' in 'refresh_pattern' violates HTTP\n");
514
515 break;
516 }
517
518 for (R = Config.Refresh; R; R = R->next)
519 {
520 if (!R->flags.override_lastmod)
521 continue;
522
523 debug(22, 1) ("WARNING: use of 'override-lastmod' in 'refresh_pattern' violates HTTP\n");
524
525 break;
526 }
527
38f9c547 528 for (R = Config.Refresh; R; R = R->next)
529 {
530 if (!R->flags.reload_into_ims)
531 continue;
532
533 debug(22, 1) ("WARNING: use of 'reload-into-ims' in 'refresh_pattern' violates HTTP\n");
534
535 break;
536 }
537
538 for (R = Config.Refresh; R; R = R->next)
539 {
540 if (!R->flags.ignore_reload)
541 continue;
542
543 debug(22, 1) ("WARNING: use of 'ignore-reload' in 'refresh_pattern' violates HTTP\n");
544
545 break;
546 }
547
548 for (R = Config.Refresh; R; R = R->next)
549 {
550 if (!R->flags.ignore_no_cache)
551 continue;
552
553 debug(22, 1) ("WARNING: use of 'ignore-no-cache' in 'refresh_pattern' violates HTTP\n");
554
555 break;
556 }
557
558 for (R = Config.Refresh; R; R = R->next)
559 {
560 if (!R->flags.ignore_no_store)
561 continue;
562
563 debug(22, 1) ("WARNING: use of 'ignore-no-store' in 'refresh_pattern' violates HTTP\n");
564
565 break;
566 }
567
568 for (R = Config.Refresh; R; R = R->next)
569 {
570 if (!R->flags.ignore_private)
571 continue;
572
573 debug(22, 1) ("WARNING: use of 'ignore-private' in 'refresh_pattern' violates HTTP\n");
574
575 break;
576 }
577
578 for (R = Config.Refresh; R; R = R->next)
579 {
580 if (!R->flags.ignore_auth)
581 continue;
582
583 debug(22, 1) ("WARNING: use of 'ignore-auth' in 'refresh_pattern' violates HTTP\n");
584
585 break;
586 }
587
9f60cfdf 588 }
c2f5c744 589#endif
590#if !HTTP_VIOLATIONS
591 Config.onoff.via = 1;
592#else
62e76326 593
c2f5c744 594 if (!Config.onoff.via)
62e76326 595 debug(22, 1) ("WARNING: HTTP requires the use of Via\n");
596
9f60cfdf 597#endif
62e76326 598
db1cd23c 599 if (Config.Wais.relayHost) {
62e76326 600 if (Config.Wais._peer)
601 cbdataFree(Config.Wais._peer);
602
f5691f9c 603 CBDATA_INIT_TYPE_FREECB(peer, peerDestroy);
604
62e76326 605 Config.Wais._peer = cbdataAlloc(peer);
606
607 Config.Wais._peer->host = xstrdup(Config.Wais.relayHost);
608
609 Config.Wais._peer->http_port = Config.Wais.relayPort;
db1cd23c 610 }
62e76326 611
53cb32a9 612 if (aclPurgeMethodInUse(Config.accessList.http))
62e76326 613 Config2.onoff.enable_purge = 1;
614
8749fa47 615 if (geteuid() == 0) {
62e76326 616 if (NULL != Config.effectiveUser) {
617
618 struct passwd *pwd = getpwnam(Config.effectiveUser);
619
620 if (NULL == pwd)
621 /*
622 * Andres Kroonmaa <andre@online.ee>:
623 * Some getpwnam() implementations (Solaris?) require
624 * an available FD < 256 for opening a FILE* to the
625 * passwd file.
626 * DW:
627 * This should be safe at startup, but might still fail
628 * during reconfigure.
629 */
630 fatalf("getpwnam failed to find userid for effective user '%s'",
631 Config.effectiveUser);
632
633 Config2.effectiveUserID = pwd->pw_uid;
634
635 Config2.effectiveGroupID = pwd->pw_gid;
636 }
8749fa47 637 } else {
62e76326 638 Config2.effectiveUserID = geteuid();
639 Config2.effectiveGroupID = getegid();
d20b1cd0 640 }
62e76326 641
d20b1cd0 642 if (NULL != Config.effectiveGroup) {
62e76326 643
644 struct group *grp = getgrnam(Config.effectiveGroup);
645
646 if (NULL == grp)
647 fatalf("getgrnam failed to find groupid for effective group '%s'",
648 Config.effectiveGroup);
649
650 Config2.effectiveGroupID = grp->gr_gid;
d20b1cd0 651 }
62e76326 652
56fe752e 653 urlExtMethodConfigure();
a7ad6e4e 654#if USE_SSL
62e76326 655
b0dd28ba 656 Config.ssl_client.sslContext = sslCreateClientContext(Config.ssl_client.cert, Config.ssl_client.key, Config.ssl_client.version, Config.ssl_client.cipher, Config.ssl_client.options, Config.ssl_client.flags, Config.ssl_client.cafile, Config.ssl_client.capath);
a7ad6e4e 657#endif
090089c4 658}
659
270b86af 660/* Parse a time specification from the config file. Store the
f1dc9b30 661 * result in 'tptr', after converting it to 'units' */
8203a132 662static void
a47b9029 663parseTimeLine(time_t * tptr, const char *units)
090089c4 664{
665 char *token;
270b86af 666 double d;
f1dc9b30 667 time_t m;
668 time_t u;
62e76326 669
270b86af 670 if ((u = parseTimeUnits(units)) == 0)
62e76326 671 self_destruct();
672
270b86af 673 if ((token = strtok(NULL, w_space)) == NULL)
62e76326 674 self_destruct();
675
5c20d6fa 676 d = xatof(token);
62e76326 677
270b86af 678 m = u; /* default to 'units' if none specified */
62e76326 679
10738561 680 if (0 == d)
62e76326 681 (void) 0;
10738561 682 else if ((token = strtok(NULL, w_space)) == NULL)
62e76326 683 debug(3, 0) ("WARNING: No units on '%s', assuming %f %s\n",
684 config_input_line, d, units);
9e975e4e 685 else if ((m = parseTimeUnits(token)) == 0)
62e76326 686 self_destruct();
687
e6ccf245 688 *tptr = static_cast<time_t> (m * d / u);
090089c4 689}
690
270b86af 691static int
692parseTimeUnits(const char *unit)
693{
694 if (!strncasecmp(unit, T_SECOND_STR, strlen(T_SECOND_STR)))
62e76326 695 return 1;
696
270b86af 697 if (!strncasecmp(unit, T_MINUTE_STR, strlen(T_MINUTE_STR)))
62e76326 698 return 60;
699
270b86af 700 if (!strncasecmp(unit, T_HOUR_STR, strlen(T_HOUR_STR)))
62e76326 701 return 3600;
702
270b86af 703 if (!strncasecmp(unit, T_DAY_STR, strlen(T_DAY_STR)))
62e76326 704 return 86400;
705
270b86af 706 if (!strncasecmp(unit, T_WEEK_STR, strlen(T_WEEK_STR)))
62e76326 707 return 86400 * 7;
708
270b86af 709 if (!strncasecmp(unit, T_FORTNIGHT_STR, strlen(T_FORTNIGHT_STR)))
62e76326 710 return 86400 * 14;
711
270b86af 712 if (!strncasecmp(unit, T_MONTH_STR, strlen(T_MONTH_STR)))
62e76326 713 return 86400 * 30;
714
270b86af 715 if (!strncasecmp(unit, T_YEAR_STR, strlen(T_YEAR_STR)))
62e76326 716 return static_cast<int>(86400 * 365.2522);
717
270b86af 718 if (!strncasecmp(unit, T_DECADE_STR, strlen(T_DECADE_STR)))
62e76326 719 return static_cast<int>(86400 * 365.2522 * 10);
720
270b86af 721 debug(3, 1) ("parseTimeUnits: unknown time unit '%s'\n", unit);
62e76326 722
270b86af 723 return 0;
724}
725
9906e724 726static void
9e975e4e 727parseBytesLine(size_t * bptr, const char *units)
9906e724 728{
729 char *token;
730 double d;
731 size_t m;
732 size_t u;
62e76326 733
9906e724 734 if ((u = parseBytesUnits(units)) == 0)
62e76326 735 self_destruct();
736
9906e724 737 if ((token = strtok(NULL, w_space)) == NULL)
62e76326 738 self_destruct();
739
f8ecd7d7 740 if (strcmp(token, "none") == 0 || strcmp(token, "-1") == 0) {
b2d729e6 741 *bptr = static_cast<size_t>(-1);
ef1955a5 742 return;
743 }
744
5c20d6fa 745 d = xatof(token);
62e76326 746
9906e724 747 m = u; /* default to 'units' if none specified */
62e76326 748
343f47a3 749 if (0.0 == d)
62e76326 750 (void) 0;
4860dc1b 751 else if ((token = strtok(NULL, w_space)) == NULL)
62e76326 752 debug(3, 0) ("WARNING: No units on '%s', assuming %f %s\n",
753 config_input_line, d, units);
9e975e4e 754 else if ((m = parseBytesUnits(token)) == 0)
62e76326 755 self_destruct();
756
e6ccf245 757 *bptr = static_cast<size_t>(m * d / u);
347ae7c4 758
759 if (static_cast<double>(*bptr) != m * d / u)
760 self_destruct();
9906e724 761}
762
763static size_t
764parseBytesUnits(const char *unit)
765{
766 if (!strncasecmp(unit, B_BYTES_STR, strlen(B_BYTES_STR)))
62e76326 767 return 1;
768
9906e724 769 if (!strncasecmp(unit, B_KBYTES_STR, strlen(B_KBYTES_STR)))
62e76326 770 return 1 << 10;
771
9906e724 772 if (!strncasecmp(unit, B_MBYTES_STR, strlen(B_MBYTES_STR)))
62e76326 773 return 1 << 20;
774
9906e724 775 if (!strncasecmp(unit, B_GBYTES_STR, strlen(B_GBYTES_STR)))
62e76326 776 return 1 << 30;
777
9906e724 778 debug(3, 1) ("parseBytesUnits: unknown bytes unit '%s'\n", unit);
62e76326 779
9906e724 780 return 0;
781}
782
270b86af 783/*****************************************************************************
784 * Max
785 *****************************************************************************/
786
8203a132 787static void
97427e90 788dump_acl(StoreEntry * entry, const char *name, ACL * ae)
090089c4 789{
56b63fa1 790 wordlist *w;
791 wordlist *v;
62e76326 792
9ef28b60 793 while (ae != NULL) {
62e76326 794 debug(3, 3) ("dump_acl: %s %s\n", name, ae->name);
795 storeAppendPrintf(entry, "%s %s %s ",
796 name,
797 ae->name,
798 ae->typeString());
799 v = w = ae->dumpGeneric();
800
801 while (v != NULL) {
802 debug(3, 3) ("dump_acl: %s %s %s\n", name, ae->name, v->key);
803 storeAppendPrintf(entry, "%s ", v->key);
804 v = v->next;
805 }
806
807 storeAppendPrintf(entry, "\n");
808 wordlistDestroy(&w);
809 ae = ae->next;
56b63fa1 810 }
090089c4 811}
812
8203a132 813static void
97427e90 814parse_acl(ACL ** ae)
090089c4 815{
8000a965 816 ACL::ParseAclLine(ae);
f1dc9b30 817}
818
819static void
97427e90 820free_acl(ACL ** ae)
f1dc9b30 821{
9ef28b60 822 aclDestroyAcls(ae);
090089c4 823}
824
8203a132 825static void
d6827718 826dump_acl_list(StoreEntry * entry, acl_list * head)
30a4f2a8 827{
56b63fa1 828 acl_list *l;
62e76326 829
d6827718 830 for (l = head; l; l = l->next) {
62e76326 831 storeAppendPrintf(entry, " %s%s",
832 l->op ? null_string : "!",
833 l->_acl->name);
d6827718 834 }
835}
836
b67e2c8c 837void
d6827718 838dump_acl_access(StoreEntry * entry, const char *name, acl_access * head)
839{
840 acl_access *l;
62e76326 841
d6827718 842 for (l = head; l; l = l->next) {
62e76326 843 storeAppendPrintf(entry, "%s %s",
844 name,
845 l->allow ? "Allow" : "Deny");
846 dump_acl_list(entry, l->aclList);
847 storeAppendPrintf(entry, "\n");
56b63fa1 848 }
30a4f2a8 849}
090089c4 850
8203a132 851static void
16300b58 852parse_acl_access(acl_access ** head)
090089c4 853{
270b86af 854 aclParseAccessLine(head);
090089c4 855}
856
0153d498 857static void
16300b58 858free_acl_access(acl_access ** head)
0153d498 859{
a47b9029 860 aclDestroyAccessList(head);
0153d498 861}
862
8203a132 863static void
62e76326 864
a7d59104 865dump_address(StoreEntry * entry, const char *name, struct in_addr addr)
270b86af 866{
f53b06f9 867 storeAppendPrintf(entry, "%s %s\n", name, inet_ntoa(addr));
270b86af 868}
869
870static void
62e76326 871
270b86af 872parse_address(struct in_addr *addr)
090089c4 873{
62e76326 874
0ee4272b 875 const struct hostent *hp;
270b86af 876 char *token = strtok(NULL, w_space);
877
30a4f2a8 878 if (token == NULL)
62e76326 879 self_destruct();
880
429fdbec 881 if (safe_inet_addr(token, addr) == 1)
62e76326 882 (void) 0;
ceb8994e 883 else if ((hp = gethostbyname(token))) /* dont use ipcache */
62e76326 884 *addr = inaddrFromHostent(hp);
30a4f2a8 885 else
62e76326 886 self_destruct();
090089c4 887}
888
0153d498 889static void
62e76326 890
0153d498 891free_address(struct in_addr *addr)
892{
62e76326 893
a47b9029 894 memset(addr, '\0', sizeof(struct in_addr));
0153d498 895}
896
d6827718 897CBDATA_TYPE(acl_address);
898
899static void
900dump_acl_address(StoreEntry * entry, const char *name, acl_address * head)
901{
902 acl_address *l;
62e76326 903
d6827718 904 for (l = head; l; l = l->next) {
62e76326 905 if (l->addr.s_addr != INADDR_ANY)
906 storeAppendPrintf(entry, "%s %s", name, inet_ntoa(l->addr));
907 else
908 storeAppendPrintf(entry, "%s autoselect", name);
909
910 dump_acl_list(entry, l->aclList);
911
912 storeAppendPrintf(entry, "\n");
d6827718 913 }
914}
915
916static void
917freed_acl_address(void *data)
918{
e6ccf245 919 acl_address *l = static_cast<acl_address *>(data);
29b8d8d6 920 aclDestroyAclList(&l->aclList);
d6827718 921}
922
923static void
924parse_acl_address(acl_address ** head)
925{
926 acl_address *l;
927 acl_address **tail = head; /* sane name below */
928 CBDATA_INIT_TYPE_FREECB(acl_address, freed_acl_address);
929 l = cbdataAlloc(acl_address);
930 parse_address(&l->addr);
29b8d8d6 931 aclParseAclList(&l->aclList);
62e76326 932
d6827718 933 while (*tail)
62e76326 934 tail = &(*tail)->next;
935
d6827718 936 *tail = l;
937}
938
939static void
940free_acl_address(acl_address ** head)
941{
942 while (*head) {
62e76326 943 acl_address *l = *head;
944 *head = l->next;
945 cbdataFree(l);
d6827718 946 }
947}
948
949CBDATA_TYPE(acl_tos);
950
951static void
952dump_acl_tos(StoreEntry * entry, const char *name, acl_tos * head)
953{
954 acl_tos *l;
62e76326 955
d6827718 956 for (l = head; l; l = l->next) {
62e76326 957 if (l->tos > 0)
958 storeAppendPrintf(entry, "%s 0x%02X", name, l->tos);
959 else
960 storeAppendPrintf(entry, "%s none", name);
961
962 dump_acl_list(entry, l->aclList);
963
964 storeAppendPrintf(entry, "\n");
d6827718 965 }
966}
967
968static void
969freed_acl_tos(void *data)
970{
e6ccf245 971 acl_tos *l = static_cast<acl_tos *>(data);
29b8d8d6 972 aclDestroyAclList(&l->aclList);
d6827718 973}
974
975static void
976parse_acl_tos(acl_tos ** head)
977{
978 acl_tos *l;
979 acl_tos **tail = head; /* sane name below */
980 int tos;
981 char junk;
982 char *token = strtok(NULL, w_space);
62e76326 983
d6827718 984 if (!token)
62e76326 985 self_destruct();
986
d6827718 987 if (sscanf(token, "0x%x%c", &tos, &junk) != 1)
62e76326 988 self_destruct();
989
d6827718 990 if (tos < 0 || tos > 255)
62e76326 991 self_destruct();
992
d6827718 993 CBDATA_INIT_TYPE_FREECB(acl_tos, freed_acl_tos);
62e76326 994
d6827718 995 l = cbdataAlloc(acl_tos);
62e76326 996
d6827718 997 l->tos = tos;
62e76326 998
29b8d8d6 999 aclParseAclList(&l->aclList);
62e76326 1000
d6827718 1001 while (*tail)
62e76326 1002 tail = &(*tail)->next;
1003
d6827718 1004 *tail = l;
1005}
1006
1007static void
1008free_acl_tos(acl_tos ** head)
1009{
1010 while (*head) {
62e76326 1011 acl_tos *l = *head;
1012 *head = l->next;
1013 l->next = NULL;
1014 cbdataFree(l);
d6827718 1015 }
1016}
1017
ef1955a5 1018CBDATA_TYPE(acl_size_t);
1019
1020static void
1021dump_acl_b_size_t(StoreEntry * entry, const char *name, acl_size_t * head)
1022{
1023 acl_size_t *l;
1024
1025 for (l = head; l; l = l->next) {
1026 if (l->size != static_cast<size_t>(-1))
1027 storeAppendPrintf(entry, "%s %d %s\n", name, (int) l->size, B_BYTES_STR);
1028 else
1029 storeAppendPrintf(entry, "%s none", name);
1030
1031 dump_acl_list(entry, l->aclList);
1032
1033 storeAppendPrintf(entry, "\n");
1034 }
1035}
1036
1037static void
1038freed_acl_b_size_t(void *data)
1039{
1040 acl_size_t *l = static_cast<acl_size_t *>(data);
1041 aclDestroyAclList(&l->aclList);
1042}
1043
1044static void
1045parse_acl_b_size_t(acl_size_t ** head)
1046{
1047 acl_size_t *l;
1048 acl_size_t **tail = head; /* sane name below */
1049
1050 CBDATA_INIT_TYPE_FREECB(acl_size_t, freed_acl_b_size_t);
1051
1052 l = cbdataAlloc(acl_size_t);
1053
1054 parse_b_size_t(&l->size);
1055
1056 aclParseAclList(&l->aclList);
1057
1058 while (*tail)
1059 tail = &(*tail)->next;
1060
1061 *tail = l;
1062}
1063
1064static void
1065free_acl_b_size_t(acl_size_t ** head)
1066{
1067 while (*head) {
1068 acl_size_t *l = *head;
1069 *head = l->next;
1070 l->next = NULL;
1071 cbdataFree(l);
1072 }
1073}
1074
59715b38 1075#if DELAY_POOLS
1076
b67e2c8c 1077#include "DelayPools.h"
1078#include "DelayConfig.h"
59715b38 1079/* do nothing - free_delay_pool_count is the magic free function.
1080 * this is why delay_pool_count isn't just marked TYPE: ushort
1081 */
1082#define free_delay_pool_class(X)
1083#define free_delay_pool_access(X)
1084#define free_delay_pool_rates(X)
1085#define dump_delay_pool_class(X, Y, Z)
1086#define dump_delay_pool_access(X, Y, Z)
1087#define dump_delay_pool_rates(X, Y, Z)
1088
1089static void
b67e2c8c 1090free_delay_pool_count(DelayConfig * cfg)
59715b38 1091{
b67e2c8c 1092 cfg->freePoolCount();
59715b38 1093}
1094
1095static void
b67e2c8c 1096dump_delay_pool_count(StoreEntry * entry, const char *name, DelayConfig &cfg)
59715b38 1097{
b67e2c8c 1098 cfg.dumpPoolCount (entry, name);
59715b38 1099}
1100
1101static void
b67e2c8c 1102parse_delay_pool_count(DelayConfig * cfg)
59715b38 1103{
b67e2c8c 1104 cfg->parsePoolCount();
59715b38 1105}
1106
1107static void
b67e2c8c 1108parse_delay_pool_class(DelayConfig * cfg)
59715b38 1109{
b67e2c8c 1110 cfg->parsePoolClass();
59715b38 1111}
1112
1113static void
b67e2c8c 1114parse_delay_pool_rates(DelayConfig * cfg)
59715b38 1115{
b67e2c8c 1116 cfg->parsePoolRates();
59715b38 1117}
1118
1119static void
b67e2c8c 1120parse_delay_pool_access(DelayConfig * cfg)
59715b38 1121{
b67e2c8c 1122 cfg->parsePoolAccess();
59715b38 1123}
62e76326 1124
59715b38 1125#endif
1126
c26ffae9 1127#if HTTP_VIOLATIONS
97474590 1128static void
6bccf575 1129dump_http_header_access(StoreEntry * entry, const char *name, header_mangler header[])
e3dd531e 1130{
efd900cb 1131 int i;
62e76326 1132
6bccf575 1133 for (i = 0; i < HDR_ENUM_END; i++) {
62e76326 1134 if (header[i].access_list != NULL) {
1135 storeAppendPrintf(entry, "%s ", name);
1136 dump_acl_access(entry, httpHeaderNameById(i),
1137 header[i].access_list);
1138 }
efd900cb 1139 }
97474590 1140}
e3dd531e 1141
97474590 1142static void
6bccf575 1143parse_http_header_access(header_mangler header[])
97474590 1144{
6bccf575 1145 int id, i;
97474590 1146 char *t = NULL;
62e76326 1147
97474590 1148 if ((t = strtok(NULL, w_space)) == NULL) {
62e76326 1149 debug(3, 0) ("%s line %d: %s\n",
1150 cfg_filename, config_lineno, config_input_line);
1151 debug(3, 0) ("parse_http_header_access: missing header name.\n");
1152 return;
97474590 1153 }
62e76326 1154
6bccf575 1155 /* Now lookup index of header. */
1156 id = httpHeaderIdByNameDef(t, strlen(t));
62e76326 1157
6bccf575 1158 if (strcmp(t, "All") == 0)
62e76326 1159 id = HDR_ENUM_END;
6bccf575 1160 else if (strcmp(t, "Other") == 0)
62e76326 1161 id = HDR_OTHER;
6bccf575 1162 else if (id == -1) {
62e76326 1163 debug(3, 0) ("%s line %d: %s\n",
1164 cfg_filename, config_lineno, config_input_line);
1165 debug(3, 0) ("parse_http_header_access: unknown header name %s.\n", t);
1166 return;
97474590 1167 }
62e76326 1168
6bccf575 1169 if (id != HDR_ENUM_END) {
62e76326 1170 parse_acl_access(&header[id].access_list);
6bccf575 1171 } else {
62e76326 1172 char *next_string = t + strlen(t) - 1;
1173 *next_string = 'A';
1174 *(next_string + 1) = ' ';
1175
1176 for (i = 0; i < HDR_ENUM_END; i++) {
1177 char *new_string = xstrdup(next_string);
1178 strtok(new_string, w_space);
1179 parse_acl_access(&header[i].access_list);
1180 safe_free(new_string);
1181 }
97474590 1182 }
6bccf575 1183}
1184
1185static void
1186free_http_header_access(header_mangler header[])
1187{
1188 int i;
62e76326 1189
6bccf575 1190 for (i = 0; i < HDR_ENUM_END; i++) {
62e76326 1191 free_acl_access(&header[i].access_list);
6bccf575 1192 }
1193}
1194
1195static void
1196dump_http_header_replace(StoreEntry * entry, const char *name, header_mangler
62e76326 1197 header[])
6bccf575 1198{
1199 int i;
62e76326 1200
6bccf575 1201 for (i = 0; i < HDR_ENUM_END; i++) {
62e76326 1202 if (NULL == header[i].replacement)
1203 continue;
1204
1205 storeAppendPrintf(entry, "%s %s %s\n", name, httpHeaderNameById(i),
1206 header[i].replacement);
97474590 1207 }
1208}
e3dd531e 1209
97474590 1210static void
6bccf575 1211parse_http_header_replace(header_mangler header[])
e3dd531e 1212{
6bccf575 1213 int id, i;
1214 char *t = NULL;
62e76326 1215
6bccf575 1216 if ((t = strtok(NULL, w_space)) == NULL) {
62e76326 1217 debug(3, 0) ("%s line %d: %s\n",
1218 cfg_filename, config_lineno, config_input_line);
1219 debug(3, 0) ("parse_http_header_replace: missing header name.\n");
1220 return;
6bccf575 1221 }
62e76326 1222
6bccf575 1223 /* Now lookup index of header. */
1224 id = httpHeaderIdByNameDef(t, strlen(t));
62e76326 1225
6bccf575 1226 if (strcmp(t, "All") == 0)
62e76326 1227 id = HDR_ENUM_END;
6bccf575 1228 else if (strcmp(t, "Other") == 0)
62e76326 1229 id = HDR_OTHER;
6bccf575 1230 else if (id == -1) {
62e76326 1231 debug(3, 0) ("%s line %d: %s\n",
1232 cfg_filename, config_lineno, config_input_line);
1233 debug(3, 0) ("parse_http_header_replace: unknown header name %s.\n",
1234 t);
1235 return;
6bccf575 1236 }
62e76326 1237
6bccf575 1238 if (id != HDR_ENUM_END) {
62e76326 1239 if (header[id].replacement != NULL)
1240 safe_free(header[id].replacement);
1241
1242 header[id].replacement = xstrdup(t + strlen(t) + 1);
6bccf575 1243 } else {
62e76326 1244 for (i = 0; i < HDR_ENUM_END; i++) {
1245 if (header[i].replacement != NULL)
1246 safe_free(header[i].replacement);
1247
1248 header[i].replacement = xstrdup(t + strlen(t) + 1);
1249 }
6bccf575 1250 }
1251}
1252
1253static void
1254free_http_header_replace(header_mangler header[])
1255{
1256 int i;
62e76326 1257
6bccf575 1258 for (i = 0; i < HDR_ENUM_END; i++) {
62e76326 1259 if (header[i].replacement != NULL)
1260 safe_free(header[i].replacement);
6bccf575 1261 }
97474590 1262}
62e76326 1263
9e8b2f1c 1264#endif
97474590 1265
25a77f03 1266
e90100aa 1267static void
e6ccf245 1268dump_cachedir(StoreEntry * entry, const char *name, _SquidConfig::_cacheSwap swap)
e90100aa 1269{
f53b06f9 1270 SwapDir *s;
1271 int i;
d3b3ab85 1272 assert (entry);
62e76326 1273
a7d59104 1274 for (i = 0; i < swap.n_configured; i++) {
62e76326 1275 s = swap.swapDirs[i];
59b2d47f 1276 storeAppendPrintf(entry, "%s %s %s", name, s->type(), s->path);
62e76326 1277 s->dump(*entry);
62e76326 1278 storeAppendPrintf(entry, "\n");
f53b06f9 1279 }
1280}
1281
59b2d47f 1282
f53b06f9 1283static int
e6ccf245 1284check_null_cachedir(_SquidConfig::_cacheSwap swap)
f53b06f9 1285{
1286 return swap.swapDirs == NULL;
e90100aa 1287}
1288
53ad48e6 1289static int
1290check_null_string(char *s)
1291{
1292 return s == NULL;
1293}
1294
94439e4e 1295static void
1296parse_authparam(authConfig * config)
1297{
1298 char *type_str;
1299 char *param_str;
94439e4e 1300
1301 if ((type_str = strtok(NULL, w_space)) == NULL)
62e76326 1302 self_destruct();
94439e4e 1303
1304 if ((param_str = strtok(NULL, w_space)) == NULL)
62e76326 1305 self_destruct();
94439e4e 1306
f5691f9c 1307 /* find a configuration for the scheme */
1308 AuthConfig *scheme = AuthConfig::Find (type_str);
62e76326 1309
f5691f9c 1310 if (scheme == NULL) {
1311 /* Create a configuration */
1312 AuthScheme *theScheme;
1313
1314 if ((theScheme = AuthScheme::Find(type_str)) == NULL) {
1315 debug(3, 0) ("Parsing Config File: Unknown authentication scheme '%s'.\n", type_str);
1316 return;
62e76326 1317 }
94439e4e 1318
f5691f9c 1319 config->push_back(theScheme->createConfig());
1320 scheme = config->back();
1321 assert (scheme);
94439e4e 1322 }
62e76326 1323
f5691f9c 1324 scheme->parse(scheme, config->size(), param_str);
94439e4e 1325}
1326
1327static void
1328free_authparam(authConfig * cfg)
1329{
f5691f9c 1330 AuthConfig *scheme;
94439e4e 1331 /* DON'T FREE THESE FOR RECONFIGURE */
62e76326 1332
94439e4e 1333 if (reconfiguring)
62e76326 1334 return;
1335
f5691f9c 1336 while (cfg->size()) {
1337 scheme = cfg->pop_back();
1338 scheme->done();
94439e4e 1339 }
94439e4e 1340}
1341
1342static void
1343dump_authparam(StoreEntry * entry, const char *name, authConfig cfg)
1344{
f5691f9c 1345 for (authConfig::iterator i = cfg.begin(); i != cfg.end(); ++i)
1346 (*i)->dump(entry, name, (*i));
94439e4e 1347}
1348
0e4e0e7d 1349void
e6ccf245 1350allocate_new_swapdir(_SquidConfig::_cacheSwap * swap)
090089c4 1351{
f1dc9b30 1352 if (swap->swapDirs == NULL) {
62e76326 1353 swap->n_allocated = 4;
1354 swap->swapDirs = static_cast<SwapDir **>(xcalloc(swap->n_allocated, sizeof(SwapDir *)));
f1dc9b30 1355 }
62e76326 1356
f1dc9b30 1357 if (swap->n_allocated == swap->n_configured) {
62e76326 1358 SwapDir **tmp;
1359 swap->n_allocated <<= 1;
1360 tmp = static_cast<SwapDir **>(xcalloc(swap->n_allocated, sizeof(SwapDir *)));
1361 xmemcpy(tmp, swap->swapDirs, swap->n_configured * sizeof(SwapDir *));
1362 xfree(swap->swapDirs);
1363 swap->swapDirs = tmp;
f1dc9b30 1364 }
0e4e0e7d 1365}
1366
59b2d47f 1367/* TODO: just return the object, the # is irrelevant */
cd748f27 1368static int
1369find_fstype(char *type)
1370{
59b2d47f 1371 for (size_t i = 0; i < StoreFileSystem::FileSystems().size(); ++i)
1372 if (strcasecmp(type, StoreFileSystem::FileSystems().items[i]->type()) == 0)
1373 return (int)i;
62e76326 1374
cd748f27 1375 return (-1);
1376}
1377
0e4e0e7d 1378static void
e6ccf245 1379parse_cachedir(_SquidConfig::_cacheSwap * swap)
0e4e0e7d 1380{
1381 char *type_str;
cd748f27 1382 char *path_str;
1383 SwapDir *sd;
1384 int i;
1385 int fs;
cd748f27 1386
0e4e0e7d 1387 if ((type_str = strtok(NULL, w_space)) == NULL)
62e76326 1388 self_destruct();
cd748f27 1389
cd748f27 1390 if ((path_str = strtok(NULL, w_space)) == NULL)
62e76326 1391 self_destruct();
cd748f27 1392
1393 /*
1394 * This bit of code is a little strange.
1395 * See, if we find a path and type match for a given line, then
1396 * as long as we're reconfiguring, we can just call its reconfigure
1397 * function. No harm there.
1398 *
1399 * Trouble is, if we find a path match, but not a type match, we have
1400 * a dilemma - we could gracefully shut down the fs, kill it, and
1401 * create a new one of a new type in its place, BUT at this stage the
1402 * fs is meant to be the *NEW* one, and so things go very strange. :-)
1403 *
1404 * So, we'll assume the person isn't going to change the fs type for now,
1405 * and XXX later on we will make sure that its picked up.
1406 *
1407 * (moving around cache_dir lines will be looked at later in a little
1408 * more sane detail..)
1409 */
1410
1411 for (i = 0; i < swap->n_configured; i++) {
62e76326 1412 assert (swap->swapDirs[i]);
1413
1414 if (0 == strcasecmp(path_str, swap->swapDirs[i]->path)) {
1415 /* This is a little weird, you'll appreciate it later */
1416 fs = find_fstype(type_str);
1417
1418 if (fs < 0) {
1419 fatalf("Unknown cache_dir type '%s'\n", type_str);
1420 }
1421
1422 sd = swap->swapDirs[i];
1423 sd->reconfigure (i, path_str);
1424 update_maxobjsize();
1425 return;
1426 }
cd748f27 1427 }
1428
2b6662ba 1429 assert(swap->n_configured < 63); /* 7 bits, signed */
dc986280 1430
cd748f27 1431 fs = find_fstype(type_str);
62e76326 1432
cd748f27 1433 if (fs < 0) {
62e76326 1434 /* If we get here, we didn't find a matching cache_dir type */
1435 fatalf("Unknown cache_dir type '%s'\n", type_str);
0e4e0e7d 1436 }
62e76326 1437
cd748f27 1438 allocate_new_swapdir(swap);
59b2d47f 1439 swap->swapDirs[swap->n_configured] = StoreFileSystem::FileSystems().items[fs]->createSwapDir();
d3b3ab85 1440 sd = swap->swapDirs[swap->n_configured];
8e8d4f30 1441 /* parse the FS parameters and options */
d3b3ab85 1442 sd->parse(swap->n_configured, path_str);
1443 ++swap->n_configured;
cd748f27 1444 /* Update the max object size */
1445 update_maxobjsize();
752c3b27 1446}
1447
8203a132 1448static void
e6ccf245 1449free_cachedir(_SquidConfig::_cacheSwap * swap)
f1dc9b30 1450{
a47b9029 1451 int i;
860ee7e3 1452 /* DON'T FREE THESE FOR RECONFIGURE */
62e76326 1453
5cd39a10 1454 if (reconfiguring)
62e76326 1455 return;
1456
a47b9029 1457 for (i = 0; i < swap->n_configured; i++) {
62e76326 1458 SwapDir * s = swap->swapDirs[i];
1459 swap->swapDirs[i] = NULL;
1460 delete s;
a47b9029 1461 }
62e76326 1462
a47b9029 1463 safe_free(swap->swapDirs);
1464 swap->swapDirs = NULL;
1465 swap->n_allocated = 0;
1466 swap->n_configured = 0;
f1dc9b30 1467}
1468
2d72d4fd 1469static const char *
505e35db 1470peer_type_str(const peer_t type)
1471{
0cdcddb9 1472 switch (type) {
62e76326 1473
505e35db 1474 case PEER_PARENT:
62e76326 1475 return "parent";
1476 break;
1477
505e35db 1478 case PEER_SIBLING:
62e76326 1479 return "sibling";
1480 break;
1481
505e35db 1482 case PEER_MULTICAST:
62e76326 1483 return "multicast";
1484 break;
1485
505e35db 1486 default:
62e76326 1487 return "unknown";
1488 break;
505e35db 1489 }
1490}
1491
f1dc9b30 1492static void
a7d59104 1493dump_peer(StoreEntry * entry, const char *name, peer * p)
98ffb7e4 1494{
505e35db 1495 domain_ping *d;
505e35db 1496 domain_type *t;
1497 LOCAL_ARRAY(char, xname, 128);
62e76326 1498
d41de3c1 1499 while (p != NULL) {
62e76326 1500 storeAppendPrintf(entry, "%s %s %s %d %d",
1501 name,
1502 p->host,
1503 neighborTypeStr(p),
1504 p->http_port,
1505 p->icp.port);
1506 dump_peer_options(entry, p);
1507
1508 for (d = p->peer_domain; d; d = d->next) {
1509 storeAppendPrintf(entry, "cache_peer_domain %s %s%s\n",
1510 p->host,
1511 d->do_ping ? null_string : "!",
1512 d->domain);
1513 }
1514
1515 if (p->access) {
1516 snprintf(xname, 128, "cache_peer_access %s", p->name);
1517 dump_acl_access(entry, xname, p->access);
1518 }
1519
1520 for (t = p->typelist; t; t = t->next) {
1521 storeAppendPrintf(entry, "neighbor_type_domain %s %s %s\n",
1522 p->host,
1523 peer_type_str(t->type),
1524 t->domain);
1525 }
1526
1527 p = p->next;
d41de3c1 1528 }
98ffb7e4 1529}
1530
8203a132 1531static void
40a1495e 1532parse_peer(peer ** head)
7813c6d5 1533{
270b86af 1534 char *token = NULL;
40a1495e 1535 peer *p;
7813c6d5 1536 int i;
f5691f9c 1537 CBDATA_INIT_TYPE_FREECB(peer, peerDestroy);
72711e31 1538 p = cbdataAlloc(peer);
40a1495e 1539 p->http_port = CACHE_HTTP_PORT;
399cabec 1540 p->icp.port = CACHE_ICP_PORT;
40a1495e 1541 p->weight = 1;
d1b63fc8 1542 p->basetime = 0;
dc835977 1543 p->stats.logged_state = PEER_ALIVE;
62e76326 1544
e481c2dc 1545 if ((token = strtok(NULL, w_space)) == NULL)
62e76326 1546 self_destruct();
1547
40a1495e 1548 p->host = xstrdup(token);
62e76326 1549
be753325 1550 p->name = xstrdup(token);
62e76326 1551
e481c2dc 1552 if ((token = strtok(NULL, w_space)) == NULL)
62e76326 1553 self_destruct();
1554
40a1495e 1555 p->type = parseNeighborType(token);
62e76326 1556
0e4e0e7d 1557 i = GetInteger();
62e76326 1558
40a1495e 1559 p->http_port = (u_short) i;
62e76326 1560
0e4e0e7d 1561 i = GetInteger();
62e76326 1562
399cabec 1563 p->icp.port = (u_short) i;
62e76326 1564
270b86af 1565 while ((token = strtok(NULL, w_space))) {
62e76326 1566 if (!strcasecmp(token, "proxy-only")) {
1567 p->options.proxy_only = 1;
1568 } else if (!strcasecmp(token, "no-query")) {
1569 p->options.no_query = 1;
1570 } else if (!strcasecmp(token, "background-ping")) {
1571 p->options.background_ping = 1;
1572 } else if (!strcasecmp(token, "no-digest")) {
1573 p->options.no_digest = 1;
1574 } else if (!strcasecmp(token, "multicast-responder")) {
1575 p->options.mcast_responder = 1;
1576 } else if (!strncasecmp(token, "weight=", 7)) {
1577 p->weight = xatoi(token + 7);
1578 } else if (!strncasecmp(token, "basetime=", 9)) {
1579 p->basetime = xatoi(token + 9);
1580 } else if (!strcasecmp(token, "closest-only")) {
1581 p->options.closest_only = 1;
1582 } else if (!strncasecmp(token, "ttl=", 4)) {
1583 p->mcast.ttl = xatoi(token + 4);
1584
1585 if (p->mcast.ttl < 0)
1586 p->mcast.ttl = 0;
1587
1588 if (p->mcast.ttl > 128)
1589 p->mcast.ttl = 128;
1590 } else if (!strcasecmp(token, "default")) {
1591 p->options.default_parent = 1;
1592 } else if (!strcasecmp(token, "round-robin")) {
1593 p->options.roundrobin = 1;
1594 } else if (!strcasecmp(token, "weighted-round-robin")) {
1595 p->options.weighted_roundrobin = 1;
dc9d133b 1596#if USE_HTCP
62e76326 1597
1598 } else if (!strcasecmp(token, "htcp")) {
1599 p->options.htcp = 1;
dc9d133b 1600#endif
62e76326 1601
1602 } else if (!strcasecmp(token, "no-netdb-exchange")) {
1603 p->options.no_netdb_exchange = 1;
afd88fbe 1604#if USE_CARP
62e76326 1605
1606 } else if (!strcasecmp(token, "carp")) {
1607 if (p->type != PEER_PARENT)
1608 fatalf("parse_peer: non-parent carp peer %s/%d\n", p->host, p->http_port);
1609
1610 p->options.carp = 1;
1611
95e36d02 1612#endif
1613#if DELAY_POOLS
62e76326 1614
1615 } else if (!strcasecmp(token, "no-delay")) {
1616 p->options.no_delay = 1;
afd88fbe 1617#endif
62e76326 1618
1619 } else if (!strncasecmp(token, "login=", 6)) {
1620 p->login = xstrdup(token + 6);
1621 rfc1738_unescape(p->login);
1622 } else if (!strncasecmp(token, "connect-timeout=", 16)) {
1623 p->connect_timeout = xatoi(token + 16);
7e3ce7b9 1624#if USE_CACHE_DIGESTS
62e76326 1625
1626 } else if (!strncasecmp(token, "digest-url=", 11)) {
1627 p->digest_url = xstrdup(token + 11);
7e3ce7b9 1628#endif
62e76326 1629
1630 } else if (!strcasecmp(token, "allow-miss")) {
1631 p->options.allow_miss = 1;
1632 } else if (!strncasecmp(token, "max-conn=", 9)) {
1633 p->max_conn = xatoi(token + 9);
1634 } else if (!strcasecmp(token, "originserver")) {
1635 p->options.originserver = 1;
1636 } else if (!strncasecmp(token, "name=", 5)) {
1637 safe_free(p->name);
1638
1639 if (token[5])
1640 p->name = xstrdup(token + 5);
1641 } else if (!strncasecmp(token, "forceddomain=", 13)) {
1642 safe_free(p->domain);
1643
1644 if (token[13])
1645 p->domain = xstrdup(token + 13);
1646
a7ad6e4e 1647#if USE_SSL
62e76326 1648
1649 } else if (strcmp(token, "ssl") == 0) {
1650 p->use_ssl = 1;
1651 } else if (strncmp(token, "sslcert=", 8) == 0) {
1652 safe_free(p->sslcert);
1653 p->sslcert = xstrdup(token + 8);
1654 } else if (strncmp(token, "sslkey=", 7) == 0) {
1655 safe_free(p->sslkey);
1656 p->sslkey = xstrdup(token + 7);
1657 } else if (strncmp(token, "sslversion=", 11) == 0) {
1658 p->sslversion = atoi(token + 11);
1659 } else if (strncmp(token, "ssloptions=", 11) == 0) {
1660 safe_free(p->ssloptions);
1661 p->ssloptions = xstrdup(token + 11);
1662 } else if (strncmp(token, "sslcipher=", 10) == 0) {
1663 safe_free(p->sslcipher);
1664 p->sslcipher = xstrdup(token + 10);
1665 } else if (strncmp(token, "sslcafile=", 10) == 0) {
1666 safe_free(p->sslcafile);
1667 p->sslcipher = xstrdup(token + 10);
1668 } else if (strncmp(token, "sslcapath=", 10) == 0) {
1669 safe_free(p->sslcapath);
1670 p->sslcipher = xstrdup(token + 10);
1671 } else if (strncmp(token, "sslflags=", 9) == 0) {
1672 safe_free(p->sslflags);
1673 p->sslflags = xstrdup(token + 9);
1674 } else if (strncmp(token, "ssldomain=", 10) == 0) {
1675 safe_free(p->ssldomain);
1676 p->ssldomain = xstrdup(token + 10);
a7ad6e4e 1677#endif
62e76326 1678
1679 } else if (strcmp(token, "front-end-https") == 0) {
1680 p->front_end_https = 1;
1681 } else if (strcmp(token, "front-end-https=on") == 0) {
1682 p->front_end_https = 1;
1683 } else if (strcmp(token, "front-end-https=auto") == 0) {
1684 p->front_end_https = 2;
1685 } else {
1686 debug(3, 0) ("parse_peer: token='%s'\n", token);
1687 self_destruct();
1688 }
270b86af 1689 }
62e76326 1690
be753325 1691 if (peerFindByName(p->name))
62e76326 1692 fatalf("ERROR: cache_peer %s specified twice\n", p->name);
1693
40a1495e 1694 if (p->weight < 1)
62e76326 1695 p->weight = 1;
1696
399cabec 1697 p->icp.version = ICP_VERSION_CURRENT;
62e76326 1698
98829f69 1699 p->tcp_up = PEER_TCP_MAGIC_COUNT;
62e76326 1700
eb406bb7 1701 p->test_fd = -1;
62e76326 1702
e13ee7ad 1703#if USE_CACHE_DIGESTS
62e76326 1704
e13ee7ad 1705 if (!p->options.no_digest) {
62e76326 1706 /* XXX This looks odd.. who has the original pointer
1707 * then?
1708 */
1709 PeerDigest *pd = peerDigestCreate(p);
1710 p->digest = cbdataReference(pd);
8a6218c6 1711 }
62e76326 1712
a7ad6e4e 1713#endif
1714#if USE_SSL
1715 if (p->use_ssl) {
62e76326 1716 p->sslContext = sslCreateClientContext(p->sslcert, p->sslkey, p->sslversion, p->sslcipher, p->ssloptions, p->sslflags, p->sslcafile, p->sslcapath);
a7ad6e4e 1717 }
62e76326 1718
e13ee7ad 1719#endif
0153d498 1720 while (*head != NULL)
62e76326 1721 head = &(*head)->next;
1722
0153d498 1723 *head = p;
62e76326 1724
40a1495e 1725 Config.npeers++;
62e76326 1726
82056f1e 1727 peerClearRR(p);
0153d498 1728}
1729
1730static void
40a1495e 1731free_peer(peer ** P)
0153d498 1732{
40a1495e 1733 peer *p;
62e76326 1734
79d39a72 1735 while ((p = *P) != NULL) {
62e76326 1736 *P = p->next;
3855c318 1737#if USE_CACHE_DIGESTS
62e76326 1738
1739 cbdataReferenceDone(p->digest);
3855c318 1740#endif
62e76326 1741
1742 cbdataFree(p);
a47b9029 1743 }
62e76326 1744
987c67d1 1745 Config.npeers = 0;
270b86af 1746}
1747
1748static void
a7d59104 1749dump_cachemgrpasswd(StoreEntry * entry, const char *name, cachemgr_passwd * list)
270b86af 1750{
d41de3c1 1751 wordlist *w;
62e76326 1752
d41de3c1 1753 while (list != NULL) {
62e76326 1754 if (strcmp(list->passwd, "none") && strcmp(list->passwd, "disable"))
1755 storeAppendPrintf(entry, "%s XXXXXXXXXX", name);
1756 else
1757 storeAppendPrintf(entry, "%s %s", name, list->passwd);
1758
1759 for (w = list->actions; w != NULL; w = w->next) {
1760 storeAppendPrintf(entry, " %s", w->key);
1761 }
1762
1763 storeAppendPrintf(entry, "\n");
1764 list = list->next;
d41de3c1 1765 }
270b86af 1766}
1767
1768static void
a47b9029 1769parse_cachemgrpasswd(cachemgr_passwd ** head)
270b86af 1770{
1771 char *passwd = NULL;
1772 wordlist *actions = NULL;
22f3fd98 1773 cachemgr_passwd *p;
1774 cachemgr_passwd **P;
270b86af 1775 parse_string(&passwd);
1776 parse_wordlist(&actions);
e6ccf245 1777 p = static_cast<cachemgr_passwd *>(xcalloc(1, sizeof(cachemgr_passwd)));
22f3fd98 1778 p->passwd = passwd;
1779 p->actions = actions;
62e76326 1780
26aa7e31 1781 for (P = head; *P; P = &(*P)->next) {
62e76326 1782 /*
1783 * See if any of the actions from this line already have a
1784 * password from previous lines. The password checking
1785 * routines in cache_manager.c take the the password from
1786 * the first cachemgr_passwd struct that contains the
1787 * requested action. Thus, we should warn users who might
1788 * think they can have two passwords for the same action.
1789 */
1790 wordlist *w;
1791 wordlist *u;
1792
1793 for (w = (*P)->actions; w; w = w->next) {
1794 for (u = actions; u; u = u->next) {
1795 if (strcmp(w->key, u->key))
1796 continue;
1797
1798 debug(0, 0) ("WARNING: action '%s' (line %d) already has a password\n",
1799 u->key, config_lineno);
1800 }
1801 }
26aa7e31 1802 }
62e76326 1803
22f3fd98 1804 *P = p;
270b86af 1805}
1806
1807static void
a47b9029 1808free_cachemgrpasswd(cachemgr_passwd ** head)
270b86af 1809{
a47b9029 1810 cachemgr_passwd *p;
62e76326 1811
79d39a72 1812 while ((p = *head) != NULL) {
62e76326 1813 *head = p->next;
1814 xfree(p->passwd);
1815 wordlistDestroy(&p->actions);
1816 xfree(p);
a47b9029 1817 }
270b86af 1818}
1819
8203a132 1820static void
16300b58 1821dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var)
270b86af 1822{
d41de3c1 1823 acl_name_list *a;
62e76326 1824
d41de3c1 1825 while (var != NULL) {
62e76326 1826 storeAppendPrintf(entry, "%s %s", name, var->err_page_name);
1827
1828 for (a = var->acl_list; a != NULL; a = a->next)
1829 storeAppendPrintf(entry, " %s", a->name);
1830
1831 storeAppendPrintf(entry, "\n");
1832
1833 var = var->next;
d41de3c1 1834 }
270b86af 1835}
1836
1837static void
16300b58 1838parse_denyinfo(acl_deny_info_list ** var)
6e40f263 1839{
f1dc9b30 1840 aclParseDenyInfoLine(var);
6e40f263 1841}
403279e0 1842
1273d501 1843void
a47b9029 1844free_denyinfo(acl_deny_info_list ** list)
3c5557f9 1845{
56b63fa1 1846 acl_deny_info_list *a = NULL;
1847 acl_deny_info_list *a_next = NULL;
1848 acl_name_list *l = NULL;
1849 acl_name_list *l_next = NULL;
62e76326 1850
1273d501 1851 for (a = *list; a; a = a_next) {
62e76326 1852 for (l = a->acl_list; l; l = l_next) {
1853 l_next = l->next;
1854 memFree(l, MEM_ACL_NAME_LIST);
1855 l = NULL;
1856 }
1857
1858 a_next = a->next;
1859 memFree(a, MEM_ACL_DENY_INFO_LIST);
1860 a = NULL;
1273d501 1861 }
62e76326 1862
1273d501 1863 *list = NULL;
270b86af 1864}
1865
1866static void
505e35db 1867parse_peer_access(void)
270b86af 1868{
1869 char *host = NULL;
505e35db 1870 peer *p;
62e76326 1871
270b86af 1872 if (!(host = strtok(NULL, w_space)))
62e76326 1873 self_destruct();
1874
0cdcddb9 1875 if ((p = peerFindByName(host)) == NULL) {
62e76326 1876 debug(15, 0) ("%s, line %d: No cache_peer '%s'\n",
1877 cfg_filename, config_lineno, host);
1878 return;
0cdcddb9 1879 }
62e76326 1880
505e35db 1881 aclParseAccessLine(&p->access);
270b86af 1882}
1883
270b86af 1884static void
1885parse_hostdomain(void)
1886{
1887 char *host = NULL;
1888 char *domain = NULL;
62e76326 1889
270b86af 1890 if (!(host = strtok(NULL, w_space)))
62e76326 1891 self_destruct();
1892
f1dc9b30 1893 while ((domain = strtok(NULL, list_sep))) {
62e76326 1894 domain_ping *l = NULL;
1895 domain_ping **L = NULL;
1896 peer *p;
1897
1898 if ((p = peerFindByName(host)) == NULL) {
1899 debug(15, 0) ("%s, line %d: No cache_peer '%s'\n",
1900 cfg_filename, config_lineno, host);
1901 continue;
1902 }
1903
1904 l = static_cast<domain_ping *>(xcalloc(1, sizeof(domain_ping)));
1905 l->do_ping = 1;
1906
1907 if (*domain == '!') { /* check for !.edu */
1908 l->do_ping = 0;
1909 domain++;
1910 }
1911
1912 l->domain = xstrdup(domain);
1913
1914 for (L = &(p->peer_domain); *L; L = &((*L)->next))
1915
1916 ;
1917 *L = l;
f1dc9b30 1918 }
270b86af 1919}
1920
1921static void
1922parse_hostdomaintype(void)
1923{
1924 char *host = NULL;
1925 char *type = NULL;
1926 char *domain = NULL;
62e76326 1927
270b86af 1928 if (!(host = strtok(NULL, w_space)))
62e76326 1929 self_destruct();
1930
270b86af 1931 if (!(type = strtok(NULL, w_space)))
62e76326 1932 self_destruct();
1933
f1dc9b30 1934 while ((domain = strtok(NULL, list_sep))) {
62e76326 1935 domain_type *l = NULL;
1936 domain_type **L = NULL;
1937 peer *p;
1938
1939 if ((p = peerFindByName(host)) == NULL) {
1940 debug(15, 0) ("%s, line %d: No cache_peer '%s'\n",
1941 cfg_filename, config_lineno, host);
1942 return;
1943 }
1944
1945 l = static_cast<domain_type *>(xcalloc(1, sizeof(domain_type)));
1946 l->type = parseNeighborType(type);
1947 l->domain = xstrdup(domain);
1948
1949 for (L = &(p->typelist); *L; L = &((*L)->next))
1950
1951 ;
1952 *L = l;
f1dc9b30 1953 }
270b86af 1954}
1955
7e3ce7b9 1956#if UNUSED_CODE
270b86af 1957static void
a7d59104 1958dump_ushortlist(StoreEntry * entry, const char *name, ushortlist * u)
090089c4 1959{
270b86af 1960 while (u) {
62e76326 1961 storeAppendPrintf(entry, "%s %d\n", name, (int) u->i);
1962 u = u->next;
270b86af 1963 }
1964}
090089c4 1965
f53b06f9 1966static int
1967check_null_ushortlist(ushortlist * u)
1968{
1969 return u == NULL;
1970}
1971
270b86af 1972static void
1973parse_ushortlist(ushortlist ** P)
1974{
1975 char *token;
1976 int i;
1977 ushortlist *u;
1978 ushortlist **U;
62e76326 1979
270b86af 1980 while ((token = strtok(NULL, w_space))) {
62e76326 1981 if (sscanf(token, "%d", &i) != 1)
1982 self_destruct();
1983
1984 if (i < 0)
1985 i = 0;
1986
1987 u = xcalloc(1, sizeof(ushortlist));
1988
1989 u->i = (u_short) i;
1990
1991 for (U = P; *U; U = &(*U)->next)
1992
1993 ;
1994 *U = u;
090089c4 1995 }
270b86af 1996}
090089c4 1997
0153d498 1998static void
a47b9029 1999free_ushortlist(ushortlist ** P)
0153d498 2000{
a47b9029 2001 ushortlist *u;
62e76326 2002
79d39a72 2003 while ((u = *P) != NULL) {
62e76326 2004 *P = u->next;
2005 xfree(u);
a47b9029 2006 }
0153d498 2007}
62e76326 2008
7e3ce7b9 2009#endif
0153d498 2010
270b86af 2011static void
a7d59104 2012dump_int(StoreEntry * entry, const char *name, int var)
270b86af 2013{
f53b06f9 2014 storeAppendPrintf(entry, "%s %d\n", name, var);
270b86af 2015}
c1c29eb6 2016
94439e4e 2017void
270b86af 2018parse_int(int *var)
2019{
270b86af 2020 int i;
0e4e0e7d 2021 i = GetInteger();
270b86af 2022 *var = i;
2023}
090089c4 2024
0153d498 2025static void
2026free_int(int *var)
2027{
a47b9029 2028 *var = 0;
0153d498 2029}
2030
270b86af 2031static void
a7d59104 2032dump_onoff(StoreEntry * entry, const char *name, int var)
270b86af 2033{
f53b06f9 2034 storeAppendPrintf(entry, "%s %s\n", name, var ? "on" : "off");
270b86af 2035}
090089c4 2036
d205783b 2037void
270b86af 2038parse_onoff(int *var)
2039{
2040 char *token = strtok(NULL, w_space);
090089c4 2041
270b86af 2042 if (token == NULL)
62e76326 2043 self_destruct();
2044
270b86af 2045 if (!strcasecmp(token, "on") || !strcasecmp(token, "enable"))
62e76326 2046 *var = 1;
270b86af 2047 else
62e76326 2048 *var = 0;
270b86af 2049}
e90100aa 2050
0153d498 2051#define free_onoff free_int
f1dc9b30 2052#define dump_eol dump_string
2053#define free_eol free_string
d9e04dc7 2054#define dump_debug dump_string
2055#define free_debug free_string
30a4f2a8 2056
270b86af 2057static void
a7d59104 2058dump_refreshpattern(StoreEntry * entry, const char *name, refresh_t * head)
270b86af 2059{
d41de3c1 2060 while (head != NULL) {
62e76326 2061 storeAppendPrintf(entry, "%s%s %s %d %d%% %d\n",
2062 name,
2063 head->flags.icase ? " -i" : null_string,
2064 head->pattern,
2065 (int) head->min / 60,
2066 (int) (100.0 * head->pct + 0.5),
2067 (int) head->max / 60);
9f60cfdf 2068#if HTTP_VIOLATIONS
62e76326 2069
2070 if (head->flags.override_expire)
2071 storeAppendPrintf(entry, " override-expire");
2072
2073 if (head->flags.override_lastmod)
2074 storeAppendPrintf(entry, " override-lastmod");
2075
2076 if (head->flags.reload_into_ims)
2077 storeAppendPrintf(entry, " reload-into-ims");
2078
2079 if (head->flags.ignore_reload)
2080 storeAppendPrintf(entry, " ignore-reload");
2081
38f9c547 2082 if (head->flags.ignore_no_cache)
2083 storeAppendPrintf(entry, " ignore-no-cache");
2084
2085 if (head->flags.ignore_no_store)
2086 storeAppendPrintf(entry, " ignore-no-store");
2087
2088 if (head->flags.ignore_private)
2089 storeAppendPrintf(entry, " ignore-private");
2090
2091 if (head->flags.ignore_auth)
2092 storeAppendPrintf(entry, " ignore-auth");
2093
9f60cfdf 2094#endif
62e76326 2095
2096 storeAppendPrintf(entry, "\n");
2097
2098 head = head->next;
d41de3c1 2099 }
270b86af 2100}
090089c4 2101
270b86af 2102static void
f1dc9b30 2103parse_refreshpattern(refresh_t ** head)
270b86af 2104{
f1dc9b30 2105 char *token;
2106 char *pattern;
2107 time_t min = 0;
c3f6d204 2108 double pct = 0.0;
f1dc9b30 2109 time_t max = 0;
9f60cfdf 2110#if HTTP_VIOLATIONS
62e76326 2111
1dfa1d81 2112 int override_expire = 0;
2113 int override_lastmod = 0;
cbe3a719 2114 int reload_into_ims = 0;
2115 int ignore_reload = 0;
38f9c547 2116 int ignore_no_cache = 0;
2117 int ignore_no_store = 0;
2118 int ignore_private = 0;
2119 int ignore_auth = 0;
9f60cfdf 2120#endif
62e76326 2121
f1dc9b30 2122 int i;
2123 refresh_t *t;
2124 regex_t comp;
2125 int errcode;
2126 int flags = REG_EXTENDED | REG_NOSUB;
62e76326 2127
f1dc9b30 2128 if ((token = strtok(NULL, w_space)) == NULL)
62e76326 2129 self_destruct();
2130
f1dc9b30 2131 if (strcmp(token, "-i") == 0) {
62e76326 2132 flags |= REG_ICASE;
2133 token = strtok(NULL, w_space);
f1dc9b30 2134 } else if (strcmp(token, "+i") == 0) {
62e76326 2135 flags &= ~REG_ICASE;
2136 token = strtok(NULL, w_space);
f1dc9b30 2137 }
62e76326 2138
f1dc9b30 2139 if (token == NULL)
62e76326 2140 self_destruct();
2141
f1dc9b30 2142 pattern = xstrdup(token);
62e76326 2143
0e4e0e7d 2144 i = GetInteger(); /* token: min */
62e76326 2145
f1dc9b30 2146 min = (time_t) (i * 60); /* convert minutes to seconds */
62e76326 2147
0e4e0e7d 2148 i = GetInteger(); /* token: pct */
62e76326 2149
c3f6d204 2150 pct = (double) i / 100.0;
62e76326 2151
0e4e0e7d 2152 i = GetInteger(); /* token: max */
62e76326 2153
f1dc9b30 2154 max = (time_t) (i * 60); /* convert minutes to seconds */
62e76326 2155
1dfa1d81 2156 /* Options */
2157 while ((token = strtok(NULL, w_space)) != NULL) {
9f60cfdf 2158#if HTTP_VIOLATIONS
62e76326 2159
2160 if (!strcmp(token, "override-expire"))
2161 override_expire = 1;
2162 else if (!strcmp(token, "override-lastmod"))
2163 override_lastmod = 1;
38f9c547 2164 else if (!strcmp(token, "ignore-no-cache"))
2165 ignore_no_cache = 1;
2166 else if (!strcmp(token, "ignore-no-store"))
2167 ignore_no_store = 1;
2168 else if (!strcmp(token, "ignore-private"))
2169 ignore_private = 1;
2170 else if (!strcmp(token, "ignore-auth"))
2171 ignore_auth = 1;
62e76326 2172 else if (!strcmp(token, "reload-into-ims")) {
2173 reload_into_ims = 1;
2174 refresh_nocache_hack = 1;
2175 /* tell client_side.c that this is used */
2176 } else if (!strcmp(token, "ignore-reload")) {
2177 ignore_reload = 1;
2178 refresh_nocache_hack = 1;
2179 /* tell client_side.c that this is used */
2180 } else
9f60cfdf 2181#endif
62e76326 2182
2183 debug(22, 0) ("redreshAddToList: Unknown option '%s': %s\n",
2184 pattern, token);
1dfa1d81 2185 }
62e76326 2186
f1dc9b30 2187 if ((errcode = regcomp(&comp, pattern, flags)) != 0) {
62e76326 2188 char errbuf[256];
2189 regerror(errcode, &comp, errbuf, sizeof errbuf);
2190 debug(22, 0) ("%s line %d: %s\n",
2191 cfg_filename, config_lineno, config_input_line);
2192 debug(22, 0) ("refreshAddToList: Invalid regular expression '%s': %s\n",
2193 pattern, errbuf);
2194 return;
f1dc9b30 2195 }
62e76326 2196
c3f6d204 2197 pct = pct < 0.0 ? 0.0 : pct;
f1dc9b30 2198 max = max < 0 ? 0 : max;
e6ccf245 2199 t = static_cast<refresh_t *>(xcalloc(1, sizeof(refresh_t)));
f1dc9b30 2200 t->pattern = (char *) xstrdup(pattern);
2201 t->compiled_pattern = comp;
2202 t->min = min;
c3f6d204 2203 t->pct = pct;
f1dc9b30 2204 t->max = max;
62e76326 2205
c3f6d204 2206 if (flags & REG_ICASE)
62e76326 2207 t->flags.icase = 1;
2208
9f60cfdf 2209#if HTTP_VIOLATIONS
62e76326 2210
1dfa1d81 2211 if (override_expire)
62e76326 2212 t->flags.override_expire = 1;
2213
1dfa1d81 2214 if (override_lastmod)
62e76326 2215 t->flags.override_lastmod = 1;
2216
cbe3a719 2217 if (reload_into_ims)
62e76326 2218 t->flags.reload_into_ims = 1;
2219
cbe3a719 2220 if (ignore_reload)
62e76326 2221 t->flags.ignore_reload = 1;
2222
38f9c547 2223 if (ignore_no_cache)
2224 t->flags.ignore_no_cache = 1;
2225
2226 if (ignore_no_store)
2227 t->flags.ignore_no_store = 1;
2228
2229 if (ignore_private)
2230 t->flags.ignore_private = 1;
2231
2232 if (ignore_auth)
2233 t->flags.ignore_auth = 1;
2234
9f60cfdf 2235#endif
62e76326 2236
f1dc9b30 2237 t->next = NULL;
62e76326 2238
f1dc9b30 2239 while (*head)
62e76326 2240 head = &(*head)->next;
2241
f1dc9b30 2242 *head = t;
62e76326 2243
f1dc9b30 2244 safe_free(pattern);
270b86af 2245}
090089c4 2246
8e89beb3 2247#if UNUSED_CODE
6b53c392 2248static int
a4b8110e 2249check_null_refreshpattern(refresh_t * data)
6b53c392 2250{
80e073c0 2251 return data == NULL;
6b53c392 2252}
62e76326 2253
8e89beb3 2254#endif
6b53c392 2255
270b86af 2256static void
a47b9029 2257free_refreshpattern(refresh_t ** head)
270b86af 2258{
f1dc9b30 2259 refresh_t *t;
62e76326 2260
79d39a72 2261 while ((t = *head) != NULL) {
62e76326 2262 *head = t->next;
2263 safe_free(t->pattern);
2264 regfree(&t->compiled_pattern);
2265 safe_free(t);
f1dc9b30 2266 }
270b86af 2267}
12b9e9b1 2268
270b86af 2269static void
a7d59104 2270dump_string(StoreEntry * entry, const char *name, char *var)
270b86af 2271{
f53b06f9 2272 if (var != NULL)
62e76326 2273 storeAppendPrintf(entry, "%s %s\n", name, var);
270b86af 2274}
98ffb7e4 2275
270b86af 2276static void
0153d498 2277parse_string(char **var)
270b86af 2278{
2279 char *token = strtok(NULL, w_space);
270b86af 2280 safe_free(*var);
62e76326 2281
270b86af 2282 if (token == NULL)
62e76326 2283 self_destruct();
2284
270b86af 2285 *var = xstrdup(token);
2286}
b15e6857 2287
0153d498 2288static void
2289free_string(char **var)
2290{
027acbaf 2291 safe_free(*var);
0153d498 2292}
caebbe00 2293
94439e4e 2294void
f1dc9b30 2295parse_eol(char *volatile *var)
270b86af 2296{
852751f7 2297 unsigned char *token = (unsigned char *) strtok(NULL, null_string);
270b86af 2298 safe_free(*var);
62e76326 2299
f1dc9b30 2300 if (token == NULL)
62e76326 2301 self_destruct();
2302
2d72d4fd 2303 while (*token && isspace(*token))
62e76326 2304 token++;
2305
20cb98c9 2306 if (!*token)
62e76326 2307 self_destruct();
2308
852751f7 2309 *var = xstrdup((char *) token);
270b86af 2310}
090089c4 2311
d9e04dc7 2312void
2313parse_debug(char *volatile *var)
2314{
2315 parse_eol(var);
2316 safe_free(debug_options)
2317 debug_options = xstrdup(Config.debugOptions);
2318 Debug::parseOptions(Config.debugOptions);
2319}
2320
270b86af 2321static void
a7d59104 2322dump_time_t(StoreEntry * entry, const char *name, time_t var)
090089c4 2323{
f53b06f9 2324 storeAppendPrintf(entry, "%s %d seconds\n", name, (int) var);
090089c4 2325}
2326
94439e4e 2327void
a47b9029 2328parse_time_t(time_t * var)
0ffd22bc 2329{
f1dc9b30 2330 parseTimeLine(var, T_SECOND_STR);
0ffd22bc 2331}
2332
270b86af 2333static void
a47b9029 2334free_time_t(time_t * var)
270b86af 2335{
a47b9029 2336 *var = 0;
270b86af 2337}
9906e724 2338
2339static void
a7d59104 2340dump_size_t(StoreEntry * entry, const char *name, size_t var)
1b635117 2341{
f53b06f9 2342 storeAppendPrintf(entry, "%s %d\n", name, (int) var);
1b635117 2343}
2344
2345static void
a7d59104 2346dump_b_size_t(StoreEntry * entry, const char *name, size_t var)
9906e724 2347{
f53b06f9 2348 storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_BYTES_STR);
9906e724 2349}
2350
2351static void
a7d59104 2352dump_kb_size_t(StoreEntry * entry, const char *name, size_t var)
9906e724 2353{
f53b06f9 2354 storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_KBYTES_STR);
9906e724 2355}
2356
2357static void
a47b9029 2358parse_size_t(size_t * var)
1b635117 2359{
1b635117 2360 int i;
0e4e0e7d 2361 i = GetInteger();
1b635117 2362 *var = (size_t) i;
2363}
2364
2365static void
2366parse_b_size_t(size_t * var)
9906e724 2367{
2368 parseBytesLine(var, B_BYTES_STR);
2369}
2370
2371static void
a47b9029 2372parse_kb_size_t(size_t * var)
9906e724 2373{
2374 parseBytesLine(var, B_KBYTES_STR);
2375}
2376
2377static void
a47b9029 2378free_size_t(size_t * var)
9906e724 2379{
a47b9029 2380 *var = 0;
9906e724 2381}
2382
1b635117 2383#define free_b_size_t free_size_t
9906e724 2384#define free_kb_size_t free_size_t
2385#define free_mb_size_t free_size_t
2386#define free_gb_size_t free_size_t
090089c4 2387
8203a132 2388static void
a7d59104 2389dump_ushort(StoreEntry * entry, const char *name, u_short var)
090089c4 2390{
f53b06f9 2391 storeAppendPrintf(entry, "%s %d\n", name, var);
270b86af 2392}
090089c4 2393
0153d498 2394static void
a47b9029 2395free_ushort(u_short * u)
0153d498 2396{
2397 *u = 0;
2398}
2399
270b86af 2400static void
2401parse_ushort(u_short * var)
b67e2c8c 2402{
2403 ConfigParser::ParseUShort(var);
2404}
2405
2406void
2407ConfigParser::ParseUShort(u_short *var)
270b86af 2408{
270b86af 2409 int i;
090089c4 2410
0e4e0e7d 2411 i = GetInteger();
62e76326 2412
270b86af 2413 if (i < 0)
62e76326 2414 i = 0;
2415
270b86af 2416 *var = (u_short) i;
090089c4 2417}
2418
270b86af 2419static void
a7d59104 2420dump_wordlist(StoreEntry * entry, const char *name, wordlist * list)
270b86af 2421{
270b86af 2422 while (list != NULL) {
62e76326 2423 storeAppendPrintf(entry, "%s %s\n", name, list->key);
2424 list = list->next;
429fdbec 2425 }
429fdbec 2426}
2427
94439e4e 2428void
270b86af 2429parse_wordlist(wordlist ** list)
429fdbec 2430{
270b86af 2431 char *token;
a3c6890f 2432 char *t = strtok(NULL, "");
62e76326 2433
a3c6890f 2434 while ((token = strwordtok(NULL, &t)))
62e76326 2435 wordlistAdd(list, token);
429fdbec 2436}
270b86af 2437
f8d9f54a 2438static int
5da06f20 2439check_null_wordlist(wordlist * w)
f8d9f54a 2440{
2441 return w == NULL;
2442}
2443
63e9d884 2444static int
c6d5b87b 2445check_null_acl_access(acl_access * a)
63e9d884 2446{
2447 return a == NULL;
2448}
2449
0153d498 2450#define free_wordlist wordlistDestroy
270b86af 2451
d548ee64 2452#define free_uri_whitespace free_int
2453
2454static void
2455parse_uri_whitespace(int *var)
2456{
2457 char *token = strtok(NULL, w_space);
62e76326 2458
d548ee64 2459 if (token == NULL)
62e76326 2460 self_destruct();
2461
7e3ce7b9 2462 if (!strcasecmp(token, "strip"))
62e76326 2463 *var = URI_WHITESPACE_STRIP;
7e3ce7b9 2464 else if (!strcasecmp(token, "deny"))
62e76326 2465 *var = URI_WHITESPACE_DENY;
d548ee64 2466 else if (!strcasecmp(token, "allow"))
62e76326 2467 *var = URI_WHITESPACE_ALLOW;
d548ee64 2468 else if (!strcasecmp(token, "encode"))
62e76326 2469 *var = URI_WHITESPACE_ENCODE;
d548ee64 2470 else if (!strcasecmp(token, "chop"))
62e76326 2471 *var = URI_WHITESPACE_CHOP;
d548ee64 2472 else
62e76326 2473 self_destruct();
d548ee64 2474}
2475
2476
2477static void
2478dump_uri_whitespace(StoreEntry * entry, const char *name, int var)
2479{
c193c972 2480 const char *s;
62e76326 2481
d548ee64 2482 if (var == URI_WHITESPACE_ALLOW)
62e76326 2483 s = "allow";
d548ee64 2484 else if (var == URI_WHITESPACE_ENCODE)
62e76326 2485 s = "encode";
d548ee64 2486 else if (var == URI_WHITESPACE_CHOP)
62e76326 2487 s = "chop";
7e3ce7b9 2488 else if (var == URI_WHITESPACE_DENY)
62e76326 2489 s = "deny";
7e3ce7b9 2490 else
62e76326 2491 s = "strip";
2492
d548ee64 2493 storeAppendPrintf(entry, "%s %s\n", name, s);
2494}
2495
6a566b9c 2496static void
c1dd71ae 2497free_removalpolicy(RemovalPolicySettings ** settings)
6a566b9c 2498{
2499 if (!*settings)
62e76326 2500 return;
2501
6a566b9c 2502 free_string(&(*settings)->type);
62e76326 2503
6a566b9c 2504 free_wordlist(&(*settings)->args);
62e76326 2505
6a566b9c 2506 xfree(*settings);
62e76326 2507
6a566b9c 2508 *settings = NULL;
2509}
2510
2511static void
c1dd71ae 2512parse_removalpolicy(RemovalPolicySettings ** settings)
6a566b9c 2513{
2514 if (*settings)
62e76326 2515 free_removalpolicy(settings);
2516
e6ccf245 2517 *settings = static_cast<RemovalPolicySettings *>(xcalloc(1, sizeof(**settings)));
62e76326 2518
6a566b9c 2519 parse_string(&(*settings)->type);
62e76326 2520
6a566b9c 2521 parse_wordlist(&(*settings)->args);
2522}
2523
2524static void
c1dd71ae 2525dump_removalpolicy(StoreEntry * entry, const char *name, RemovalPolicySettings * settings)
6a566b9c 2526{
2527 wordlist *args;
2528 storeAppendPrintf(entry, "%s %s", name, settings->type);
2529 args = settings->args;
62e76326 2530
6a566b9c 2531 while (args) {
62e76326 2532 storeAppendPrintf(entry, " %s", args->key);
2533 args = args->next;
6a566b9c 2534 }
62e76326 2535
be58afb5 2536 storeAppendPrintf(entry, "\n");
6a566b9c 2537}
c1dd71ae 2538
6a566b9c 2539
1ee67578 2540#include "cf_parser.h"
f1dc9b30 2541
2542peer_t
2543parseNeighborType(const char *s)
2544{
2545 if (!strcasecmp(s, "parent"))
62e76326 2546 return PEER_PARENT;
2547
f1dc9b30 2548 if (!strcasecmp(s, "neighbor"))
62e76326 2549 return PEER_SIBLING;
2550
f1dc9b30 2551 if (!strcasecmp(s, "neighbour"))
62e76326 2552 return PEER_SIBLING;
2553
f1dc9b30 2554 if (!strcasecmp(s, "sibling"))
62e76326 2555 return PEER_SIBLING;
2556
f1dc9b30 2557 if (!strcasecmp(s, "multicast"))
62e76326 2558 return PEER_MULTICAST;
2559
f1dc9b30 2560 debug(15, 0) ("WARNING: Unknown neighbor type: %s\n", s);
62e76326 2561
f1dc9b30 2562 return PEER_SIBLING;
2563}
f150dd4b 2564
3f38a55e 2565#if CURRENTLY_UNUSED
2566/* This code was previously used by http_port. Left as it really should
2567 * be used by icp_port and htcp_port
2568 */
52f772de 2569void
2570parse_sockaddr_in_list_token(sockaddr_in_list ** head, char *token)
7e3ce7b9 2571{
7e3ce7b9 2572 char *t;
efd900cb 2573 char *host;
62e76326 2574
7e3ce7b9 2575 const struct hostent *hp;
efd900cb 2576 unsigned short port;
7e3ce7b9 2577 sockaddr_in_list *s;
52f772de 2578
2579 host = NULL;
2580 port = 0;
62e76326 2581
52f772de 2582 if ((t = strchr(token, ':'))) {
62e76326 2583 /* host:port */
2584 host = token;
2585 *t = '\0';
2586 port = (unsigned short) xatoi(t + 1);
2587
2588 if (0 == port)
2589 self_destruct();
5c20d6fa 2590 } else if ((port = xatoi(token)) > 0) {
62e76326 2591 /* port */
52f772de 2592 } else {
62e76326 2593 self_destruct();
52f772de 2594 }
62e76326 2595
e6ccf245 2596 s = static_cast<sockaddr_in_list *>(xcalloc(1, sizeof(*s)));
52f772de 2597 s->s.sin_port = htons(port);
62e76326 2598
52f772de 2599 if (NULL == host)
62e76326 2600 s->s.sin_addr = any_addr;
52f772de 2601 else if (1 == safe_inet_addr(host, &s->s.sin_addr))
62e76326 2602 (void) 0;
52f772de 2603 else if ((hp = gethostbyname(host))) /* dont use ipcache */
62e76326 2604 s->s.sin_addr = inaddrFromHostent(hp);
52f772de 2605 else
62e76326 2606 self_destruct();
2607
52f772de 2608 while (*head)
62e76326 2609 head = &(*head)->next;
2610
52f772de 2611 *head = s;
2612}
2613
2614static void
2615parse_sockaddr_in_list(sockaddr_in_list ** head)
2616{
2617 char *token;
62e76326 2618
52f772de 2619 while ((token = strtok(NULL, w_space))) {
62e76326 2620 parse_sockaddr_in_list_token(head, token);
7e3ce7b9 2621 }
2622}
2623
2624static void
2625dump_sockaddr_in_list(StoreEntry * e, const char *n, const sockaddr_in_list * s)
2626{
2627 while (s) {
62e76326 2628 storeAppendPrintf(e, "%s %s:%d\n",
2629 n,
2630 inet_ntoa(s->s.sin_addr),
2631 ntohs(s->s.sin_port));
2632 s = s->next;
7e3ce7b9 2633 }
2634}
2635
2636static void
2637free_sockaddr_in_list(sockaddr_in_list ** head)
2638{
2639 sockaddr_in_list *s;
62e76326 2640
7e3ce7b9 2641 while ((s = *head) != NULL) {
62e76326 2642 *head = s->next;
2643 xfree(s);
7e3ce7b9 2644 }
2645}
2646
2647static int
2648check_null_sockaddr_in_list(const sockaddr_in_list * s)
2649{
2650 return NULL == s;
2651}
62e76326 2652
3f38a55e 2653#endif /* CURRENTLY_UNUSED */
7e3ce7b9 2654
d193a436 2655static void
3f38a55e 2656parse_http_port_specification(http_port_list * s, char *token)
d193a436 2657{
3f38a55e 2658 char *host = NULL;
62e76326 2659
d193a436 2660 const struct hostent *hp;
3f38a55e 2661 unsigned short port = 0;
2662 char *t;
62e76326 2663
d193a436 2664 if ((t = strchr(token, ':'))) {
62e76326 2665 /* host:port */
2666 host = token;
2667 *t = '\0';
2668 port = (unsigned short) atoi(t + 1);
2669
2670 if (0 == port)
2671 self_destruct();
3f38a55e 2672 } else if ((port = atoi(token)) > 0) {
62e76326 2673 /* port */
d193a436 2674 } else {
62e76326 2675 self_destruct();
d193a436 2676 }
62e76326 2677
d193a436 2678 s->s.sin_port = htons(port);
62e76326 2679
d193a436 2680 if (NULL == host)
62e76326 2681 s->s.sin_addr = any_addr;
d193a436 2682 else if (1 == safe_inet_addr(host, &s->s.sin_addr))
62e76326 2683 (void) 0;
3f38a55e 2684 else if ((hp = gethostbyname(host))) {
62e76326 2685 /* dont use ipcache */
2686 s->s.sin_addr = inaddrFromHostent(hp);
2687 s->defaultsite = xstrdup(host);
3f38a55e 2688 } else
62e76326 2689 self_destruct();
3f38a55e 2690}
2691
2692static void
2693parse_http_port_option(http_port_list * s, char *token)
2694{
2695 if (strncmp(token, "defaultsite=", 12) == 0) {
62e76326 2696 safe_free(s->defaultsite);
2697 s->defaultsite = xstrdup(token + 12);
2698 s->accel = 1;
3f38a55e 2699 } else if (strncmp(token, "name=", 5) == 0) {
62e76326 2700 safe_free(s->name);
2701 s->name = xstrdup(token + 5);
3f38a55e 2702 } else if (strcmp(token, "transparent") == 0) {
62e76326 2703 s->transparent = 1;
3f38a55e 2704 } else if (strcmp(token, "vhost") == 0) {
62e76326 2705 s->vhost = 1;
2706 s->accel = 1;
3f38a55e 2707 } else if (strcmp(token, "vport") == 0) {
62e76326 2708 s->vport = -1;
2709 s->accel = 1;
3f38a55e 2710 } else if (strncmp(token, "vport=", 6) == 0) {
62e76326 2711 s->vport = atoi(token + 6);
2712 s->accel = 1;
3f38a55e 2713 } else if (strncmp(token, "protocol=", 9) == 0) {
62e76326 2714 s->protocol = xstrdup(token + 9);
2715 s->accel = 1;
3f38a55e 2716 } else if (strcmp(token, "accel") == 0) {
62e76326 2717 s->accel = 1;
3f38a55e 2718 } else {
62e76326 2719 self_destruct();
3f38a55e 2720 }
2721}
2722
2723static void
2724free_generic_http_port_data(http_port_list * s)
2725{
2726 safe_free(s->name);
2727 safe_free(s->defaultsite);
2728}
2729
2730static void
2731cbdataFree_http_port(void *data)
2732{
2733 free_generic_http_port_data((http_port_list *)data);
2734}
2735
2736
2737static http_port_list *
2738create_http_port(char *portspec)
2739{
2740 CBDATA_TYPE(http_port_list);
2741 CBDATA_INIT_TYPE_FREECB(http_port_list, cbdataFree_http_port);
2742
2743 http_port_list *s = cbdataAlloc(http_port_list);
2744 s->protocol = xstrdup("http");
2745 parse_http_port_specification(s, portspec);
2746 return s;
2747}
2748
2749void
2750add_http_port(char *portspec)
2751{
2752 http_port_list *s = create_http_port(portspec);
2753 s->next = Config.Sockaddr.http;
2754 Config.Sockaddr.http = s;
2755}
2756
2757static void
2758parse_http_port_list(http_port_list ** head)
2759{
2760 char *token = strtok(NULL, w_space);
62e76326 2761
3f38a55e 2762 if (!token)
62e76326 2763 self_destruct();
2764
3f38a55e 2765 http_port_list *s = create_http_port(token);
62e76326 2766
3f38a55e 2767 /* parse options ... */
2768 while ((token = strtok(NULL, w_space))) {
62e76326 2769 parse_http_port_option(s, token);
3f38a55e 2770 }
62e76326 2771
3f38a55e 2772 while (*head)
62e76326 2773 head = &(*head)->next;
2774
3f38a55e 2775 *head = s;
2776}
2777
2778static void
2779dump_generic_http_port(StoreEntry * e, const char *n, const http_port_list * s)
2780{
2781 storeAppendPrintf(e, "%s %s:%d",
62e76326 2782 n,
2783 inet_ntoa(s->s.sin_addr),
2784 ntohs(s->s.sin_port));
2785
3f38a55e 2786 if (s->defaultsite)
62e76326 2787 storeAppendPrintf(e, " defaultsite=%s", s->defaultsite);
2788
3f38a55e 2789 if (s->transparent)
62e76326 2790 storeAppendPrintf(e, " transparent");
2791
3f38a55e 2792 if (s->vhost)
62e76326 2793 storeAppendPrintf(e, " vhost");
2794
3f38a55e 2795 if (s->vport)
62e76326 2796 storeAppendPrintf(e, " vport");
3f38a55e 2797}
62e76326 2798
3f38a55e 2799static void
2800dump_http_port_list(StoreEntry * e, const char *n, const http_port_list * s)
2801{
2802 while (s) {
62e76326 2803 dump_generic_http_port(e, n, s);
2804 storeAppendPrintf(e, "\n");
2805 s = s->next;
3f38a55e 2806 }
2807}
2808
2809static void
2810free_http_port_list(http_port_list ** head)
2811{
2812 http_port_list *s;
62e76326 2813
3f38a55e 2814 while ((s = *head) != NULL) {
62e76326 2815 *head = s->next;
2816 cbdataFree(s);
3f38a55e 2817 }
2818}
2819
2820#if UNUSED_CODE
2821static int
2822check_null_http_port_list(const http_port_list * s)
2823{
2824 return NULL == s;
2825}
62e76326 2826
3f38a55e 2827#endif
2828
2829#if USE_SSL
2830static void
2831cbdataFree_https_port(void *data)
2832{
2833 https_port_list *s = (https_port_list *)data;
2834 free_generic_http_port_data(&s->http);
2835 safe_free(s->cert);
2836 safe_free(s->key);
2837}
2838
2839static void
2840parse_https_port_list(https_port_list ** head)
2841{
2842 CBDATA_TYPE(https_port_list);
2843 char *token;
2844 https_port_list *s;
2845 CBDATA_INIT_TYPE_FREECB(https_port_list, cbdataFree_https_port);
2846 token = strtok(NULL, w_space);
62e76326 2847
3f38a55e 2848 if (!token)
62e76326 2849 self_destruct();
2850
3f38a55e 2851 s = cbdataAlloc(https_port_list);
62e76326 2852
3f38a55e 2853 s->http.protocol = xstrdup("https");
62e76326 2854
3f38a55e 2855 parse_http_port_specification(&s->http, token);
62e76326 2856
d193a436 2857 /* parse options ... */
2858 while ((token = strtok(NULL, w_space))) {
62e76326 2859 if (strncmp(token, "cert=", 5) == 0) {
2860 safe_free(s->cert);
2861 s->cert = xstrdup(token + 5);
2862 } else if (strncmp(token, "key=", 4) == 0) {
2863 safe_free(s->key);
2864 s->key = xstrdup(token + 4);
2865 } else if (strncmp(token, "version=", 8) == 0) {
2866 s->version = xatoi(token + 8);
2867 } else if (strncmp(token, "options=", 8) == 0) {
2868 safe_free(s->options);
2869 s->options = xstrdup(token + 8);
2870 } else if (strncmp(token, "cipher=", 7) == 0) {
2871 safe_free(s->cipher);
2872 s->cipher = xstrdup(token + 7);
2873 } else if (strncmp(token, "clientca=", 9) == 0) {
2874 safe_free(s->clientca);
2875 s->clientca = xstrdup(token + 9);
2876 } else if (strncmp(token, "cafile=", 7) == 0) {
2877 safe_free(s->cafile);
2878 s->cafile = xstrdup(token + 7);
2879 } else if (strncmp(token, "capath=", 7) == 0) {
2880 safe_free(s->capath);
2881 s->capath = xstrdup(token + 7);
35105e4b 2882 } else if (strncmp(token, "dhparams=", 9) == 0) {
2883 safe_free(s->dhfile);
2884 s->dhfile = xstrdup(token + 9);
62e76326 2885 } else if (strncmp(token, "sslflags=", 9) == 0) {
2886 safe_free(s->sslflags);
2887 s->sslflags = xstrdup(token + 9);
2888 } else {
2889 parse_http_port_option(&s->http, token);
2890 }
d193a436 2891 }
62e76326 2892
35105e4b 2893 s->sslContext = sslCreateServerContext(s->cert, s->key, s->version, s->cipher, s->options, s->sslflags, s->clientca, s->cafile, s->capath, s->dhfile);
62e76326 2894
87ec2a09 2895 if (!s->sslContext)
62e76326 2896 self_destruct();
2897
3f38a55e 2898 while (*head)
62e76326 2899 head = (https_port_list **)&(*head)->http.next;
2900
d193a436 2901 *head = s;
2902}
2903
2904static void
2905dump_https_port_list(StoreEntry * e, const char *n, const https_port_list * s)
2906{
2907 while (s) {
62e76326 2908 dump_generic_http_port(e, n, &s->http);
2909
2910 if (s->cert)
2911 storeAppendPrintf(e, " cert=%s", s->cert);
2912
2913 if (s->key)
2914 storeAppendPrintf(e, " key=%s", s->cert);
2915
2916 if (s->version)
2917 storeAppendPrintf(e, " version=%d", s->version);
2918
2919 if (s->options)
2920 storeAppendPrintf(e, " options=%s", s->options);
2921
2922 if (s->cipher)
2923 storeAppendPrintf(e, " cipher=%s", s->cipher);
2924
2925 if (s->cafile)
2926 storeAppendPrintf(e, " cafile=%s", s->cafile);
2927
2928 if (s->capath)
2929 storeAppendPrintf(e, " capath=%s", s->capath);
2930
35105e4b 2931 if (s->dhfile)
2932 storeAppendPrintf(e, " dhparams=%s", s->dhfile);
2933
62e76326 2934 if (s->sslflags)
2935 storeAppendPrintf(e, " sslflags=%s", s->sslflags);
2936
2937 storeAppendPrintf(e, "\n");
2938
2939 s = (https_port_list *) s->http.next;
d193a436 2940 }
2941}
2942
2943static void
2944free_https_port_list(https_port_list ** head)
2945{
2946 https_port_list *s;
62e76326 2947
d193a436 2948 while ((s = *head) != NULL) {
62e76326 2949 *head = (https_port_list *) s->http.next;
2950 cbdataFree(s);
d193a436 2951 }
2952}
2953
2954#if 0
2955static int
2956check_null_https_port_list(const https_port_list * s)
2957{
2958 return NULL == s;
2959}
62e76326 2960
d193a436 2961#endif
2962
2963#endif /* USE_SSL */
2964
f150dd4b 2965void
2966configFreeMemory(void)
2967{
23ff6968 2968 free_all();
f150dd4b 2969}
f0b19334 2970
94439e4e 2971void
f0b19334 2972requirePathnameExists(const char *name, const char *path)
2973{
62e76326 2974
f0b19334 2975 struct stat sb;
08577e16 2976 char pathbuf[BUFSIZ];
f0b19334 2977 assert(path != NULL);
62e76326 2978
08577e16 2979 if (Config.chroot_dir) {
62e76326 2980 snprintf(pathbuf, BUFSIZ, "%s/%s", Config.chroot_dir, path);
2981 path = pathbuf;
08577e16 2982 }
62e76326 2983
137ee196 2984 if (stat(path, &sb) < 0)
62e76326 2985 fatalf("%s %s: %s", name, path, xstrerror());
f0b19334 2986}
d860a1aa 2987
2988char *
2989strtokFile(void)
2990{
42419a95 2991 static int fromFile = 0;
2992 static FILE *wordFile = NULL;
2993
d860a1aa 2994 char *t, *fn;
2995 LOCAL_ARRAY(char, buf, 256);
2996
62e76326 2997strtok_again:
2998
42419a95 2999 if (!fromFile) {
62e76326 3000 t = (strtok(NULL, w_space));
3001
3002 if (!t || *t == '#') {
3003 return NULL;
3004 } else if (*t == '\"' || *t == '\'') {
3005 /* quote found, start reading from file */
3006 fn = ++t;
3007
3008 while (*t && *t != '\"' && *t != '\'')
3009 t++;
3010
3011 *t = '\0';
3012
3013 if ((wordFile = fopen(fn, "r")) == NULL) {
3014 debug(28, 0) ("strtokFile: %s not found\n", fn);
3015 return (NULL);
3016 }
3017
ec4daaa5 3018#ifdef _SQUID_WIN32_
62e76326 3019 setmode(fileno(wordFile), O_TEXT);
3020
d860a1aa 3021#endif
62e76326 3022
3023 fromFile = 1;
3024 } else {
3025 return t;
3026 }
d860a1aa 3027 }
62e76326 3028
42419a95 3029 /* fromFile */
3030 if (fgets(buf, 256, wordFile) == NULL) {
62e76326 3031 /* stop reading from file */
3032 fclose(wordFile);
3033 wordFile = NULL;
3034 fromFile = 0;
3035 goto strtok_again;
d860a1aa 3036 } else {
62e76326 3037 char *t2, *t3;
3038 t = buf;
3039 /* skip leading and trailing white space */
3040 t += strspn(buf, w_space);
3041 t2 = t + strcspn(t, w_space);
3042 t3 = t2 + strspn(t2, w_space);
3043
3044 while (*t3 && *t3 != '#') {
3045 t2 = t3 + strcspn(t3, w_space);
3046 t3 = t2 + strspn(t2, w_space);
3047 }
3048
3049 *t2 = '\0';
3050 /* skip comments */
3051
3052 if (*t == '#')
3053 goto strtok_again;
3054
3055 /* skip blank lines */
3056 if (!*t)
3057 goto strtok_again;
3058
3059 return t;
d860a1aa 3060 }
3061}
7684c4b1 3062
450e0c10 3063#include "AccessLogEntry.h"
3064/* TODO: split out parsing somehow ...*/
7684c4b1 3065static void
3066parse_logformat(logformat ** logformat_definitions)
3067{
3068 logformat *nlf;
3069 char *name, *def;
3070
3071 if ((name = strtok(NULL, w_space)) == NULL)
3072 self_destruct();
3073
3074 if ((def = strtok(NULL, "\r\n")) == NULL)
3075 self_destruct();
3076
3077 debug(3, 1) ("Logformat for '%s' is '%s'\n", name, def);
3078
3079 nlf = (logformat *)xcalloc(1, sizeof(logformat));
3080
3081 nlf->name = xstrdup(name);
3082
3083 if (!accessLogParseLogFormat(&nlf->format, def))
3084 self_destruct();
3085
3086 nlf->next = *logformat_definitions;
3087
3088 *logformat_definitions = nlf;
3089}
3090
3091static void
3092parse_access_log(customlog ** logs)
3093{
3094 const char *filename, *logdef_name;
3095 customlog *cl;
3096 logformat *lf;
3097
3098 cl = (customlog *)xcalloc(1, sizeof(*cl));
3099
3100 if ((filename = strtok(NULL, w_space)) == NULL)
3101 self_destruct();
3102
3103 if (strcmp(filename, "none") == 0) {
3104 cl->type = CLF_NONE;
3105 goto done;
3106 }
3107
3108 if ((logdef_name = strtok(NULL, w_space)) == NULL)
3109 logdef_name = "auto";
3110
3111 debug(3, 9) ("Log definition name '%s' file '%s'\n", logdef_name, filename);
3112
3113 cl->filename = xstrdup(filename);
3114
3115 /* look for the definition pointer corresponding to this name */
3116 lf = Config.Log.logformats;
3117
3118 while (lf != NULL) {
3119 debug(3, 9) ("Comparing against '%s'\n", lf->name);
3120
3121 if (strcmp(lf->name, logdef_name) == 0)
3122 break;
3123
3124 lf = lf->next;
3125 }
3126
3127 if (lf != NULL) {
3128 cl->type = CLF_CUSTOM;
3129 cl->logFormat = lf;
3130 } else if (strcmp(logdef_name, "auto") == 0) {
3131 cl->type = CLF_AUTO;
3132 } else if (strcmp(logdef_name, "squid") == 0) {
3133 cl->type = CLF_SQUID;
3134 } else if (strcmp(logdef_name, "common") == 0) {
3135 cl->type = CLF_COMMON;
3136 } else {
3137 debug(3, 0) ("Log format '%s' is not defined\n", logdef_name);
3138 self_destruct();
3139 }
3140
3141done:
3142 aclParseAclList(&cl->aclList);
3143
3144 while (*logs)
3145 logs = &(*logs)->next;
3146
3147 *logs = cl;
3148}
3149
d64bef4c 3150static int
3151check_null_access_log(customlog *customlog_definitions)
3152{
3153 return customlog_definitions == NULL;
3154}
3155
7684c4b1 3156static void
3157dump_logformat(StoreEntry * entry, const char *name, logformat * definitions)
3158{
3159 accessLogDumpLogFormat(entry, name, definitions);
3160}
3161
3162static void
3163dump_access_log(StoreEntry * entry, const char *name, customlog * logs)
3164{
3165 customlog *log;
3166
3167 for (log = logs; log; log = log->next) {
3168 storeAppendPrintf(entry, "%s ", name);
3169
3170 switch (log->type) {
3171
3172 case CLF_CUSTOM:
3173 storeAppendPrintf(entry, "%s %s", log->filename, log->logFormat->name);
3174 break;
3175
3176 case CLF_NONE:
3177 storeAppendPrintf(entry, "none");
3178 break;
3179
3180 case CLF_SQUID:
3181 storeAppendPrintf(entry, "%s squid", log->filename);
3182 break;
3183
3184 case CLF_COMMON:
3185 storeAppendPrintf(entry, "%s squid", log->filename);
3186 break;
3187
3188 case CLF_AUTO:
3189
3190 if (log->aclList)
3191 storeAppendPrintf(entry, "%s auto", log->filename);
3192 else
3193 storeAppendPrintf(entry, "%s", log->filename);
3194
3195 break;
3196
3197 case CLF_UNKNOWN:
3198 break;
3199 }
3200
3201 if (log->aclList)
3202 dump_acl_list(entry, log->aclList);
3203
3204 storeAppendPrintf(entry, "\n");
3205 }
3206}
3207
3208static void
3209free_logformat(logformat ** definitions)
3210{
3211 while (*definitions) {
3212 logformat *format = *definitions;
3213 *definitions = format->next;
3214 accessLogFreeLogFormat(&format->format);
3215 xfree(format);
3216 }
3217}
3218
3219static void
3220free_access_log(customlog ** definitions)
3221{
3222 while (*definitions) {
3223 customlog *log = *definitions;
3224 *definitions = log->next;
3225
3226 log->logFormat = NULL;
3227 log->type = CLF_UNKNOWN;
3228
3229 if (log->aclList)
3230 aclDestroyAclList(&log->aclList);
3231
3232 safe_free(log->filename);
3233
3234 xfree(log);
3235 }
3236}