]> git.ipfire.org Git - thirdparty/squid.git/blob - src/cache_cf.cc
Bug #1057: New options to refresh-pattern configuration
[thirdparty/squid.git] / src / cache_cf.cc
1
2 /*
3 * $Id: cache_cf.cc,v 1.456 2004/11/06 22:20:47 hno Exp $
4 *
5 * DEBUG: section 3 Configuration File Parsing
6 * AUTHOR: Harvest Derived
7 *
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
10 *
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.
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
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35
36 #include "squid.h"
37 #include "authenticate.h"
38 #include "AuthConfig.h"
39 #include "AuthScheme.h"
40 #include "Store.h"
41 #include "SwapDir.h"
42 #include "ConfigParser.h"
43 #include "ACL.h"
44 #include "StoreFileSystem.h"
45
46 #if SQUID_SNMP
47 #include "snmp.h"
48 #endif
49 #if ESI
50 #include "ESIParser.h"
51 #endif
52
53 CBDATA_TYPE(peer);
54
55 static const char *const T_SECOND_STR = "second";
56 static const char *const T_MINUTE_STR = "minute";
57 static const char *const T_HOUR_STR = "hour";
58 static const char *const T_DAY_STR = "day";
59 static const char *const T_WEEK_STR = "week";
60 static const char *const T_FORTNIGHT_STR = "fortnight";
61 static const char *const T_MONTH_STR = "month";
62 static const char *const T_YEAR_STR = "year";
63 static const char *const T_DECADE_STR = "decade";
64
65 static const char *const B_BYTES_STR = "bytes";
66 static const char *const B_KBYTES_STR = "KB";
67 static const char *const B_MBYTES_STR = "MB";
68 static const char *const B_GBYTES_STR = "GB";
69
70 static const char *const list_sep = ", \t\n\r";
71
72 static void parse_logformat(logformat ** logformat_definitions);
73 static void parse_access_log(customlog ** customlog_definitions);
74 static int check_null_access_log(customlog *customlog_definitions);
75
76 static void dump_logformat(StoreEntry * entry, const char *name, logformat * definitions);
77 static void dump_access_log(StoreEntry * entry, const char *name, customlog * definitions);
78 static void free_logformat(logformat ** definitions);
79 static void free_access_log(customlog ** definitions);
80
81
82
83
84 static void update_maxobjsize(void);
85 static void configDoConfigure(void);
86 static void parse_refreshpattern(refresh_t **);
87 static int parseTimeUnits(const char *unit);
88 static void parseTimeLine(time_t * tptr, const char *units);
89 static void parse_ushort(u_short * var);
90 static void parse_string(char **);
91 static void default_all(void);
92 static void defaults_if_none(void);
93 static int parse_line(char *);
94 static void parseBytesLine(size_t * bptr, const char *units);
95 static size_t parseBytesUnits(const char *unit);
96 static void free_all(void);
97 void requirePathnameExists(const char *name, const char *path);
98 static OBJH dump_config;
99 #if HTTP_VIOLATIONS
100 static void dump_http_header_access(StoreEntry * entry, const char *name, header_mangler header[]);
101 static void parse_http_header_access(header_mangler header[]);
102 static void free_http_header_access(header_mangler header[]);
103 static void dump_http_header_replace(StoreEntry * entry, const char *name, header_mangler header[]);
104 static void parse_http_header_replace(header_mangler * header);
105 static void free_http_header_replace(header_mangler * header);
106 #endif
107 static void parse_denyinfo(acl_deny_info_list ** var);
108 static void dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var);
109 static void free_denyinfo(acl_deny_info_list ** var);
110 #if CURRENTLY_UNUSED
111 static void parse_sockaddr_in_list(sockaddr_in_list **);
112 static void dump_sockaddr_in_list(StoreEntry *, const char *, const sockaddr_in_list *);
113 static void free_sockaddr_in_list(sockaddr_in_list **);
114 static int check_null_sockaddr_in_list(const sockaddr_in_list *);
115 #endif /* CURRENTLY_UNUSED */
116 static void parse_http_port_list(http_port_list **);
117 static void dump_http_port_list(StoreEntry *, const char *, const http_port_list *);
118 static void free_http_port_list(http_port_list **);
119 #if UNUSED_CODE
120 static int check_null_http_port_list(const http_port_list *);
121 #endif
122 #if USE_SSL
123 static void parse_https_port_list(https_port_list **);
124 static void dump_https_port_list(StoreEntry *, const char *, const https_port_list *);
125 static void free_https_port_list(https_port_list **);
126 #if 0
127 static int check_null_https_port_list(const https_port_list *);
128 #endif
129 #endif /* USE_SSL */
130 static void parse_b_size_t(size_t * var);
131
132 void
133 self_destruct(void)
134 {
135 fatalf("Bungled %s line %d: %s",
136 cfg_filename, config_lineno, config_input_line);
137 }
138
139 void
140 wordlistDestroy(wordlist ** list)
141 {
142 wordlist *w = NULL;
143
144 while ((w = *list) != NULL) {
145 *list = w->next;
146 safe_free(w->key);
147 memFree(w, MEM_WORDLIST);
148 }
149
150 *list = NULL;
151 }
152
153 const char *
154 wordlistAdd(wordlist ** list, const char *key)
155 {
156 while (*list)
157 list = &(*list)->next;
158
159 *list = static_cast<wordlist *>(memAllocate(MEM_WORDLIST));
160
161 (*list)->key = xstrdup(key);
162
163 (*list)->next = NULL;
164
165 return (*list)->key;
166 }
167
168 void
169 wordlistJoin(wordlist ** list, wordlist ** wl)
170 {
171 while (*list)
172 list = &(*list)->next;
173
174 *list = *wl;
175
176 *wl = NULL;
177 }
178
179 void
180 wordlistAddWl(wordlist ** list, wordlist * wl)
181 {
182 while (*list)
183 list = &(*list)->next;
184
185 for (; wl; wl = wl->next, list = &(*list)->next) {
186 *list = static_cast<wordlist *>(memAllocate(MEM_WORDLIST));
187 (*list)->key = xstrdup(wl->key);
188 (*list)->next = NULL;
189 }
190 }
191
192 void
193 wordlistCat(const wordlist * w, MemBuf * mb)
194 {
195 while (NULL != w) {
196 memBufPrintf(mb, "%s\n", w->key);
197 w = w->next;
198 }
199 }
200
201 wordlist *
202 wordlistDup(const wordlist * w)
203 {
204 wordlist *D = NULL;
205
206 while (NULL != w) {
207 wordlistAdd(&D, w->key);
208 w = w->next;
209 }
210
211 return D;
212 }
213
214 /*
215 * These functions is the same as atoi/l/f, except that they check for errors
216 */
217
218 long
219 xatol(const char *token)
220 {
221 char *end;
222 long ret = strtol(token, &end, 10);
223
224 if (ret == 0 && end == token)
225 self_destruct();
226
227 return ret;
228 }
229
230 int
231 xatoi(const char *token)
232 {
233 return xatol(token);
234 }
235
236 static double
237 xatof(const char *token)
238 {
239 char *end;
240 double ret = strtod(token, &end);
241
242 if (ret == 0 && end == token)
243 self_destruct();
244
245 return ret;
246 }
247
248 int
249 GetInteger(void)
250 {
251 char *token = strtok(NULL, w_space);
252 int i;
253
254 if (token == NULL)
255 self_destruct();
256
257 if (sscanf(token, "%d", &i) != 1)
258 self_destruct();
259
260 return i;
261 }
262
263 static void
264 update_maxobjsize(void)
265 {
266 int i;
267 ssize_t ms = -1;
268
269 for (i = 0; i < Config.cacheSwap.n_configured; i++) {
270 assert (Config.cacheSwap.swapDirs[i]);
271
272 if (Config.cacheSwap.swapDirs[i]->max_objsize > ms)
273 ms = Config.cacheSwap.swapDirs[i]->max_objsize;
274 }
275
276 store_maxobjsize = ms;
277 }
278
279 static void
280 SetConfigFilename(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
292 int
293 parseConfigFile(const char *file_name)
294 {
295 FILE *fp = NULL;
296 char *token = NULL;
297 char *tmp_line;
298 int err_count = 0;
299 int is_pipe = 0;
300 configFreeMemory();
301 default_all();
302
303 if (file_name[0] == '!' || file_name[0] == '|') {
304 fp = popen(file_name + 1, "r");
305 is_pipe = 1;
306 } else {
307 fp = fopen(file_name, "r");
308 }
309
310 if (fp == NULL)
311 fatalf("Unable to open configuration file: %s: %s",
312 file_name, xstrerror());
313
314 #ifdef _SQUID_WIN32_
315
316 setmode(fileno(fp), O_TEXT);
317
318 #endif
319
320 SetConfigFilename(file_name, bool(is_pipe));
321
322 memset(config_input_line, '\0', BUFSIZ);
323
324 config_lineno = 0;
325
326 while (fgets(config_input_line, BUFSIZ, fp)) {
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
356 #if PROBABLY_NOT_WANTED_HERE
357
358 SetConfigFilename(cfg_filename, false);
359
360 #endif
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);
386 }
387
388 if (is_pipe) {
389 int ret = pclose(fp);
390
391 if (ret != 0)
392 fatalf("parseConfigFile: '%s' failed with exit code %d\n", file_name, ret);
393 } else {
394 fclose(fp);
395 }
396
397 defaults_if_none();
398 configDoConfigure();
399 cachemgrRegister("config",
400 "Current Squid Configuration",
401 dump_config,
402 1, 1);
403 return err_count;
404 }
405
406 static void
407 configDoConfigure(void)
408 {
409 memset(&Config2, '\0', sizeof(SquidConfig2));
410 /* init memory as early as possible */
411 memConfigure();
412 /* Sanity checks */
413
414 if (Config.cacheSwap.swapDirs == NULL)
415 fatal("No cache_dir's specified in config file");
416
417 /* calculate Config.Swap.maxSize */
418 storeDirConfigure();
419
420 if (0 == Config.Swap.maxSize)
421 /* people might want a zero-sized cache on purpose */
422 (void) 0;
423 else if (Config.Swap.maxSize < (Config.memMaxSize >> 10))
424 debug(3, 0) ("WARNING cache_mem is larger than total disk cache space!\n");
425
426 if (Config.Announce.period > 0) {
427 Config.onoff.announce = 1;
428 } else if (Config.Announce.period < 1) {
429 Config.Announce.period = 86400 * 365; /* one year */
430 Config.onoff.announce = 0;
431 }
432
433 #if USE_DNSSERVERS
434 if (Config.dnsChildren < 1)
435 fatal("No dnsservers allocated");
436
437 #endif
438
439 if (Config.Program.redirect) {
440 if (Config.redirectChildren < 1) {
441 Config.redirectChildren = 0;
442 wordlistDestroy(&Config.Program.redirect);
443 }
444 }
445
446 if (Config.appendDomain)
447 if (*Config.appendDomain != '.')
448 fatal("append_domain must begin with a '.'");
449
450 if (Config.errHtmlText == NULL)
451 Config.errHtmlText = xstrdup(null_string);
452
453 storeConfigure();
454
455 snprintf(ThisCache, sizeof(ThisCache), "%s (%s)",
456 uniqueHostname(),
457 full_appname_string);
458
459 /*
460 * the extra space is for loop detection in client_side.c -- we search
461 * for substrings in the Via header.
462 */
463 snprintf(ThisCache2, sizeof(ThisCache), " %s (%s)",
464 uniqueHostname(),
465 full_appname_string);
466
467 if (!Config.udpMaxHitObjsz || Config.udpMaxHitObjsz > SQUID_UDP_SO_SNDBUF)
468 Config.udpMaxHitObjsz = SQUID_UDP_SO_SNDBUF;
469
470 if (Config.appendDomain)
471 Config.appendDomainLen = strlen(Config.appendDomain);
472 else
473 Config.appendDomainLen = 0;
474
475 safe_free(debug_options)
476 debug_options = xstrdup(Config.debugOptions);
477
478 if (Config.retry.maxtries > 10)
479 fatal("maximum_single_addr_tries cannot be larger than 10");
480
481 if (Config.retry.maxtries < 1) {
482 debug(3, 0) ("WARNING: resetting 'maximum_single_addr_tries to 1\n");
483 Config.retry.maxtries = 1;
484 }
485
486 requirePathnameExists("MIME Config Table", Config.mimeTablePathname);
487 #if USE_DNSSERVERS
488
489 requirePathnameExists("cache_dns_program", Config.Program.dnsserver);
490 #endif
491 #if USE_UNLINKD
492
493 requirePathnameExists("unlinkd_program", Config.Program.unlinkd);
494 #endif
495
496 if (Config.Program.redirect)
497 requirePathnameExists("redirect_program", Config.Program.redirect->key);
498
499 requirePathnameExists("Icon Directory", Config.icons.directory);
500
501 requirePathnameExists("Error Directory", Config.errorDirectory);
502
503 #if HTTP_VIOLATIONS
504
505 {
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
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
588 }
589 #endif
590 #if !HTTP_VIOLATIONS
591 Config.onoff.via = 1;
592 #else
593
594 if (!Config.onoff.via)
595 debug(22, 1) ("WARNING: HTTP requires the use of Via\n");
596
597 #endif
598
599 if (Config.Wais.relayHost) {
600 if (Config.Wais._peer)
601 cbdataFree(Config.Wais._peer);
602
603 CBDATA_INIT_TYPE_FREECB(peer, peerDestroy);
604
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;
610 }
611
612 if (aclPurgeMethodInUse(Config.accessList.http))
613 Config2.onoff.enable_purge = 1;
614
615 if (geteuid() == 0) {
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 }
637 } else {
638 Config2.effectiveUserID = geteuid();
639 Config2.effectiveGroupID = getegid();
640 }
641
642 if (NULL != Config.effectiveGroup) {
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;
651 }
652
653 urlExtMethodConfigure();
654 #if USE_SSL
655
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);
657 #endif
658 }
659
660 /* Parse a time specification from the config file. Store the
661 * result in 'tptr', after converting it to 'units' */
662 static void
663 parseTimeLine(time_t * tptr, const char *units)
664 {
665 char *token;
666 double d;
667 time_t m;
668 time_t u;
669
670 if ((u = parseTimeUnits(units)) == 0)
671 self_destruct();
672
673 if ((token = strtok(NULL, w_space)) == NULL)
674 self_destruct();
675
676 d = xatof(token);
677
678 m = u; /* default to 'units' if none specified */
679
680 if (0 == d)
681 (void) 0;
682 else if ((token = strtok(NULL, w_space)) == NULL)
683 debug(3, 0) ("WARNING: No units on '%s', assuming %f %s\n",
684 config_input_line, d, units);
685 else if ((m = parseTimeUnits(token)) == 0)
686 self_destruct();
687
688 *tptr = static_cast<time_t> (m * d / u);
689 }
690
691 static int
692 parseTimeUnits(const char *unit)
693 {
694 if (!strncasecmp(unit, T_SECOND_STR, strlen(T_SECOND_STR)))
695 return 1;
696
697 if (!strncasecmp(unit, T_MINUTE_STR, strlen(T_MINUTE_STR)))
698 return 60;
699
700 if (!strncasecmp(unit, T_HOUR_STR, strlen(T_HOUR_STR)))
701 return 3600;
702
703 if (!strncasecmp(unit, T_DAY_STR, strlen(T_DAY_STR)))
704 return 86400;
705
706 if (!strncasecmp(unit, T_WEEK_STR, strlen(T_WEEK_STR)))
707 return 86400 * 7;
708
709 if (!strncasecmp(unit, T_FORTNIGHT_STR, strlen(T_FORTNIGHT_STR)))
710 return 86400 * 14;
711
712 if (!strncasecmp(unit, T_MONTH_STR, strlen(T_MONTH_STR)))
713 return 86400 * 30;
714
715 if (!strncasecmp(unit, T_YEAR_STR, strlen(T_YEAR_STR)))
716 return static_cast<int>(86400 * 365.2522);
717
718 if (!strncasecmp(unit, T_DECADE_STR, strlen(T_DECADE_STR)))
719 return static_cast<int>(86400 * 365.2522 * 10);
720
721 debug(3, 1) ("parseTimeUnits: unknown time unit '%s'\n", unit);
722
723 return 0;
724 }
725
726 static void
727 parseBytesLine(size_t * bptr, const char *units)
728 {
729 char *token;
730 double d;
731 size_t m;
732 size_t u;
733
734 if ((u = parseBytesUnits(units)) == 0)
735 self_destruct();
736
737 if ((token = strtok(NULL, w_space)) == NULL)
738 self_destruct();
739
740 if (strcmp(token, "none") == 0 || strcmp(token, "-1") == 0) {
741 *bptr = static_cast<size_t>(-1);
742 return;
743 }
744
745 d = xatof(token);
746
747 m = u; /* default to 'units' if none specified */
748
749 if (0.0 == d)
750 (void) 0;
751 else if ((token = strtok(NULL, w_space)) == NULL)
752 debug(3, 0) ("WARNING: No units on '%s', assuming %f %s\n",
753 config_input_line, d, units);
754 else if ((m = parseBytesUnits(token)) == 0)
755 self_destruct();
756
757 *bptr = static_cast<size_t>(m * d / u);
758
759 if (static_cast<double>(*bptr) != m * d / u)
760 self_destruct();
761 }
762
763 static size_t
764 parseBytesUnits(const char *unit)
765 {
766 if (!strncasecmp(unit, B_BYTES_STR, strlen(B_BYTES_STR)))
767 return 1;
768
769 if (!strncasecmp(unit, B_KBYTES_STR, strlen(B_KBYTES_STR)))
770 return 1 << 10;
771
772 if (!strncasecmp(unit, B_MBYTES_STR, strlen(B_MBYTES_STR)))
773 return 1 << 20;
774
775 if (!strncasecmp(unit, B_GBYTES_STR, strlen(B_GBYTES_STR)))
776 return 1 << 30;
777
778 debug(3, 1) ("parseBytesUnits: unknown bytes unit '%s'\n", unit);
779
780 return 0;
781 }
782
783 /*****************************************************************************
784 * Max
785 *****************************************************************************/
786
787 static void
788 dump_acl(StoreEntry * entry, const char *name, ACL * ae)
789 {
790 wordlist *w;
791 wordlist *v;
792
793 while (ae != NULL) {
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;
810 }
811 }
812
813 static void
814 parse_acl(ACL ** ae)
815 {
816 ACL::ParseAclLine(ae);
817 }
818
819 static void
820 free_acl(ACL ** ae)
821 {
822 aclDestroyAcls(ae);
823 }
824
825 static void
826 dump_acl_list(StoreEntry * entry, acl_list * head)
827 {
828 acl_list *l;
829
830 for (l = head; l; l = l->next) {
831 storeAppendPrintf(entry, " %s%s",
832 l->op ? null_string : "!",
833 l->_acl->name);
834 }
835 }
836
837 void
838 dump_acl_access(StoreEntry * entry, const char *name, acl_access * head)
839 {
840 acl_access *l;
841
842 for (l = head; l; l = l->next) {
843 storeAppendPrintf(entry, "%s %s",
844 name,
845 l->allow ? "Allow" : "Deny");
846 dump_acl_list(entry, l->aclList);
847 storeAppendPrintf(entry, "\n");
848 }
849 }
850
851 static void
852 parse_acl_access(acl_access ** head)
853 {
854 aclParseAccessLine(head);
855 }
856
857 static void
858 free_acl_access(acl_access ** head)
859 {
860 aclDestroyAccessList(head);
861 }
862
863 static void
864
865 dump_address(StoreEntry * entry, const char *name, struct in_addr addr)
866 {
867 storeAppendPrintf(entry, "%s %s\n", name, inet_ntoa(addr));
868 }
869
870 static void
871
872 parse_address(struct in_addr *addr)
873 {
874
875 const struct hostent *hp;
876 char *token = strtok(NULL, w_space);
877
878 if (token == NULL)
879 self_destruct();
880
881 if (safe_inet_addr(token, addr) == 1)
882 (void) 0;
883 else if ((hp = gethostbyname(token))) /* dont use ipcache */
884 *addr = inaddrFromHostent(hp);
885 else
886 self_destruct();
887 }
888
889 static void
890
891 free_address(struct in_addr *addr)
892 {
893
894 memset(addr, '\0', sizeof(struct in_addr));
895 }
896
897 CBDATA_TYPE(acl_address);
898
899 static void
900 dump_acl_address(StoreEntry * entry, const char *name, acl_address * head)
901 {
902 acl_address *l;
903
904 for (l = head; l; l = l->next) {
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");
913 }
914 }
915
916 static void
917 freed_acl_address(void *data)
918 {
919 acl_address *l = static_cast<acl_address *>(data);
920 aclDestroyAclList(&l->aclList);
921 }
922
923 static void
924 parse_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);
931 aclParseAclList(&l->aclList);
932
933 while (*tail)
934 tail = &(*tail)->next;
935
936 *tail = l;
937 }
938
939 static void
940 free_acl_address(acl_address ** head)
941 {
942 while (*head) {
943 acl_address *l = *head;
944 *head = l->next;
945 cbdataFree(l);
946 }
947 }
948
949 CBDATA_TYPE(acl_tos);
950
951 static void
952 dump_acl_tos(StoreEntry * entry, const char *name, acl_tos * head)
953 {
954 acl_tos *l;
955
956 for (l = head; l; l = l->next) {
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");
965 }
966 }
967
968 static void
969 freed_acl_tos(void *data)
970 {
971 acl_tos *l = static_cast<acl_tos *>(data);
972 aclDestroyAclList(&l->aclList);
973 }
974
975 static void
976 parse_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);
983
984 if (!token)
985 self_destruct();
986
987 if (sscanf(token, "0x%x%c", &tos, &junk) != 1)
988 self_destruct();
989
990 if (tos < 0 || tos > 255)
991 self_destruct();
992
993 CBDATA_INIT_TYPE_FREECB(acl_tos, freed_acl_tos);
994
995 l = cbdataAlloc(acl_tos);
996
997 l->tos = tos;
998
999 aclParseAclList(&l->aclList);
1000
1001 while (*tail)
1002 tail = &(*tail)->next;
1003
1004 *tail = l;
1005 }
1006
1007 static void
1008 free_acl_tos(acl_tos ** head)
1009 {
1010 while (*head) {
1011 acl_tos *l = *head;
1012 *head = l->next;
1013 l->next = NULL;
1014 cbdataFree(l);
1015 }
1016 }
1017
1018 CBDATA_TYPE(acl_size_t);
1019
1020 static void
1021 dump_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
1037 static void
1038 freed_acl_b_size_t(void *data)
1039 {
1040 acl_size_t *l = static_cast<acl_size_t *>(data);
1041 aclDestroyAclList(&l->aclList);
1042 }
1043
1044 static void
1045 parse_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
1064 static void
1065 free_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
1075 #if DELAY_POOLS
1076
1077 #include "DelayPools.h"
1078 #include "DelayConfig.h"
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
1089 static void
1090 free_delay_pool_count(DelayConfig * cfg)
1091 {
1092 cfg->freePoolCount();
1093 }
1094
1095 static void
1096 dump_delay_pool_count(StoreEntry * entry, const char *name, DelayConfig &cfg)
1097 {
1098 cfg.dumpPoolCount (entry, name);
1099 }
1100
1101 static void
1102 parse_delay_pool_count(DelayConfig * cfg)
1103 {
1104 cfg->parsePoolCount();
1105 }
1106
1107 static void
1108 parse_delay_pool_class(DelayConfig * cfg)
1109 {
1110 cfg->parsePoolClass();
1111 }
1112
1113 static void
1114 parse_delay_pool_rates(DelayConfig * cfg)
1115 {
1116 cfg->parsePoolRates();
1117 }
1118
1119 static void
1120 parse_delay_pool_access(DelayConfig * cfg)
1121 {
1122 cfg->parsePoolAccess();
1123 }
1124
1125 #endif
1126
1127 #if HTTP_VIOLATIONS
1128 static void
1129 dump_http_header_access(StoreEntry * entry, const char *name, header_mangler header[])
1130 {
1131 int i;
1132
1133 for (i = 0; i < HDR_ENUM_END; i++) {
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 }
1139 }
1140 }
1141
1142 static void
1143 parse_http_header_access(header_mangler header[])
1144 {
1145 int id, i;
1146 char *t = NULL;
1147
1148 if ((t = strtok(NULL, w_space)) == NULL) {
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;
1153 }
1154
1155 /* Now lookup index of header. */
1156 id = httpHeaderIdByNameDef(t, strlen(t));
1157
1158 if (strcmp(t, "All") == 0)
1159 id = HDR_ENUM_END;
1160 else if (strcmp(t, "Other") == 0)
1161 id = HDR_OTHER;
1162 else if (id == -1) {
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;
1167 }
1168
1169 if (id != HDR_ENUM_END) {
1170 parse_acl_access(&header[id].access_list);
1171 } else {
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 }
1182 }
1183 }
1184
1185 static void
1186 free_http_header_access(header_mangler header[])
1187 {
1188 int i;
1189
1190 for (i = 0; i < HDR_ENUM_END; i++) {
1191 free_acl_access(&header[i].access_list);
1192 }
1193 }
1194
1195 static void
1196 dump_http_header_replace(StoreEntry * entry, const char *name, header_mangler
1197 header[])
1198 {
1199 int i;
1200
1201 for (i = 0; i < HDR_ENUM_END; i++) {
1202 if (NULL == header[i].replacement)
1203 continue;
1204
1205 storeAppendPrintf(entry, "%s %s %s\n", name, httpHeaderNameById(i),
1206 header[i].replacement);
1207 }
1208 }
1209
1210 static void
1211 parse_http_header_replace(header_mangler header[])
1212 {
1213 int id, i;
1214 char *t = NULL;
1215
1216 if ((t = strtok(NULL, w_space)) == NULL) {
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;
1221 }
1222
1223 /* Now lookup index of header. */
1224 id = httpHeaderIdByNameDef(t, strlen(t));
1225
1226 if (strcmp(t, "All") == 0)
1227 id = HDR_ENUM_END;
1228 else if (strcmp(t, "Other") == 0)
1229 id = HDR_OTHER;
1230 else if (id == -1) {
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;
1236 }
1237
1238 if (id != HDR_ENUM_END) {
1239 if (header[id].replacement != NULL)
1240 safe_free(header[id].replacement);
1241
1242 header[id].replacement = xstrdup(t + strlen(t) + 1);
1243 } else {
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 }
1250 }
1251 }
1252
1253 static void
1254 free_http_header_replace(header_mangler header[])
1255 {
1256 int i;
1257
1258 for (i = 0; i < HDR_ENUM_END; i++) {
1259 if (header[i].replacement != NULL)
1260 safe_free(header[i].replacement);
1261 }
1262 }
1263
1264 #endif
1265
1266
1267 static void
1268 dump_cachedir(StoreEntry * entry, const char *name, _SquidConfig::_cacheSwap swap)
1269 {
1270 SwapDir *s;
1271 int i;
1272 assert (entry);
1273
1274 for (i = 0; i < swap.n_configured; i++) {
1275 s = swap.swapDirs[i];
1276 storeAppendPrintf(entry, "%s %s %s", name, s->type(), s->path);
1277 s->dump(*entry);
1278 storeAppendPrintf(entry, "\n");
1279 }
1280 }
1281
1282
1283 static int
1284 check_null_cachedir(_SquidConfig::_cacheSwap swap)
1285 {
1286 return swap.swapDirs == NULL;
1287 }
1288
1289 static int
1290 check_null_string(char *s)
1291 {
1292 return s == NULL;
1293 }
1294
1295 static void
1296 parse_authparam(authConfig * config)
1297 {
1298 char *type_str;
1299 char *param_str;
1300
1301 if ((type_str = strtok(NULL, w_space)) == NULL)
1302 self_destruct();
1303
1304 if ((param_str = strtok(NULL, w_space)) == NULL)
1305 self_destruct();
1306
1307 /* find a configuration for the scheme */
1308 AuthConfig *scheme = AuthConfig::Find (type_str);
1309
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;
1317 }
1318
1319 config->push_back(theScheme->createConfig());
1320 scheme = config->back();
1321 assert (scheme);
1322 }
1323
1324 scheme->parse(scheme, config->size(), param_str);
1325 }
1326
1327 static void
1328 free_authparam(authConfig * cfg)
1329 {
1330 AuthConfig *scheme;
1331 /* DON'T FREE THESE FOR RECONFIGURE */
1332
1333 if (reconfiguring)
1334 return;
1335
1336 while (cfg->size()) {
1337 scheme = cfg->pop_back();
1338 scheme->done();
1339 }
1340 }
1341
1342 static void
1343 dump_authparam(StoreEntry * entry, const char *name, authConfig cfg)
1344 {
1345 for (authConfig::iterator i = cfg.begin(); i != cfg.end(); ++i)
1346 (*i)->dump(entry, name, (*i));
1347 }
1348
1349 void
1350 allocate_new_swapdir(_SquidConfig::_cacheSwap * swap)
1351 {
1352 if (swap->swapDirs == NULL) {
1353 swap->n_allocated = 4;
1354 swap->swapDirs = static_cast<SwapDir **>(xcalloc(swap->n_allocated, sizeof(SwapDir *)));
1355 }
1356
1357 if (swap->n_allocated == swap->n_configured) {
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;
1364 }
1365 }
1366
1367 /* TODO: just return the object, the # is irrelevant */
1368 static int
1369 find_fstype(char *type)
1370 {
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;
1374
1375 return (-1);
1376 }
1377
1378 static void
1379 parse_cachedir(_SquidConfig::_cacheSwap * swap)
1380 {
1381 char *type_str;
1382 char *path_str;
1383 SwapDir *sd;
1384 int i;
1385 int fs;
1386
1387 if ((type_str = strtok(NULL, w_space)) == NULL)
1388 self_destruct();
1389
1390 if ((path_str = strtok(NULL, w_space)) == NULL)
1391 self_destruct();
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++) {
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 }
1427 }
1428
1429 assert(swap->n_configured < 63); /* 7 bits, signed */
1430
1431 fs = find_fstype(type_str);
1432
1433 if (fs < 0) {
1434 /* If we get here, we didn't find a matching cache_dir type */
1435 fatalf("Unknown cache_dir type '%s'\n", type_str);
1436 }
1437
1438 allocate_new_swapdir(swap);
1439 swap->swapDirs[swap->n_configured] = StoreFileSystem::FileSystems().items[fs]->createSwapDir();
1440 sd = swap->swapDirs[swap->n_configured];
1441 /* parse the FS parameters and options */
1442 sd->parse(swap->n_configured, path_str);
1443 ++swap->n_configured;
1444 /* Update the max object size */
1445 update_maxobjsize();
1446 }
1447
1448 static void
1449 free_cachedir(_SquidConfig::_cacheSwap * swap)
1450 {
1451 int i;
1452 /* DON'T FREE THESE FOR RECONFIGURE */
1453
1454 if (reconfiguring)
1455 return;
1456
1457 for (i = 0; i < swap->n_configured; i++) {
1458 SwapDir * s = swap->swapDirs[i];
1459 swap->swapDirs[i] = NULL;
1460 delete s;
1461 }
1462
1463 safe_free(swap->swapDirs);
1464 swap->swapDirs = NULL;
1465 swap->n_allocated = 0;
1466 swap->n_configured = 0;
1467 }
1468
1469 static const char *
1470 peer_type_str(const peer_t type)
1471 {
1472 switch (type) {
1473
1474 case PEER_PARENT:
1475 return "parent";
1476 break;
1477
1478 case PEER_SIBLING:
1479 return "sibling";
1480 break;
1481
1482 case PEER_MULTICAST:
1483 return "multicast";
1484 break;
1485
1486 default:
1487 return "unknown";
1488 break;
1489 }
1490 }
1491
1492 static void
1493 dump_peer(StoreEntry * entry, const char *name, peer * p)
1494 {
1495 domain_ping *d;
1496 domain_type *t;
1497 LOCAL_ARRAY(char, xname, 128);
1498
1499 while (p != NULL) {
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;
1528 }
1529 }
1530
1531 static void
1532 parse_peer(peer ** head)
1533 {
1534 char *token = NULL;
1535 peer *p;
1536 int i;
1537 CBDATA_INIT_TYPE_FREECB(peer, peerDestroy);
1538 p = cbdataAlloc(peer);
1539 p->http_port = CACHE_HTTP_PORT;
1540 p->icp.port = CACHE_ICP_PORT;
1541 p->weight = 1;
1542 p->basetime = 0;
1543 p->stats.logged_state = PEER_ALIVE;
1544
1545 if ((token = strtok(NULL, w_space)) == NULL)
1546 self_destruct();
1547
1548 p->host = xstrdup(token);
1549
1550 p->name = xstrdup(token);
1551
1552 if ((token = strtok(NULL, w_space)) == NULL)
1553 self_destruct();
1554
1555 p->type = parseNeighborType(token);
1556
1557 i = GetInteger();
1558
1559 p->http_port = (u_short) i;
1560
1561 i = GetInteger();
1562
1563 p->icp.port = (u_short) i;
1564
1565 while ((token = strtok(NULL, w_space))) {
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;
1596 #if USE_HTCP
1597
1598 } else if (!strcasecmp(token, "htcp")) {
1599 p->options.htcp = 1;
1600 #endif
1601
1602 } else if (!strcasecmp(token, "no-netdb-exchange")) {
1603 p->options.no_netdb_exchange = 1;
1604 #if USE_CARP
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
1612 #endif
1613 #if DELAY_POOLS
1614
1615 } else if (!strcasecmp(token, "no-delay")) {
1616 p->options.no_delay = 1;
1617 #endif
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);
1624 #if USE_CACHE_DIGESTS
1625
1626 } else if (!strncasecmp(token, "digest-url=", 11)) {
1627 p->digest_url = xstrdup(token + 11);
1628 #endif
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
1647 #if USE_SSL
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);
1677 #endif
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 }
1689 }
1690
1691 if (peerFindByName(p->name))
1692 fatalf("ERROR: cache_peer %s specified twice\n", p->name);
1693
1694 if (p->weight < 1)
1695 p->weight = 1;
1696
1697 p->icp.version = ICP_VERSION_CURRENT;
1698
1699 p->tcp_up = PEER_TCP_MAGIC_COUNT;
1700
1701 p->test_fd = -1;
1702
1703 #if USE_CACHE_DIGESTS
1704
1705 if (!p->options.no_digest) {
1706 /* XXX This looks odd.. who has the original pointer
1707 * then?
1708 */
1709 PeerDigest *pd = peerDigestCreate(p);
1710 p->digest = cbdataReference(pd);
1711 }
1712
1713 #endif
1714 #if USE_SSL
1715 if (p->use_ssl) {
1716 p->sslContext = sslCreateClientContext(p->sslcert, p->sslkey, p->sslversion, p->sslcipher, p->ssloptions, p->sslflags, p->sslcafile, p->sslcapath);
1717 }
1718
1719 #endif
1720 while (*head != NULL)
1721 head = &(*head)->next;
1722
1723 *head = p;
1724
1725 Config.npeers++;
1726
1727 peerClearRR(p);
1728 }
1729
1730 static void
1731 free_peer(peer ** P)
1732 {
1733 peer *p;
1734
1735 while ((p = *P) != NULL) {
1736 *P = p->next;
1737 #if USE_CACHE_DIGESTS
1738
1739 cbdataReferenceDone(p->digest);
1740 #endif
1741
1742 cbdataFree(p);
1743 }
1744
1745 Config.npeers = 0;
1746 }
1747
1748 static void
1749 dump_cachemgrpasswd(StoreEntry * entry, const char *name, cachemgr_passwd * list)
1750 {
1751 wordlist *w;
1752
1753 while (list != NULL) {
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;
1765 }
1766 }
1767
1768 static void
1769 parse_cachemgrpasswd(cachemgr_passwd ** head)
1770 {
1771 char *passwd = NULL;
1772 wordlist *actions = NULL;
1773 cachemgr_passwd *p;
1774 cachemgr_passwd **P;
1775 parse_string(&passwd);
1776 parse_wordlist(&actions);
1777 p = static_cast<cachemgr_passwd *>(xcalloc(1, sizeof(cachemgr_passwd)));
1778 p->passwd = passwd;
1779 p->actions = actions;
1780
1781 for (P = head; *P; P = &(*P)->next) {
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 }
1802 }
1803
1804 *P = p;
1805 }
1806
1807 static void
1808 free_cachemgrpasswd(cachemgr_passwd ** head)
1809 {
1810 cachemgr_passwd *p;
1811
1812 while ((p = *head) != NULL) {
1813 *head = p->next;
1814 xfree(p->passwd);
1815 wordlistDestroy(&p->actions);
1816 xfree(p);
1817 }
1818 }
1819
1820 static void
1821 dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var)
1822 {
1823 acl_name_list *a;
1824
1825 while (var != NULL) {
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;
1834 }
1835 }
1836
1837 static void
1838 parse_denyinfo(acl_deny_info_list ** var)
1839 {
1840 aclParseDenyInfoLine(var);
1841 }
1842
1843 void
1844 free_denyinfo(acl_deny_info_list ** list)
1845 {
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;
1850
1851 for (a = *list; a; a = a_next) {
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;
1861 }
1862
1863 *list = NULL;
1864 }
1865
1866 static void
1867 parse_peer_access(void)
1868 {
1869 char *host = NULL;
1870 peer *p;
1871
1872 if (!(host = strtok(NULL, w_space)))
1873 self_destruct();
1874
1875 if ((p = peerFindByName(host)) == NULL) {
1876 debug(15, 0) ("%s, line %d: No cache_peer '%s'\n",
1877 cfg_filename, config_lineno, host);
1878 return;
1879 }
1880
1881 aclParseAccessLine(&p->access);
1882 }
1883
1884 static void
1885 parse_hostdomain(void)
1886 {
1887 char *host = NULL;
1888 char *domain = NULL;
1889
1890 if (!(host = strtok(NULL, w_space)))
1891 self_destruct();
1892
1893 while ((domain = strtok(NULL, list_sep))) {
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;
1918 }
1919 }
1920
1921 static void
1922 parse_hostdomaintype(void)
1923 {
1924 char *host = NULL;
1925 char *type = NULL;
1926 char *domain = NULL;
1927
1928 if (!(host = strtok(NULL, w_space)))
1929 self_destruct();
1930
1931 if (!(type = strtok(NULL, w_space)))
1932 self_destruct();
1933
1934 while ((domain = strtok(NULL, list_sep))) {
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;
1953 }
1954 }
1955
1956 #if UNUSED_CODE
1957 static void
1958 dump_ushortlist(StoreEntry * entry, const char *name, ushortlist * u)
1959 {
1960 while (u) {
1961 storeAppendPrintf(entry, "%s %d\n", name, (int) u->i);
1962 u = u->next;
1963 }
1964 }
1965
1966 static int
1967 check_null_ushortlist(ushortlist * u)
1968 {
1969 return u == NULL;
1970 }
1971
1972 static void
1973 parse_ushortlist(ushortlist ** P)
1974 {
1975 char *token;
1976 int i;
1977 ushortlist *u;
1978 ushortlist **U;
1979
1980 while ((token = strtok(NULL, w_space))) {
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;
1995 }
1996 }
1997
1998 static void
1999 free_ushortlist(ushortlist ** P)
2000 {
2001 ushortlist *u;
2002
2003 while ((u = *P) != NULL) {
2004 *P = u->next;
2005 xfree(u);
2006 }
2007 }
2008
2009 #endif
2010
2011 static void
2012 dump_int(StoreEntry * entry, const char *name, int var)
2013 {
2014 storeAppendPrintf(entry, "%s %d\n", name, var);
2015 }
2016
2017 void
2018 parse_int(int *var)
2019 {
2020 int i;
2021 i = GetInteger();
2022 *var = i;
2023 }
2024
2025 static void
2026 free_int(int *var)
2027 {
2028 *var = 0;
2029 }
2030
2031 static void
2032 dump_onoff(StoreEntry * entry, const char *name, int var)
2033 {
2034 storeAppendPrintf(entry, "%s %s\n", name, var ? "on" : "off");
2035 }
2036
2037 void
2038 parse_onoff(int *var)
2039 {
2040 char *token = strtok(NULL, w_space);
2041
2042 if (token == NULL)
2043 self_destruct();
2044
2045 if (!strcasecmp(token, "on") || !strcasecmp(token, "enable"))
2046 *var = 1;
2047 else
2048 *var = 0;
2049 }
2050
2051 #define free_onoff free_int
2052 #define dump_eol dump_string
2053 #define free_eol free_string
2054 #define dump_debug dump_string
2055 #define free_debug free_string
2056
2057 static void
2058 dump_refreshpattern(StoreEntry * entry, const char *name, refresh_t * head)
2059 {
2060 while (head != NULL) {
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);
2068 #if HTTP_VIOLATIONS
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
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
2094 #endif
2095
2096 storeAppendPrintf(entry, "\n");
2097
2098 head = head->next;
2099 }
2100 }
2101
2102 static void
2103 parse_refreshpattern(refresh_t ** head)
2104 {
2105 char *token;
2106 char *pattern;
2107 time_t min = 0;
2108 double pct = 0.0;
2109 time_t max = 0;
2110 #if HTTP_VIOLATIONS
2111
2112 int override_expire = 0;
2113 int override_lastmod = 0;
2114 int reload_into_ims = 0;
2115 int ignore_reload = 0;
2116 int ignore_no_cache = 0;
2117 int ignore_no_store = 0;
2118 int ignore_private = 0;
2119 int ignore_auth = 0;
2120 #endif
2121
2122 int i;
2123 refresh_t *t;
2124 regex_t comp;
2125 int errcode;
2126 int flags = REG_EXTENDED | REG_NOSUB;
2127
2128 if ((token = strtok(NULL, w_space)) == NULL)
2129 self_destruct();
2130
2131 if (strcmp(token, "-i") == 0) {
2132 flags |= REG_ICASE;
2133 token = strtok(NULL, w_space);
2134 } else if (strcmp(token, "+i") == 0) {
2135 flags &= ~REG_ICASE;
2136 token = strtok(NULL, w_space);
2137 }
2138
2139 if (token == NULL)
2140 self_destruct();
2141
2142 pattern = xstrdup(token);
2143
2144 i = GetInteger(); /* token: min */
2145
2146 min = (time_t) (i * 60); /* convert minutes to seconds */
2147
2148 i = GetInteger(); /* token: pct */
2149
2150 pct = (double) i / 100.0;
2151
2152 i = GetInteger(); /* token: max */
2153
2154 max = (time_t) (i * 60); /* convert minutes to seconds */
2155
2156 /* Options */
2157 while ((token = strtok(NULL, w_space)) != NULL) {
2158 #if HTTP_VIOLATIONS
2159
2160 if (!strcmp(token, "override-expire"))
2161 override_expire = 1;
2162 else if (!strcmp(token, "override-lastmod"))
2163 override_lastmod = 1;
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;
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
2181 #endif
2182
2183 debug(22, 0) ("redreshAddToList: Unknown option '%s': %s\n",
2184 pattern, token);
2185 }
2186
2187 if ((errcode = regcomp(&comp, pattern, flags)) != 0) {
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;
2195 }
2196
2197 pct = pct < 0.0 ? 0.0 : pct;
2198 max = max < 0 ? 0 : max;
2199 t = static_cast<refresh_t *>(xcalloc(1, sizeof(refresh_t)));
2200 t->pattern = (char *) xstrdup(pattern);
2201 t->compiled_pattern = comp;
2202 t->min = min;
2203 t->pct = pct;
2204 t->max = max;
2205
2206 if (flags & REG_ICASE)
2207 t->flags.icase = 1;
2208
2209 #if HTTP_VIOLATIONS
2210
2211 if (override_expire)
2212 t->flags.override_expire = 1;
2213
2214 if (override_lastmod)
2215 t->flags.override_lastmod = 1;
2216
2217 if (reload_into_ims)
2218 t->flags.reload_into_ims = 1;
2219
2220 if (ignore_reload)
2221 t->flags.ignore_reload = 1;
2222
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
2235 #endif
2236
2237 t->next = NULL;
2238
2239 while (*head)
2240 head = &(*head)->next;
2241
2242 *head = t;
2243
2244 safe_free(pattern);
2245 }
2246
2247 #if UNUSED_CODE
2248 static int
2249 check_null_refreshpattern(refresh_t * data)
2250 {
2251 return data == NULL;
2252 }
2253
2254 #endif
2255
2256 static void
2257 free_refreshpattern(refresh_t ** head)
2258 {
2259 refresh_t *t;
2260
2261 while ((t = *head) != NULL) {
2262 *head = t->next;
2263 safe_free(t->pattern);
2264 regfree(&t->compiled_pattern);
2265 safe_free(t);
2266 }
2267 }
2268
2269 static void
2270 dump_string(StoreEntry * entry, const char *name, char *var)
2271 {
2272 if (var != NULL)
2273 storeAppendPrintf(entry, "%s %s\n", name, var);
2274 }
2275
2276 static void
2277 parse_string(char **var)
2278 {
2279 char *token = strtok(NULL, w_space);
2280 safe_free(*var);
2281
2282 if (token == NULL)
2283 self_destruct();
2284
2285 *var = xstrdup(token);
2286 }
2287
2288 static void
2289 free_string(char **var)
2290 {
2291 safe_free(*var);
2292 }
2293
2294 void
2295 parse_eol(char *volatile *var)
2296 {
2297 unsigned char *token = (unsigned char *) strtok(NULL, null_string);
2298 safe_free(*var);
2299
2300 if (token == NULL)
2301 self_destruct();
2302
2303 while (*token && isspace(*token))
2304 token++;
2305
2306 if (!*token)
2307 self_destruct();
2308
2309 *var = xstrdup((char *) token);
2310 }
2311
2312 void
2313 parse_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
2321 static void
2322 dump_time_t(StoreEntry * entry, const char *name, time_t var)
2323 {
2324 storeAppendPrintf(entry, "%s %d seconds\n", name, (int) var);
2325 }
2326
2327 void
2328 parse_time_t(time_t * var)
2329 {
2330 parseTimeLine(var, T_SECOND_STR);
2331 }
2332
2333 static void
2334 free_time_t(time_t * var)
2335 {
2336 *var = 0;
2337 }
2338
2339 static void
2340 dump_size_t(StoreEntry * entry, const char *name, size_t var)
2341 {
2342 storeAppendPrintf(entry, "%s %d\n", name, (int) var);
2343 }
2344
2345 static void
2346 dump_b_size_t(StoreEntry * entry, const char *name, size_t var)
2347 {
2348 storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_BYTES_STR);
2349 }
2350
2351 static void
2352 dump_kb_size_t(StoreEntry * entry, const char *name, size_t var)
2353 {
2354 storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_KBYTES_STR);
2355 }
2356
2357 static void
2358 parse_size_t(size_t * var)
2359 {
2360 int i;
2361 i = GetInteger();
2362 *var = (size_t) i;
2363 }
2364
2365 static void
2366 parse_b_size_t(size_t * var)
2367 {
2368 parseBytesLine(var, B_BYTES_STR);
2369 }
2370
2371 static void
2372 parse_kb_size_t(size_t * var)
2373 {
2374 parseBytesLine(var, B_KBYTES_STR);
2375 }
2376
2377 static void
2378 free_size_t(size_t * var)
2379 {
2380 *var = 0;
2381 }
2382
2383 #define free_b_size_t free_size_t
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
2387
2388 static void
2389 dump_ushort(StoreEntry * entry, const char *name, u_short var)
2390 {
2391 storeAppendPrintf(entry, "%s %d\n", name, var);
2392 }
2393
2394 static void
2395 free_ushort(u_short * u)
2396 {
2397 *u = 0;
2398 }
2399
2400 static void
2401 parse_ushort(u_short * var)
2402 {
2403 ConfigParser::ParseUShort(var);
2404 }
2405
2406 void
2407 ConfigParser::ParseUShort(u_short *var)
2408 {
2409 int i;
2410
2411 i = GetInteger();
2412
2413 if (i < 0)
2414 i = 0;
2415
2416 *var = (u_short) i;
2417 }
2418
2419 static void
2420 dump_wordlist(StoreEntry * entry, const char *name, wordlist * list)
2421 {
2422 while (list != NULL) {
2423 storeAppendPrintf(entry, "%s %s\n", name, list->key);
2424 list = list->next;
2425 }
2426 }
2427
2428 void
2429 parse_wordlist(wordlist ** list)
2430 {
2431 char *token;
2432 char *t = strtok(NULL, "");
2433
2434 while ((token = strwordtok(NULL, &t)))
2435 wordlistAdd(list, token);
2436 }
2437
2438 static int
2439 check_null_wordlist(wordlist * w)
2440 {
2441 return w == NULL;
2442 }
2443
2444 static int
2445 check_null_acl_access(acl_access * a)
2446 {
2447 return a == NULL;
2448 }
2449
2450 #define free_wordlist wordlistDestroy
2451
2452 #define free_uri_whitespace free_int
2453
2454 static void
2455 parse_uri_whitespace(int *var)
2456 {
2457 char *token = strtok(NULL, w_space);
2458
2459 if (token == NULL)
2460 self_destruct();
2461
2462 if (!strcasecmp(token, "strip"))
2463 *var = URI_WHITESPACE_STRIP;
2464 else if (!strcasecmp(token, "deny"))
2465 *var = URI_WHITESPACE_DENY;
2466 else if (!strcasecmp(token, "allow"))
2467 *var = URI_WHITESPACE_ALLOW;
2468 else if (!strcasecmp(token, "encode"))
2469 *var = URI_WHITESPACE_ENCODE;
2470 else if (!strcasecmp(token, "chop"))
2471 *var = URI_WHITESPACE_CHOP;
2472 else
2473 self_destruct();
2474 }
2475
2476
2477 static void
2478 dump_uri_whitespace(StoreEntry * entry, const char *name, int var)
2479 {
2480 const char *s;
2481
2482 if (var == URI_WHITESPACE_ALLOW)
2483 s = "allow";
2484 else if (var == URI_WHITESPACE_ENCODE)
2485 s = "encode";
2486 else if (var == URI_WHITESPACE_CHOP)
2487 s = "chop";
2488 else if (var == URI_WHITESPACE_DENY)
2489 s = "deny";
2490 else
2491 s = "strip";
2492
2493 storeAppendPrintf(entry, "%s %s\n", name, s);
2494 }
2495
2496 static void
2497 free_removalpolicy(RemovalPolicySettings ** settings)
2498 {
2499 if (!*settings)
2500 return;
2501
2502 free_string(&(*settings)->type);
2503
2504 free_wordlist(&(*settings)->args);
2505
2506 xfree(*settings);
2507
2508 *settings = NULL;
2509 }
2510
2511 static void
2512 parse_removalpolicy(RemovalPolicySettings ** settings)
2513 {
2514 if (*settings)
2515 free_removalpolicy(settings);
2516
2517 *settings = static_cast<RemovalPolicySettings *>(xcalloc(1, sizeof(**settings)));
2518
2519 parse_string(&(*settings)->type);
2520
2521 parse_wordlist(&(*settings)->args);
2522 }
2523
2524 static void
2525 dump_removalpolicy(StoreEntry * entry, const char *name, RemovalPolicySettings * settings)
2526 {
2527 wordlist *args;
2528 storeAppendPrintf(entry, "%s %s", name, settings->type);
2529 args = settings->args;
2530
2531 while (args) {
2532 storeAppendPrintf(entry, " %s", args->key);
2533 args = args->next;
2534 }
2535
2536 storeAppendPrintf(entry, "\n");
2537 }
2538
2539
2540 #include "cf_parser.h"
2541
2542 peer_t
2543 parseNeighborType(const char *s)
2544 {
2545 if (!strcasecmp(s, "parent"))
2546 return PEER_PARENT;
2547
2548 if (!strcasecmp(s, "neighbor"))
2549 return PEER_SIBLING;
2550
2551 if (!strcasecmp(s, "neighbour"))
2552 return PEER_SIBLING;
2553
2554 if (!strcasecmp(s, "sibling"))
2555 return PEER_SIBLING;
2556
2557 if (!strcasecmp(s, "multicast"))
2558 return PEER_MULTICAST;
2559
2560 debug(15, 0) ("WARNING: Unknown neighbor type: %s\n", s);
2561
2562 return PEER_SIBLING;
2563 }
2564
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 */
2569 void
2570 parse_sockaddr_in_list_token(sockaddr_in_list ** head, char *token)
2571 {
2572 char *t;
2573 char *host;
2574
2575 const struct hostent *hp;
2576 unsigned short port;
2577 sockaddr_in_list *s;
2578
2579 host = NULL;
2580 port = 0;
2581
2582 if ((t = strchr(token, ':'))) {
2583 /* host:port */
2584 host = token;
2585 *t = '\0';
2586 port = (unsigned short) xatoi(t + 1);
2587
2588 if (0 == port)
2589 self_destruct();
2590 } else if ((port = xatoi(token)) > 0) {
2591 /* port */
2592 } else {
2593 self_destruct();
2594 }
2595
2596 s = static_cast<sockaddr_in_list *>(xcalloc(1, sizeof(*s)));
2597 s->s.sin_port = htons(port);
2598
2599 if (NULL == host)
2600 s->s.sin_addr = any_addr;
2601 else if (1 == safe_inet_addr(host, &s->s.sin_addr))
2602 (void) 0;
2603 else if ((hp = gethostbyname(host))) /* dont use ipcache */
2604 s->s.sin_addr = inaddrFromHostent(hp);
2605 else
2606 self_destruct();
2607
2608 while (*head)
2609 head = &(*head)->next;
2610
2611 *head = s;
2612 }
2613
2614 static void
2615 parse_sockaddr_in_list(sockaddr_in_list ** head)
2616 {
2617 char *token;
2618
2619 while ((token = strtok(NULL, w_space))) {
2620 parse_sockaddr_in_list_token(head, token);
2621 }
2622 }
2623
2624 static void
2625 dump_sockaddr_in_list(StoreEntry * e, const char *n, const sockaddr_in_list * s)
2626 {
2627 while (s) {
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;
2633 }
2634 }
2635
2636 static void
2637 free_sockaddr_in_list(sockaddr_in_list ** head)
2638 {
2639 sockaddr_in_list *s;
2640
2641 while ((s = *head) != NULL) {
2642 *head = s->next;
2643 xfree(s);
2644 }
2645 }
2646
2647 static int
2648 check_null_sockaddr_in_list(const sockaddr_in_list * s)
2649 {
2650 return NULL == s;
2651 }
2652
2653 #endif /* CURRENTLY_UNUSED */
2654
2655 static void
2656 parse_http_port_specification(http_port_list * s, char *token)
2657 {
2658 char *host = NULL;
2659
2660 const struct hostent *hp;
2661 unsigned short port = 0;
2662 char *t;
2663
2664 if ((t = strchr(token, ':'))) {
2665 /* host:port */
2666 host = token;
2667 *t = '\0';
2668 port = (unsigned short) atoi(t + 1);
2669
2670 if (0 == port)
2671 self_destruct();
2672 } else if ((port = atoi(token)) > 0) {
2673 /* port */
2674 } else {
2675 self_destruct();
2676 }
2677
2678 s->s.sin_port = htons(port);
2679
2680 if (NULL == host)
2681 s->s.sin_addr = any_addr;
2682 else if (1 == safe_inet_addr(host, &s->s.sin_addr))
2683 (void) 0;
2684 else if ((hp = gethostbyname(host))) {
2685 /* dont use ipcache */
2686 s->s.sin_addr = inaddrFromHostent(hp);
2687 s->defaultsite = xstrdup(host);
2688 } else
2689 self_destruct();
2690 }
2691
2692 static void
2693 parse_http_port_option(http_port_list * s, char *token)
2694 {
2695 if (strncmp(token, "defaultsite=", 12) == 0) {
2696 safe_free(s->defaultsite);
2697 s->defaultsite = xstrdup(token + 12);
2698 s->accel = 1;
2699 } else if (strncmp(token, "name=", 5) == 0) {
2700 safe_free(s->name);
2701 s->name = xstrdup(token + 5);
2702 } else if (strcmp(token, "transparent") == 0) {
2703 s->transparent = 1;
2704 } else if (strcmp(token, "vhost") == 0) {
2705 s->vhost = 1;
2706 s->accel = 1;
2707 } else if (strcmp(token, "vport") == 0) {
2708 s->vport = -1;
2709 s->accel = 1;
2710 } else if (strncmp(token, "vport=", 6) == 0) {
2711 s->vport = atoi(token + 6);
2712 s->accel = 1;
2713 } else if (strncmp(token, "protocol=", 9) == 0) {
2714 s->protocol = xstrdup(token + 9);
2715 s->accel = 1;
2716 } else if (strcmp(token, "accel") == 0) {
2717 s->accel = 1;
2718 } else {
2719 self_destruct();
2720 }
2721 }
2722
2723 static void
2724 free_generic_http_port_data(http_port_list * s)
2725 {
2726 safe_free(s->name);
2727 safe_free(s->defaultsite);
2728 }
2729
2730 static void
2731 cbdataFree_http_port(void *data)
2732 {
2733 free_generic_http_port_data((http_port_list *)data);
2734 }
2735
2736
2737 static http_port_list *
2738 create_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
2749 void
2750 add_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
2757 static void
2758 parse_http_port_list(http_port_list ** head)
2759 {
2760 char *token = strtok(NULL, w_space);
2761
2762 if (!token)
2763 self_destruct();
2764
2765 http_port_list *s = create_http_port(token);
2766
2767 /* parse options ... */
2768 while ((token = strtok(NULL, w_space))) {
2769 parse_http_port_option(s, token);
2770 }
2771
2772 while (*head)
2773 head = &(*head)->next;
2774
2775 *head = s;
2776 }
2777
2778 static void
2779 dump_generic_http_port(StoreEntry * e, const char *n, const http_port_list * s)
2780 {
2781 storeAppendPrintf(e, "%s %s:%d",
2782 n,
2783 inet_ntoa(s->s.sin_addr),
2784 ntohs(s->s.sin_port));
2785
2786 if (s->defaultsite)
2787 storeAppendPrintf(e, " defaultsite=%s", s->defaultsite);
2788
2789 if (s->transparent)
2790 storeAppendPrintf(e, " transparent");
2791
2792 if (s->vhost)
2793 storeAppendPrintf(e, " vhost");
2794
2795 if (s->vport)
2796 storeAppendPrintf(e, " vport");
2797 }
2798
2799 static void
2800 dump_http_port_list(StoreEntry * e, const char *n, const http_port_list * s)
2801 {
2802 while (s) {
2803 dump_generic_http_port(e, n, s);
2804 storeAppendPrintf(e, "\n");
2805 s = s->next;
2806 }
2807 }
2808
2809 static void
2810 free_http_port_list(http_port_list ** head)
2811 {
2812 http_port_list *s;
2813
2814 while ((s = *head) != NULL) {
2815 *head = s->next;
2816 cbdataFree(s);
2817 }
2818 }
2819
2820 #if UNUSED_CODE
2821 static int
2822 check_null_http_port_list(const http_port_list * s)
2823 {
2824 return NULL == s;
2825 }
2826
2827 #endif
2828
2829 #if USE_SSL
2830 static void
2831 cbdataFree_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
2839 static void
2840 parse_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);
2847
2848 if (!token)
2849 self_destruct();
2850
2851 s = cbdataAlloc(https_port_list);
2852
2853 s->http.protocol = xstrdup("https");
2854
2855 parse_http_port_specification(&s->http, token);
2856
2857 /* parse options ... */
2858 while ((token = strtok(NULL, w_space))) {
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);
2882 } else if (strncmp(token, "dhparams=", 9) == 0) {
2883 safe_free(s->dhfile);
2884 s->dhfile = xstrdup(token + 9);
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 }
2891 }
2892
2893 s->sslContext = sslCreateServerContext(s->cert, s->key, s->version, s->cipher, s->options, s->sslflags, s->clientca, s->cafile, s->capath, s->dhfile);
2894
2895 if (!s->sslContext)
2896 self_destruct();
2897
2898 while (*head)
2899 head = (https_port_list **)&(*head)->http.next;
2900
2901 *head = s;
2902 }
2903
2904 static void
2905 dump_https_port_list(StoreEntry * e, const char *n, const https_port_list * s)
2906 {
2907 while (s) {
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
2931 if (s->dhfile)
2932 storeAppendPrintf(e, " dhparams=%s", s->dhfile);
2933
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;
2940 }
2941 }
2942
2943 static void
2944 free_https_port_list(https_port_list ** head)
2945 {
2946 https_port_list *s;
2947
2948 while ((s = *head) != NULL) {
2949 *head = (https_port_list *) s->http.next;
2950 cbdataFree(s);
2951 }
2952 }
2953
2954 #if 0
2955 static int
2956 check_null_https_port_list(const https_port_list * s)
2957 {
2958 return NULL == s;
2959 }
2960
2961 #endif
2962
2963 #endif /* USE_SSL */
2964
2965 void
2966 configFreeMemory(void)
2967 {
2968 free_all();
2969 }
2970
2971 void
2972 requirePathnameExists(const char *name, const char *path)
2973 {
2974
2975 struct stat sb;
2976 char pathbuf[BUFSIZ];
2977 assert(path != NULL);
2978
2979 if (Config.chroot_dir) {
2980 snprintf(pathbuf, BUFSIZ, "%s/%s", Config.chroot_dir, path);
2981 path = pathbuf;
2982 }
2983
2984 if (stat(path, &sb) < 0)
2985 fatalf("%s %s: %s", name, path, xstrerror());
2986 }
2987
2988 char *
2989 strtokFile(void)
2990 {
2991 static int fromFile = 0;
2992 static FILE *wordFile = NULL;
2993
2994 char *t, *fn;
2995 LOCAL_ARRAY(char, buf, 256);
2996
2997 strtok_again:
2998
2999 if (!fromFile) {
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
3018 #ifdef _SQUID_WIN32_
3019 setmode(fileno(wordFile), O_TEXT);
3020
3021 #endif
3022
3023 fromFile = 1;
3024 } else {
3025 return t;
3026 }
3027 }
3028
3029 /* fromFile */
3030 if (fgets(buf, 256, wordFile) == NULL) {
3031 /* stop reading from file */
3032 fclose(wordFile);
3033 wordFile = NULL;
3034 fromFile = 0;
3035 goto strtok_again;
3036 } else {
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;
3060 }
3061 }
3062
3063 #include "AccessLogEntry.h"
3064 /* TODO: split out parsing somehow ...*/
3065 static void
3066 parse_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
3091 static void
3092 parse_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
3141 done:
3142 aclParseAclList(&cl->aclList);
3143
3144 while (*logs)
3145 logs = &(*logs)->next;
3146
3147 *logs = cl;
3148 }
3149
3150 static int
3151 check_null_access_log(customlog *customlog_definitions)
3152 {
3153 return customlog_definitions == NULL;
3154 }
3155
3156 static void
3157 dump_logformat(StoreEntry * entry, const char *name, logformat * definitions)
3158 {
3159 accessLogDumpLogFormat(entry, name, definitions);
3160 }
3161
3162 static void
3163 dump_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
3208 static void
3209 free_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
3219 static void
3220 free_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 }