]> git.ipfire.org Git - thirdparty/squid.git/blob - src/cache_cf.cc
50bcb536aacddcc80046eeb3617a51bc3e714d18
[thirdparty/squid.git] / src / cache_cf.cc
1
2 /*
3 * $Id: cache_cf.cc,v 1.455 2004/10/15 21:10:44 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 }
529 #endif
530 #if !HTTP_VIOLATIONS
531 Config.onoff.via = 1;
532 #else
533
534 if (!Config.onoff.via)
535 debug(22, 1) ("WARNING: HTTP requires the use of Via\n");
536
537 #endif
538
539 if (Config.Wais.relayHost) {
540 if (Config.Wais._peer)
541 cbdataFree(Config.Wais._peer);
542
543 CBDATA_INIT_TYPE_FREECB(peer, peerDestroy);
544
545 Config.Wais._peer = cbdataAlloc(peer);
546
547 Config.Wais._peer->host = xstrdup(Config.Wais.relayHost);
548
549 Config.Wais._peer->http_port = Config.Wais.relayPort;
550 }
551
552 if (aclPurgeMethodInUse(Config.accessList.http))
553 Config2.onoff.enable_purge = 1;
554
555 if (geteuid() == 0) {
556 if (NULL != Config.effectiveUser) {
557
558 struct passwd *pwd = getpwnam(Config.effectiveUser);
559
560 if (NULL == pwd)
561 /*
562 * Andres Kroonmaa <andre@online.ee>:
563 * Some getpwnam() implementations (Solaris?) require
564 * an available FD < 256 for opening a FILE* to the
565 * passwd file.
566 * DW:
567 * This should be safe at startup, but might still fail
568 * during reconfigure.
569 */
570 fatalf("getpwnam failed to find userid for effective user '%s'",
571 Config.effectiveUser);
572
573 Config2.effectiveUserID = pwd->pw_uid;
574
575 Config2.effectiveGroupID = pwd->pw_gid;
576 }
577 } else {
578 Config2.effectiveUserID = geteuid();
579 Config2.effectiveGroupID = getegid();
580 }
581
582 if (NULL != Config.effectiveGroup) {
583
584 struct group *grp = getgrnam(Config.effectiveGroup);
585
586 if (NULL == grp)
587 fatalf("getgrnam failed to find groupid for effective group '%s'",
588 Config.effectiveGroup);
589
590 Config2.effectiveGroupID = grp->gr_gid;
591 }
592
593 urlExtMethodConfigure();
594 #if USE_SSL
595
596 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);
597 #endif
598 }
599
600 /* Parse a time specification from the config file. Store the
601 * result in 'tptr', after converting it to 'units' */
602 static void
603 parseTimeLine(time_t * tptr, const char *units)
604 {
605 char *token;
606 double d;
607 time_t m;
608 time_t u;
609
610 if ((u = parseTimeUnits(units)) == 0)
611 self_destruct();
612
613 if ((token = strtok(NULL, w_space)) == NULL)
614 self_destruct();
615
616 d = xatof(token);
617
618 m = u; /* default to 'units' if none specified */
619
620 if (0 == d)
621 (void) 0;
622 else if ((token = strtok(NULL, w_space)) == NULL)
623 debug(3, 0) ("WARNING: No units on '%s', assuming %f %s\n",
624 config_input_line, d, units);
625 else if ((m = parseTimeUnits(token)) == 0)
626 self_destruct();
627
628 *tptr = static_cast<time_t> (m * d / u);
629 }
630
631 static int
632 parseTimeUnits(const char *unit)
633 {
634 if (!strncasecmp(unit, T_SECOND_STR, strlen(T_SECOND_STR)))
635 return 1;
636
637 if (!strncasecmp(unit, T_MINUTE_STR, strlen(T_MINUTE_STR)))
638 return 60;
639
640 if (!strncasecmp(unit, T_HOUR_STR, strlen(T_HOUR_STR)))
641 return 3600;
642
643 if (!strncasecmp(unit, T_DAY_STR, strlen(T_DAY_STR)))
644 return 86400;
645
646 if (!strncasecmp(unit, T_WEEK_STR, strlen(T_WEEK_STR)))
647 return 86400 * 7;
648
649 if (!strncasecmp(unit, T_FORTNIGHT_STR, strlen(T_FORTNIGHT_STR)))
650 return 86400 * 14;
651
652 if (!strncasecmp(unit, T_MONTH_STR, strlen(T_MONTH_STR)))
653 return 86400 * 30;
654
655 if (!strncasecmp(unit, T_YEAR_STR, strlen(T_YEAR_STR)))
656 return static_cast<int>(86400 * 365.2522);
657
658 if (!strncasecmp(unit, T_DECADE_STR, strlen(T_DECADE_STR)))
659 return static_cast<int>(86400 * 365.2522 * 10);
660
661 debug(3, 1) ("parseTimeUnits: unknown time unit '%s'\n", unit);
662
663 return 0;
664 }
665
666 static void
667 parseBytesLine(size_t * bptr, const char *units)
668 {
669 char *token;
670 double d;
671 size_t m;
672 size_t u;
673
674 if ((u = parseBytesUnits(units)) == 0)
675 self_destruct();
676
677 if ((token = strtok(NULL, w_space)) == NULL)
678 self_destruct();
679
680 if (strcmp(token, "none") == 0 || strcmp(token, "-1") == 0) {
681 *bptr = static_cast<size_t>(-1);
682 return;
683 }
684
685 d = xatof(token);
686
687 m = u; /* default to 'units' if none specified */
688
689 if (0.0 == d)
690 (void) 0;
691 else if ((token = strtok(NULL, w_space)) == NULL)
692 debug(3, 0) ("WARNING: No units on '%s', assuming %f %s\n",
693 config_input_line, d, units);
694 else if ((m = parseBytesUnits(token)) == 0)
695 self_destruct();
696
697 *bptr = static_cast<size_t>(m * d / u);
698
699 if (static_cast<double>(*bptr) != m * d / u)
700 self_destruct();
701 }
702
703 static size_t
704 parseBytesUnits(const char *unit)
705 {
706 if (!strncasecmp(unit, B_BYTES_STR, strlen(B_BYTES_STR)))
707 return 1;
708
709 if (!strncasecmp(unit, B_KBYTES_STR, strlen(B_KBYTES_STR)))
710 return 1 << 10;
711
712 if (!strncasecmp(unit, B_MBYTES_STR, strlen(B_MBYTES_STR)))
713 return 1 << 20;
714
715 if (!strncasecmp(unit, B_GBYTES_STR, strlen(B_GBYTES_STR)))
716 return 1 << 30;
717
718 debug(3, 1) ("parseBytesUnits: unknown bytes unit '%s'\n", unit);
719
720 return 0;
721 }
722
723 /*****************************************************************************
724 * Max
725 *****************************************************************************/
726
727 static void
728 dump_acl(StoreEntry * entry, const char *name, ACL * ae)
729 {
730 wordlist *w;
731 wordlist *v;
732
733 while (ae != NULL) {
734 debug(3, 3) ("dump_acl: %s %s\n", name, ae->name);
735 storeAppendPrintf(entry, "%s %s %s ",
736 name,
737 ae->name,
738 ae->typeString());
739 v = w = ae->dumpGeneric();
740
741 while (v != NULL) {
742 debug(3, 3) ("dump_acl: %s %s %s\n", name, ae->name, v->key);
743 storeAppendPrintf(entry, "%s ", v->key);
744 v = v->next;
745 }
746
747 storeAppendPrintf(entry, "\n");
748 wordlistDestroy(&w);
749 ae = ae->next;
750 }
751 }
752
753 static void
754 parse_acl(ACL ** ae)
755 {
756 ACL::ParseAclLine(ae);
757 }
758
759 static void
760 free_acl(ACL ** ae)
761 {
762 aclDestroyAcls(ae);
763 }
764
765 static void
766 dump_acl_list(StoreEntry * entry, acl_list * head)
767 {
768 acl_list *l;
769
770 for (l = head; l; l = l->next) {
771 storeAppendPrintf(entry, " %s%s",
772 l->op ? null_string : "!",
773 l->_acl->name);
774 }
775 }
776
777 void
778 dump_acl_access(StoreEntry * entry, const char *name, acl_access * head)
779 {
780 acl_access *l;
781
782 for (l = head; l; l = l->next) {
783 storeAppendPrintf(entry, "%s %s",
784 name,
785 l->allow ? "Allow" : "Deny");
786 dump_acl_list(entry, l->aclList);
787 storeAppendPrintf(entry, "\n");
788 }
789 }
790
791 static void
792 parse_acl_access(acl_access ** head)
793 {
794 aclParseAccessLine(head);
795 }
796
797 static void
798 free_acl_access(acl_access ** head)
799 {
800 aclDestroyAccessList(head);
801 }
802
803 static void
804
805 dump_address(StoreEntry * entry, const char *name, struct in_addr addr)
806 {
807 storeAppendPrintf(entry, "%s %s\n", name, inet_ntoa(addr));
808 }
809
810 static void
811
812 parse_address(struct in_addr *addr)
813 {
814
815 const struct hostent *hp;
816 char *token = strtok(NULL, w_space);
817
818 if (token == NULL)
819 self_destruct();
820
821 if (safe_inet_addr(token, addr) == 1)
822 (void) 0;
823 else if ((hp = gethostbyname(token))) /* dont use ipcache */
824 *addr = inaddrFromHostent(hp);
825 else
826 self_destruct();
827 }
828
829 static void
830
831 free_address(struct in_addr *addr)
832 {
833
834 memset(addr, '\0', sizeof(struct in_addr));
835 }
836
837 CBDATA_TYPE(acl_address);
838
839 static void
840 dump_acl_address(StoreEntry * entry, const char *name, acl_address * head)
841 {
842 acl_address *l;
843
844 for (l = head; l; l = l->next) {
845 if (l->addr.s_addr != INADDR_ANY)
846 storeAppendPrintf(entry, "%s %s", name, inet_ntoa(l->addr));
847 else
848 storeAppendPrintf(entry, "%s autoselect", name);
849
850 dump_acl_list(entry, l->aclList);
851
852 storeAppendPrintf(entry, "\n");
853 }
854 }
855
856 static void
857 freed_acl_address(void *data)
858 {
859 acl_address *l = static_cast<acl_address *>(data);
860 aclDestroyAclList(&l->aclList);
861 }
862
863 static void
864 parse_acl_address(acl_address ** head)
865 {
866 acl_address *l;
867 acl_address **tail = head; /* sane name below */
868 CBDATA_INIT_TYPE_FREECB(acl_address, freed_acl_address);
869 l = cbdataAlloc(acl_address);
870 parse_address(&l->addr);
871 aclParseAclList(&l->aclList);
872
873 while (*tail)
874 tail = &(*tail)->next;
875
876 *tail = l;
877 }
878
879 static void
880 free_acl_address(acl_address ** head)
881 {
882 while (*head) {
883 acl_address *l = *head;
884 *head = l->next;
885 cbdataFree(l);
886 }
887 }
888
889 CBDATA_TYPE(acl_tos);
890
891 static void
892 dump_acl_tos(StoreEntry * entry, const char *name, acl_tos * head)
893 {
894 acl_tos *l;
895
896 for (l = head; l; l = l->next) {
897 if (l->tos > 0)
898 storeAppendPrintf(entry, "%s 0x%02X", name, l->tos);
899 else
900 storeAppendPrintf(entry, "%s none", name);
901
902 dump_acl_list(entry, l->aclList);
903
904 storeAppendPrintf(entry, "\n");
905 }
906 }
907
908 static void
909 freed_acl_tos(void *data)
910 {
911 acl_tos *l = static_cast<acl_tos *>(data);
912 aclDestroyAclList(&l->aclList);
913 }
914
915 static void
916 parse_acl_tos(acl_tos ** head)
917 {
918 acl_tos *l;
919 acl_tos **tail = head; /* sane name below */
920 int tos;
921 char junk;
922 char *token = strtok(NULL, w_space);
923
924 if (!token)
925 self_destruct();
926
927 if (sscanf(token, "0x%x%c", &tos, &junk) != 1)
928 self_destruct();
929
930 if (tos < 0 || tos > 255)
931 self_destruct();
932
933 CBDATA_INIT_TYPE_FREECB(acl_tos, freed_acl_tos);
934
935 l = cbdataAlloc(acl_tos);
936
937 l->tos = tos;
938
939 aclParseAclList(&l->aclList);
940
941 while (*tail)
942 tail = &(*tail)->next;
943
944 *tail = l;
945 }
946
947 static void
948 free_acl_tos(acl_tos ** head)
949 {
950 while (*head) {
951 acl_tos *l = *head;
952 *head = l->next;
953 l->next = NULL;
954 cbdataFree(l);
955 }
956 }
957
958 CBDATA_TYPE(acl_size_t);
959
960 static void
961 dump_acl_b_size_t(StoreEntry * entry, const char *name, acl_size_t * head)
962 {
963 acl_size_t *l;
964
965 for (l = head; l; l = l->next) {
966 if (l->size != static_cast<size_t>(-1))
967 storeAppendPrintf(entry, "%s %d %s\n", name, (int) l->size, B_BYTES_STR);
968 else
969 storeAppendPrintf(entry, "%s none", name);
970
971 dump_acl_list(entry, l->aclList);
972
973 storeAppendPrintf(entry, "\n");
974 }
975 }
976
977 static void
978 freed_acl_b_size_t(void *data)
979 {
980 acl_size_t *l = static_cast<acl_size_t *>(data);
981 aclDestroyAclList(&l->aclList);
982 }
983
984 static void
985 parse_acl_b_size_t(acl_size_t ** head)
986 {
987 acl_size_t *l;
988 acl_size_t **tail = head; /* sane name below */
989
990 CBDATA_INIT_TYPE_FREECB(acl_size_t, freed_acl_b_size_t);
991
992 l = cbdataAlloc(acl_size_t);
993
994 parse_b_size_t(&l->size);
995
996 aclParseAclList(&l->aclList);
997
998 while (*tail)
999 tail = &(*tail)->next;
1000
1001 *tail = l;
1002 }
1003
1004 static void
1005 free_acl_b_size_t(acl_size_t ** head)
1006 {
1007 while (*head) {
1008 acl_size_t *l = *head;
1009 *head = l->next;
1010 l->next = NULL;
1011 cbdataFree(l);
1012 }
1013 }
1014
1015 #if DELAY_POOLS
1016
1017 #include "DelayPools.h"
1018 #include "DelayConfig.h"
1019 /* do nothing - free_delay_pool_count is the magic free function.
1020 * this is why delay_pool_count isn't just marked TYPE: ushort
1021 */
1022 #define free_delay_pool_class(X)
1023 #define free_delay_pool_access(X)
1024 #define free_delay_pool_rates(X)
1025 #define dump_delay_pool_class(X, Y, Z)
1026 #define dump_delay_pool_access(X, Y, Z)
1027 #define dump_delay_pool_rates(X, Y, Z)
1028
1029 static void
1030 free_delay_pool_count(DelayConfig * cfg)
1031 {
1032 cfg->freePoolCount();
1033 }
1034
1035 static void
1036 dump_delay_pool_count(StoreEntry * entry, const char *name, DelayConfig &cfg)
1037 {
1038 cfg.dumpPoolCount (entry, name);
1039 }
1040
1041 static void
1042 parse_delay_pool_count(DelayConfig * cfg)
1043 {
1044 cfg->parsePoolCount();
1045 }
1046
1047 static void
1048 parse_delay_pool_class(DelayConfig * cfg)
1049 {
1050 cfg->parsePoolClass();
1051 }
1052
1053 static void
1054 parse_delay_pool_rates(DelayConfig * cfg)
1055 {
1056 cfg->parsePoolRates();
1057 }
1058
1059 static void
1060 parse_delay_pool_access(DelayConfig * cfg)
1061 {
1062 cfg->parsePoolAccess();
1063 }
1064
1065 #endif
1066
1067 #if HTTP_VIOLATIONS
1068 static void
1069 dump_http_header_access(StoreEntry * entry, const char *name, header_mangler header[])
1070 {
1071 int i;
1072
1073 for (i = 0; i < HDR_ENUM_END; i++) {
1074 if (header[i].access_list != NULL) {
1075 storeAppendPrintf(entry, "%s ", name);
1076 dump_acl_access(entry, httpHeaderNameById(i),
1077 header[i].access_list);
1078 }
1079 }
1080 }
1081
1082 static void
1083 parse_http_header_access(header_mangler header[])
1084 {
1085 int id, i;
1086 char *t = NULL;
1087
1088 if ((t = strtok(NULL, w_space)) == NULL) {
1089 debug(3, 0) ("%s line %d: %s\n",
1090 cfg_filename, config_lineno, config_input_line);
1091 debug(3, 0) ("parse_http_header_access: missing header name.\n");
1092 return;
1093 }
1094
1095 /* Now lookup index of header. */
1096 id = httpHeaderIdByNameDef(t, strlen(t));
1097
1098 if (strcmp(t, "All") == 0)
1099 id = HDR_ENUM_END;
1100 else if (strcmp(t, "Other") == 0)
1101 id = HDR_OTHER;
1102 else if (id == -1) {
1103 debug(3, 0) ("%s line %d: %s\n",
1104 cfg_filename, config_lineno, config_input_line);
1105 debug(3, 0) ("parse_http_header_access: unknown header name %s.\n", t);
1106 return;
1107 }
1108
1109 if (id != HDR_ENUM_END) {
1110 parse_acl_access(&header[id].access_list);
1111 } else {
1112 char *next_string = t + strlen(t) - 1;
1113 *next_string = 'A';
1114 *(next_string + 1) = ' ';
1115
1116 for (i = 0; i < HDR_ENUM_END; i++) {
1117 char *new_string = xstrdup(next_string);
1118 strtok(new_string, w_space);
1119 parse_acl_access(&header[i].access_list);
1120 safe_free(new_string);
1121 }
1122 }
1123 }
1124
1125 static void
1126 free_http_header_access(header_mangler header[])
1127 {
1128 int i;
1129
1130 for (i = 0; i < HDR_ENUM_END; i++) {
1131 free_acl_access(&header[i].access_list);
1132 }
1133 }
1134
1135 static void
1136 dump_http_header_replace(StoreEntry * entry, const char *name, header_mangler
1137 header[])
1138 {
1139 int i;
1140
1141 for (i = 0; i < HDR_ENUM_END; i++) {
1142 if (NULL == header[i].replacement)
1143 continue;
1144
1145 storeAppendPrintf(entry, "%s %s %s\n", name, httpHeaderNameById(i),
1146 header[i].replacement);
1147 }
1148 }
1149
1150 static void
1151 parse_http_header_replace(header_mangler header[])
1152 {
1153 int id, i;
1154 char *t = NULL;
1155
1156 if ((t = strtok(NULL, w_space)) == NULL) {
1157 debug(3, 0) ("%s line %d: %s\n",
1158 cfg_filename, config_lineno, config_input_line);
1159 debug(3, 0) ("parse_http_header_replace: missing header name.\n");
1160 return;
1161 }
1162
1163 /* Now lookup index of header. */
1164 id = httpHeaderIdByNameDef(t, strlen(t));
1165
1166 if (strcmp(t, "All") == 0)
1167 id = HDR_ENUM_END;
1168 else if (strcmp(t, "Other") == 0)
1169 id = HDR_OTHER;
1170 else if (id == -1) {
1171 debug(3, 0) ("%s line %d: %s\n",
1172 cfg_filename, config_lineno, config_input_line);
1173 debug(3, 0) ("parse_http_header_replace: unknown header name %s.\n",
1174 t);
1175 return;
1176 }
1177
1178 if (id != HDR_ENUM_END) {
1179 if (header[id].replacement != NULL)
1180 safe_free(header[id].replacement);
1181
1182 header[id].replacement = xstrdup(t + strlen(t) + 1);
1183 } else {
1184 for (i = 0; i < HDR_ENUM_END; i++) {
1185 if (header[i].replacement != NULL)
1186 safe_free(header[i].replacement);
1187
1188 header[i].replacement = xstrdup(t + strlen(t) + 1);
1189 }
1190 }
1191 }
1192
1193 static void
1194 free_http_header_replace(header_mangler header[])
1195 {
1196 int i;
1197
1198 for (i = 0; i < HDR_ENUM_END; i++) {
1199 if (header[i].replacement != NULL)
1200 safe_free(header[i].replacement);
1201 }
1202 }
1203
1204 #endif
1205
1206
1207 static void
1208 dump_cachedir(StoreEntry * entry, const char *name, _SquidConfig::_cacheSwap swap)
1209 {
1210 SwapDir *s;
1211 int i;
1212 assert (entry);
1213
1214 for (i = 0; i < swap.n_configured; i++) {
1215 s = swap.swapDirs[i];
1216 storeAppendPrintf(entry, "%s %s %s", name, s->type(), s->path);
1217 s->dump(*entry);
1218 storeAppendPrintf(entry, "\n");
1219 }
1220 }
1221
1222
1223 static int
1224 check_null_cachedir(_SquidConfig::_cacheSwap swap)
1225 {
1226 return swap.swapDirs == NULL;
1227 }
1228
1229 static int
1230 check_null_string(char *s)
1231 {
1232 return s == NULL;
1233 }
1234
1235 static void
1236 parse_authparam(authConfig * config)
1237 {
1238 char *type_str;
1239 char *param_str;
1240
1241 if ((type_str = strtok(NULL, w_space)) == NULL)
1242 self_destruct();
1243
1244 if ((param_str = strtok(NULL, w_space)) == NULL)
1245 self_destruct();
1246
1247 /* find a configuration for the scheme */
1248 AuthConfig *scheme = AuthConfig::Find (type_str);
1249
1250 if (scheme == NULL) {
1251 /* Create a configuration */
1252 AuthScheme *theScheme;
1253
1254 if ((theScheme = AuthScheme::Find(type_str)) == NULL) {
1255 debug(3, 0) ("Parsing Config File: Unknown authentication scheme '%s'.\n", type_str);
1256 return;
1257 }
1258
1259 config->push_back(theScheme->createConfig());
1260 scheme = config->back();
1261 assert (scheme);
1262 }
1263
1264 scheme->parse(scheme, config->size(), param_str);
1265 }
1266
1267 static void
1268 free_authparam(authConfig * cfg)
1269 {
1270 AuthConfig *scheme;
1271 /* DON'T FREE THESE FOR RECONFIGURE */
1272
1273 if (reconfiguring)
1274 return;
1275
1276 while (cfg->size()) {
1277 scheme = cfg->pop_back();
1278 scheme->done();
1279 }
1280 }
1281
1282 static void
1283 dump_authparam(StoreEntry * entry, const char *name, authConfig cfg)
1284 {
1285 for (authConfig::iterator i = cfg.begin(); i != cfg.end(); ++i)
1286 (*i)->dump(entry, name, (*i));
1287 }
1288
1289 void
1290 allocate_new_swapdir(_SquidConfig::_cacheSwap * swap)
1291 {
1292 if (swap->swapDirs == NULL) {
1293 swap->n_allocated = 4;
1294 swap->swapDirs = static_cast<SwapDir **>(xcalloc(swap->n_allocated, sizeof(SwapDir *)));
1295 }
1296
1297 if (swap->n_allocated == swap->n_configured) {
1298 SwapDir **tmp;
1299 swap->n_allocated <<= 1;
1300 tmp = static_cast<SwapDir **>(xcalloc(swap->n_allocated, sizeof(SwapDir *)));
1301 xmemcpy(tmp, swap->swapDirs, swap->n_configured * sizeof(SwapDir *));
1302 xfree(swap->swapDirs);
1303 swap->swapDirs = tmp;
1304 }
1305 }
1306
1307 /* TODO: just return the object, the # is irrelevant */
1308 static int
1309 find_fstype(char *type)
1310 {
1311 for (size_t i = 0; i < StoreFileSystem::FileSystems().size(); ++i)
1312 if (strcasecmp(type, StoreFileSystem::FileSystems().items[i]->type()) == 0)
1313 return (int)i;
1314
1315 return (-1);
1316 }
1317
1318 static void
1319 parse_cachedir(_SquidConfig::_cacheSwap * swap)
1320 {
1321 char *type_str;
1322 char *path_str;
1323 SwapDir *sd;
1324 int i;
1325 int fs;
1326
1327 if ((type_str = strtok(NULL, w_space)) == NULL)
1328 self_destruct();
1329
1330 if ((path_str = strtok(NULL, w_space)) == NULL)
1331 self_destruct();
1332
1333 /*
1334 * This bit of code is a little strange.
1335 * See, if we find a path and type match for a given line, then
1336 * as long as we're reconfiguring, we can just call its reconfigure
1337 * function. No harm there.
1338 *
1339 * Trouble is, if we find a path match, but not a type match, we have
1340 * a dilemma - we could gracefully shut down the fs, kill it, and
1341 * create a new one of a new type in its place, BUT at this stage the
1342 * fs is meant to be the *NEW* one, and so things go very strange. :-)
1343 *
1344 * So, we'll assume the person isn't going to change the fs type for now,
1345 * and XXX later on we will make sure that its picked up.
1346 *
1347 * (moving around cache_dir lines will be looked at later in a little
1348 * more sane detail..)
1349 */
1350
1351 for (i = 0; i < swap->n_configured; i++) {
1352 assert (swap->swapDirs[i]);
1353
1354 if (0 == strcasecmp(path_str, swap->swapDirs[i]->path)) {
1355 /* This is a little weird, you'll appreciate it later */
1356 fs = find_fstype(type_str);
1357
1358 if (fs < 0) {
1359 fatalf("Unknown cache_dir type '%s'\n", type_str);
1360 }
1361
1362 sd = swap->swapDirs[i];
1363 sd->reconfigure (i, path_str);
1364 update_maxobjsize();
1365 return;
1366 }
1367 }
1368
1369 assert(swap->n_configured < 63); /* 7 bits, signed */
1370
1371 fs = find_fstype(type_str);
1372
1373 if (fs < 0) {
1374 /* If we get here, we didn't find a matching cache_dir type */
1375 fatalf("Unknown cache_dir type '%s'\n", type_str);
1376 }
1377
1378 allocate_new_swapdir(swap);
1379 swap->swapDirs[swap->n_configured] = StoreFileSystem::FileSystems().items[fs]->createSwapDir();
1380 sd = swap->swapDirs[swap->n_configured];
1381 /* parse the FS parameters and options */
1382 sd->parse(swap->n_configured, path_str);
1383 ++swap->n_configured;
1384 /* Update the max object size */
1385 update_maxobjsize();
1386 }
1387
1388 static void
1389 free_cachedir(_SquidConfig::_cacheSwap * swap)
1390 {
1391 int i;
1392 /* DON'T FREE THESE FOR RECONFIGURE */
1393
1394 if (reconfiguring)
1395 return;
1396
1397 for (i = 0; i < swap->n_configured; i++) {
1398 SwapDir * s = swap->swapDirs[i];
1399 swap->swapDirs[i] = NULL;
1400 delete s;
1401 }
1402
1403 safe_free(swap->swapDirs);
1404 swap->swapDirs = NULL;
1405 swap->n_allocated = 0;
1406 swap->n_configured = 0;
1407 }
1408
1409 static const char *
1410 peer_type_str(const peer_t type)
1411 {
1412 switch (type) {
1413
1414 case PEER_PARENT:
1415 return "parent";
1416 break;
1417
1418 case PEER_SIBLING:
1419 return "sibling";
1420 break;
1421
1422 case PEER_MULTICAST:
1423 return "multicast";
1424 break;
1425
1426 default:
1427 return "unknown";
1428 break;
1429 }
1430 }
1431
1432 static void
1433 dump_peer(StoreEntry * entry, const char *name, peer * p)
1434 {
1435 domain_ping *d;
1436 domain_type *t;
1437 LOCAL_ARRAY(char, xname, 128);
1438
1439 while (p != NULL) {
1440 storeAppendPrintf(entry, "%s %s %s %d %d",
1441 name,
1442 p->host,
1443 neighborTypeStr(p),
1444 p->http_port,
1445 p->icp.port);
1446 dump_peer_options(entry, p);
1447
1448 for (d = p->peer_domain; d; d = d->next) {
1449 storeAppendPrintf(entry, "cache_peer_domain %s %s%s\n",
1450 p->host,
1451 d->do_ping ? null_string : "!",
1452 d->domain);
1453 }
1454
1455 if (p->access) {
1456 snprintf(xname, 128, "cache_peer_access %s", p->name);
1457 dump_acl_access(entry, xname, p->access);
1458 }
1459
1460 for (t = p->typelist; t; t = t->next) {
1461 storeAppendPrintf(entry, "neighbor_type_domain %s %s %s\n",
1462 p->host,
1463 peer_type_str(t->type),
1464 t->domain);
1465 }
1466
1467 p = p->next;
1468 }
1469 }
1470
1471 static void
1472 parse_peer(peer ** head)
1473 {
1474 char *token = NULL;
1475 peer *p;
1476 int i;
1477 CBDATA_INIT_TYPE_FREECB(peer, peerDestroy);
1478 p = cbdataAlloc(peer);
1479 p->http_port = CACHE_HTTP_PORT;
1480 p->icp.port = CACHE_ICP_PORT;
1481 p->weight = 1;
1482 p->basetime = 0;
1483 p->stats.logged_state = PEER_ALIVE;
1484
1485 if ((token = strtok(NULL, w_space)) == NULL)
1486 self_destruct();
1487
1488 p->host = xstrdup(token);
1489
1490 p->name = xstrdup(token);
1491
1492 if ((token = strtok(NULL, w_space)) == NULL)
1493 self_destruct();
1494
1495 p->type = parseNeighborType(token);
1496
1497 i = GetInteger();
1498
1499 p->http_port = (u_short) i;
1500
1501 i = GetInteger();
1502
1503 p->icp.port = (u_short) i;
1504
1505 while ((token = strtok(NULL, w_space))) {
1506 if (!strcasecmp(token, "proxy-only")) {
1507 p->options.proxy_only = 1;
1508 } else if (!strcasecmp(token, "no-query")) {
1509 p->options.no_query = 1;
1510 } else if (!strcasecmp(token, "background-ping")) {
1511 p->options.background_ping = 1;
1512 } else if (!strcasecmp(token, "no-digest")) {
1513 p->options.no_digest = 1;
1514 } else if (!strcasecmp(token, "multicast-responder")) {
1515 p->options.mcast_responder = 1;
1516 } else if (!strncasecmp(token, "weight=", 7)) {
1517 p->weight = xatoi(token + 7);
1518 } else if (!strncasecmp(token, "basetime=", 9)) {
1519 p->basetime = xatoi(token + 9);
1520 } else if (!strcasecmp(token, "closest-only")) {
1521 p->options.closest_only = 1;
1522 } else if (!strncasecmp(token, "ttl=", 4)) {
1523 p->mcast.ttl = xatoi(token + 4);
1524
1525 if (p->mcast.ttl < 0)
1526 p->mcast.ttl = 0;
1527
1528 if (p->mcast.ttl > 128)
1529 p->mcast.ttl = 128;
1530 } else if (!strcasecmp(token, "default")) {
1531 p->options.default_parent = 1;
1532 } else if (!strcasecmp(token, "round-robin")) {
1533 p->options.roundrobin = 1;
1534 } else if (!strcasecmp(token, "weighted-round-robin")) {
1535 p->options.weighted_roundrobin = 1;
1536 #if USE_HTCP
1537
1538 } else if (!strcasecmp(token, "htcp")) {
1539 p->options.htcp = 1;
1540 #endif
1541
1542 } else if (!strcasecmp(token, "no-netdb-exchange")) {
1543 p->options.no_netdb_exchange = 1;
1544 #if USE_CARP
1545
1546 } else if (!strcasecmp(token, "carp")) {
1547 if (p->type != PEER_PARENT)
1548 fatalf("parse_peer: non-parent carp peer %s/%d\n", p->host, p->http_port);
1549
1550 p->options.carp = 1;
1551
1552 #endif
1553 #if DELAY_POOLS
1554
1555 } else if (!strcasecmp(token, "no-delay")) {
1556 p->options.no_delay = 1;
1557 #endif
1558
1559 } else if (!strncasecmp(token, "login=", 6)) {
1560 p->login = xstrdup(token + 6);
1561 rfc1738_unescape(p->login);
1562 } else if (!strncasecmp(token, "connect-timeout=", 16)) {
1563 p->connect_timeout = xatoi(token + 16);
1564 #if USE_CACHE_DIGESTS
1565
1566 } else if (!strncasecmp(token, "digest-url=", 11)) {
1567 p->digest_url = xstrdup(token + 11);
1568 #endif
1569
1570 } else if (!strcasecmp(token, "allow-miss")) {
1571 p->options.allow_miss = 1;
1572 } else if (!strncasecmp(token, "max-conn=", 9)) {
1573 p->max_conn = xatoi(token + 9);
1574 } else if (!strcasecmp(token, "originserver")) {
1575 p->options.originserver = 1;
1576 } else if (!strncasecmp(token, "name=", 5)) {
1577 safe_free(p->name);
1578
1579 if (token[5])
1580 p->name = xstrdup(token + 5);
1581 } else if (!strncasecmp(token, "forceddomain=", 13)) {
1582 safe_free(p->domain);
1583
1584 if (token[13])
1585 p->domain = xstrdup(token + 13);
1586
1587 #if USE_SSL
1588
1589 } else if (strcmp(token, "ssl") == 0) {
1590 p->use_ssl = 1;
1591 } else if (strncmp(token, "sslcert=", 8) == 0) {
1592 safe_free(p->sslcert);
1593 p->sslcert = xstrdup(token + 8);
1594 } else if (strncmp(token, "sslkey=", 7) == 0) {
1595 safe_free(p->sslkey);
1596 p->sslkey = xstrdup(token + 7);
1597 } else if (strncmp(token, "sslversion=", 11) == 0) {
1598 p->sslversion = atoi(token + 11);
1599 } else if (strncmp(token, "ssloptions=", 11) == 0) {
1600 safe_free(p->ssloptions);
1601 p->ssloptions = xstrdup(token + 11);
1602 } else if (strncmp(token, "sslcipher=", 10) == 0) {
1603 safe_free(p->sslcipher);
1604 p->sslcipher = xstrdup(token + 10);
1605 } else if (strncmp(token, "sslcafile=", 10) == 0) {
1606 safe_free(p->sslcafile);
1607 p->sslcipher = xstrdup(token + 10);
1608 } else if (strncmp(token, "sslcapath=", 10) == 0) {
1609 safe_free(p->sslcapath);
1610 p->sslcipher = xstrdup(token + 10);
1611 } else if (strncmp(token, "sslflags=", 9) == 0) {
1612 safe_free(p->sslflags);
1613 p->sslflags = xstrdup(token + 9);
1614 } else if (strncmp(token, "ssldomain=", 10) == 0) {
1615 safe_free(p->ssldomain);
1616 p->ssldomain = xstrdup(token + 10);
1617 #endif
1618
1619 } else if (strcmp(token, "front-end-https") == 0) {
1620 p->front_end_https = 1;
1621 } else if (strcmp(token, "front-end-https=on") == 0) {
1622 p->front_end_https = 1;
1623 } else if (strcmp(token, "front-end-https=auto") == 0) {
1624 p->front_end_https = 2;
1625 } else {
1626 debug(3, 0) ("parse_peer: token='%s'\n", token);
1627 self_destruct();
1628 }
1629 }
1630
1631 if (peerFindByName(p->name))
1632 fatalf("ERROR: cache_peer %s specified twice\n", p->name);
1633
1634 if (p->weight < 1)
1635 p->weight = 1;
1636
1637 p->icp.version = ICP_VERSION_CURRENT;
1638
1639 p->tcp_up = PEER_TCP_MAGIC_COUNT;
1640
1641 p->test_fd = -1;
1642
1643 #if USE_CACHE_DIGESTS
1644
1645 if (!p->options.no_digest) {
1646 /* XXX This looks odd.. who has the original pointer
1647 * then?
1648 */
1649 PeerDigest *pd = peerDigestCreate(p);
1650 p->digest = cbdataReference(pd);
1651 }
1652
1653 #endif
1654 #if USE_SSL
1655 if (p->use_ssl) {
1656 p->sslContext = sslCreateClientContext(p->sslcert, p->sslkey, p->sslversion, p->sslcipher, p->ssloptions, p->sslflags, p->sslcafile, p->sslcapath);
1657 }
1658
1659 #endif
1660 while (*head != NULL)
1661 head = &(*head)->next;
1662
1663 *head = p;
1664
1665 Config.npeers++;
1666
1667 peerClearRR(p);
1668 }
1669
1670 static void
1671 free_peer(peer ** P)
1672 {
1673 peer *p;
1674
1675 while ((p = *P) != NULL) {
1676 *P = p->next;
1677 #if USE_CACHE_DIGESTS
1678
1679 cbdataReferenceDone(p->digest);
1680 #endif
1681
1682 cbdataFree(p);
1683 }
1684
1685 Config.npeers = 0;
1686 }
1687
1688 static void
1689 dump_cachemgrpasswd(StoreEntry * entry, const char *name, cachemgr_passwd * list)
1690 {
1691 wordlist *w;
1692
1693 while (list != NULL) {
1694 if (strcmp(list->passwd, "none") && strcmp(list->passwd, "disable"))
1695 storeAppendPrintf(entry, "%s XXXXXXXXXX", name);
1696 else
1697 storeAppendPrintf(entry, "%s %s", name, list->passwd);
1698
1699 for (w = list->actions; w != NULL; w = w->next) {
1700 storeAppendPrintf(entry, " %s", w->key);
1701 }
1702
1703 storeAppendPrintf(entry, "\n");
1704 list = list->next;
1705 }
1706 }
1707
1708 static void
1709 parse_cachemgrpasswd(cachemgr_passwd ** head)
1710 {
1711 char *passwd = NULL;
1712 wordlist *actions = NULL;
1713 cachemgr_passwd *p;
1714 cachemgr_passwd **P;
1715 parse_string(&passwd);
1716 parse_wordlist(&actions);
1717 p = static_cast<cachemgr_passwd *>(xcalloc(1, sizeof(cachemgr_passwd)));
1718 p->passwd = passwd;
1719 p->actions = actions;
1720
1721 for (P = head; *P; P = &(*P)->next) {
1722 /*
1723 * See if any of the actions from this line already have a
1724 * password from previous lines. The password checking
1725 * routines in cache_manager.c take the the password from
1726 * the first cachemgr_passwd struct that contains the
1727 * requested action. Thus, we should warn users who might
1728 * think they can have two passwords for the same action.
1729 */
1730 wordlist *w;
1731 wordlist *u;
1732
1733 for (w = (*P)->actions; w; w = w->next) {
1734 for (u = actions; u; u = u->next) {
1735 if (strcmp(w->key, u->key))
1736 continue;
1737
1738 debug(0, 0) ("WARNING: action '%s' (line %d) already has a password\n",
1739 u->key, config_lineno);
1740 }
1741 }
1742 }
1743
1744 *P = p;
1745 }
1746
1747 static void
1748 free_cachemgrpasswd(cachemgr_passwd ** head)
1749 {
1750 cachemgr_passwd *p;
1751
1752 while ((p = *head) != NULL) {
1753 *head = p->next;
1754 xfree(p->passwd);
1755 wordlistDestroy(&p->actions);
1756 xfree(p);
1757 }
1758 }
1759
1760 static void
1761 dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var)
1762 {
1763 acl_name_list *a;
1764
1765 while (var != NULL) {
1766 storeAppendPrintf(entry, "%s %s", name, var->err_page_name);
1767
1768 for (a = var->acl_list; a != NULL; a = a->next)
1769 storeAppendPrintf(entry, " %s", a->name);
1770
1771 storeAppendPrintf(entry, "\n");
1772
1773 var = var->next;
1774 }
1775 }
1776
1777 static void
1778 parse_denyinfo(acl_deny_info_list ** var)
1779 {
1780 aclParseDenyInfoLine(var);
1781 }
1782
1783 void
1784 free_denyinfo(acl_deny_info_list ** list)
1785 {
1786 acl_deny_info_list *a = NULL;
1787 acl_deny_info_list *a_next = NULL;
1788 acl_name_list *l = NULL;
1789 acl_name_list *l_next = NULL;
1790
1791 for (a = *list; a; a = a_next) {
1792 for (l = a->acl_list; l; l = l_next) {
1793 l_next = l->next;
1794 memFree(l, MEM_ACL_NAME_LIST);
1795 l = NULL;
1796 }
1797
1798 a_next = a->next;
1799 memFree(a, MEM_ACL_DENY_INFO_LIST);
1800 a = NULL;
1801 }
1802
1803 *list = NULL;
1804 }
1805
1806 static void
1807 parse_peer_access(void)
1808 {
1809 char *host = NULL;
1810 peer *p;
1811
1812 if (!(host = strtok(NULL, w_space)))
1813 self_destruct();
1814
1815 if ((p = peerFindByName(host)) == NULL) {
1816 debug(15, 0) ("%s, line %d: No cache_peer '%s'\n",
1817 cfg_filename, config_lineno, host);
1818 return;
1819 }
1820
1821 aclParseAccessLine(&p->access);
1822 }
1823
1824 static void
1825 parse_hostdomain(void)
1826 {
1827 char *host = NULL;
1828 char *domain = NULL;
1829
1830 if (!(host = strtok(NULL, w_space)))
1831 self_destruct();
1832
1833 while ((domain = strtok(NULL, list_sep))) {
1834 domain_ping *l = NULL;
1835 domain_ping **L = NULL;
1836 peer *p;
1837
1838 if ((p = peerFindByName(host)) == NULL) {
1839 debug(15, 0) ("%s, line %d: No cache_peer '%s'\n",
1840 cfg_filename, config_lineno, host);
1841 continue;
1842 }
1843
1844 l = static_cast<domain_ping *>(xcalloc(1, sizeof(domain_ping)));
1845 l->do_ping = 1;
1846
1847 if (*domain == '!') { /* check for !.edu */
1848 l->do_ping = 0;
1849 domain++;
1850 }
1851
1852 l->domain = xstrdup(domain);
1853
1854 for (L = &(p->peer_domain); *L; L = &((*L)->next))
1855
1856 ;
1857 *L = l;
1858 }
1859 }
1860
1861 static void
1862 parse_hostdomaintype(void)
1863 {
1864 char *host = NULL;
1865 char *type = NULL;
1866 char *domain = NULL;
1867
1868 if (!(host = strtok(NULL, w_space)))
1869 self_destruct();
1870
1871 if (!(type = strtok(NULL, w_space)))
1872 self_destruct();
1873
1874 while ((domain = strtok(NULL, list_sep))) {
1875 domain_type *l = NULL;
1876 domain_type **L = NULL;
1877 peer *p;
1878
1879 if ((p = peerFindByName(host)) == NULL) {
1880 debug(15, 0) ("%s, line %d: No cache_peer '%s'\n",
1881 cfg_filename, config_lineno, host);
1882 return;
1883 }
1884
1885 l = static_cast<domain_type *>(xcalloc(1, sizeof(domain_type)));
1886 l->type = parseNeighborType(type);
1887 l->domain = xstrdup(domain);
1888
1889 for (L = &(p->typelist); *L; L = &((*L)->next))
1890
1891 ;
1892 *L = l;
1893 }
1894 }
1895
1896 #if UNUSED_CODE
1897 static void
1898 dump_ushortlist(StoreEntry * entry, const char *name, ushortlist * u)
1899 {
1900 while (u) {
1901 storeAppendPrintf(entry, "%s %d\n", name, (int) u->i);
1902 u = u->next;
1903 }
1904 }
1905
1906 static int
1907 check_null_ushortlist(ushortlist * u)
1908 {
1909 return u == NULL;
1910 }
1911
1912 static void
1913 parse_ushortlist(ushortlist ** P)
1914 {
1915 char *token;
1916 int i;
1917 ushortlist *u;
1918 ushortlist **U;
1919
1920 while ((token = strtok(NULL, w_space))) {
1921 if (sscanf(token, "%d", &i) != 1)
1922 self_destruct();
1923
1924 if (i < 0)
1925 i = 0;
1926
1927 u = xcalloc(1, sizeof(ushortlist));
1928
1929 u->i = (u_short) i;
1930
1931 for (U = P; *U; U = &(*U)->next)
1932
1933 ;
1934 *U = u;
1935 }
1936 }
1937
1938 static void
1939 free_ushortlist(ushortlist ** P)
1940 {
1941 ushortlist *u;
1942
1943 while ((u = *P) != NULL) {
1944 *P = u->next;
1945 xfree(u);
1946 }
1947 }
1948
1949 #endif
1950
1951 static void
1952 dump_int(StoreEntry * entry, const char *name, int var)
1953 {
1954 storeAppendPrintf(entry, "%s %d\n", name, var);
1955 }
1956
1957 void
1958 parse_int(int *var)
1959 {
1960 int i;
1961 i = GetInteger();
1962 *var = i;
1963 }
1964
1965 static void
1966 free_int(int *var)
1967 {
1968 *var = 0;
1969 }
1970
1971 static void
1972 dump_onoff(StoreEntry * entry, const char *name, int var)
1973 {
1974 storeAppendPrintf(entry, "%s %s\n", name, var ? "on" : "off");
1975 }
1976
1977 void
1978 parse_onoff(int *var)
1979 {
1980 char *token = strtok(NULL, w_space);
1981
1982 if (token == NULL)
1983 self_destruct();
1984
1985 if (!strcasecmp(token, "on") || !strcasecmp(token, "enable"))
1986 *var = 1;
1987 else
1988 *var = 0;
1989 }
1990
1991 #define free_onoff free_int
1992 #define dump_eol dump_string
1993 #define free_eol free_string
1994 #define dump_debug dump_string
1995 #define free_debug free_string
1996
1997 static void
1998 dump_refreshpattern(StoreEntry * entry, const char *name, refresh_t * head)
1999 {
2000 while (head != NULL) {
2001 storeAppendPrintf(entry, "%s%s %s %d %d%% %d\n",
2002 name,
2003 head->flags.icase ? " -i" : null_string,
2004 head->pattern,
2005 (int) head->min / 60,
2006 (int) (100.0 * head->pct + 0.5),
2007 (int) head->max / 60);
2008 #if HTTP_VIOLATIONS
2009
2010 if (head->flags.override_expire)
2011 storeAppendPrintf(entry, " override-expire");
2012
2013 if (head->flags.override_lastmod)
2014 storeAppendPrintf(entry, " override-lastmod");
2015
2016 if (head->flags.reload_into_ims)
2017 storeAppendPrintf(entry, " reload-into-ims");
2018
2019 if (head->flags.ignore_reload)
2020 storeAppendPrintf(entry, " ignore-reload");
2021
2022 #endif
2023
2024 storeAppendPrintf(entry, "\n");
2025
2026 head = head->next;
2027 }
2028 }
2029
2030 static void
2031 parse_refreshpattern(refresh_t ** head)
2032 {
2033 char *token;
2034 char *pattern;
2035 time_t min = 0;
2036 double pct = 0.0;
2037 time_t max = 0;
2038 #if HTTP_VIOLATIONS
2039
2040 int override_expire = 0;
2041 int override_lastmod = 0;
2042 int reload_into_ims = 0;
2043 int ignore_reload = 0;
2044 #endif
2045
2046 int i;
2047 refresh_t *t;
2048 regex_t comp;
2049 int errcode;
2050 int flags = REG_EXTENDED | REG_NOSUB;
2051
2052 if ((token = strtok(NULL, w_space)) == NULL)
2053 self_destruct();
2054
2055 if (strcmp(token, "-i") == 0) {
2056 flags |= REG_ICASE;
2057 token = strtok(NULL, w_space);
2058 } else if (strcmp(token, "+i") == 0) {
2059 flags &= ~REG_ICASE;
2060 token = strtok(NULL, w_space);
2061 }
2062
2063 if (token == NULL)
2064 self_destruct();
2065
2066 pattern = xstrdup(token);
2067
2068 i = GetInteger(); /* token: min */
2069
2070 min = (time_t) (i * 60); /* convert minutes to seconds */
2071
2072 i = GetInteger(); /* token: pct */
2073
2074 pct = (double) i / 100.0;
2075
2076 i = GetInteger(); /* token: max */
2077
2078 max = (time_t) (i * 60); /* convert minutes to seconds */
2079
2080 /* Options */
2081 while ((token = strtok(NULL, w_space)) != NULL) {
2082 #if HTTP_VIOLATIONS
2083
2084 if (!strcmp(token, "override-expire"))
2085 override_expire = 1;
2086 else if (!strcmp(token, "override-lastmod"))
2087 override_lastmod = 1;
2088 else if (!strcmp(token, "reload-into-ims")) {
2089 reload_into_ims = 1;
2090 refresh_nocache_hack = 1;
2091 /* tell client_side.c that this is used */
2092 } else if (!strcmp(token, "ignore-reload")) {
2093 ignore_reload = 1;
2094 refresh_nocache_hack = 1;
2095 /* tell client_side.c that this is used */
2096 } else
2097 #endif
2098
2099 debug(22, 0) ("redreshAddToList: Unknown option '%s': %s\n",
2100 pattern, token);
2101 }
2102
2103 if ((errcode = regcomp(&comp, pattern, flags)) != 0) {
2104 char errbuf[256];
2105 regerror(errcode, &comp, errbuf, sizeof errbuf);
2106 debug(22, 0) ("%s line %d: %s\n",
2107 cfg_filename, config_lineno, config_input_line);
2108 debug(22, 0) ("refreshAddToList: Invalid regular expression '%s': %s\n",
2109 pattern, errbuf);
2110 return;
2111 }
2112
2113 pct = pct < 0.0 ? 0.0 : pct;
2114 max = max < 0 ? 0 : max;
2115 t = static_cast<refresh_t *>(xcalloc(1, sizeof(refresh_t)));
2116 t->pattern = (char *) xstrdup(pattern);
2117 t->compiled_pattern = comp;
2118 t->min = min;
2119 t->pct = pct;
2120 t->max = max;
2121
2122 if (flags & REG_ICASE)
2123 t->flags.icase = 1;
2124
2125 #if HTTP_VIOLATIONS
2126
2127 if (override_expire)
2128 t->flags.override_expire = 1;
2129
2130 if (override_lastmod)
2131 t->flags.override_lastmod = 1;
2132
2133 if (reload_into_ims)
2134 t->flags.reload_into_ims = 1;
2135
2136 if (ignore_reload)
2137 t->flags.ignore_reload = 1;
2138
2139 #endif
2140
2141 t->next = NULL;
2142
2143 while (*head)
2144 head = &(*head)->next;
2145
2146 *head = t;
2147
2148 safe_free(pattern);
2149 }
2150
2151 #if UNUSED_CODE
2152 static int
2153 check_null_refreshpattern(refresh_t * data)
2154 {
2155 return data == NULL;
2156 }
2157
2158 #endif
2159
2160 static void
2161 free_refreshpattern(refresh_t ** head)
2162 {
2163 refresh_t *t;
2164
2165 while ((t = *head) != NULL) {
2166 *head = t->next;
2167 safe_free(t->pattern);
2168 regfree(&t->compiled_pattern);
2169 safe_free(t);
2170 }
2171 }
2172
2173 static void
2174 dump_string(StoreEntry * entry, const char *name, char *var)
2175 {
2176 if (var != NULL)
2177 storeAppendPrintf(entry, "%s %s\n", name, var);
2178 }
2179
2180 static void
2181 parse_string(char **var)
2182 {
2183 char *token = strtok(NULL, w_space);
2184 safe_free(*var);
2185
2186 if (token == NULL)
2187 self_destruct();
2188
2189 *var = xstrdup(token);
2190 }
2191
2192 static void
2193 free_string(char **var)
2194 {
2195 safe_free(*var);
2196 }
2197
2198 void
2199 parse_eol(char *volatile *var)
2200 {
2201 unsigned char *token = (unsigned char *) strtok(NULL, null_string);
2202 safe_free(*var);
2203
2204 if (token == NULL)
2205 self_destruct();
2206
2207 while (*token && isspace(*token))
2208 token++;
2209
2210 if (!*token)
2211 self_destruct();
2212
2213 *var = xstrdup((char *) token);
2214 }
2215
2216 void
2217 parse_debug(char *volatile *var)
2218 {
2219 parse_eol(var);
2220 safe_free(debug_options)
2221 debug_options = xstrdup(Config.debugOptions);
2222 Debug::parseOptions(Config.debugOptions);
2223 }
2224
2225 static void
2226 dump_time_t(StoreEntry * entry, const char *name, time_t var)
2227 {
2228 storeAppendPrintf(entry, "%s %d seconds\n", name, (int) var);
2229 }
2230
2231 void
2232 parse_time_t(time_t * var)
2233 {
2234 parseTimeLine(var, T_SECOND_STR);
2235 }
2236
2237 static void
2238 free_time_t(time_t * var)
2239 {
2240 *var = 0;
2241 }
2242
2243 static void
2244 dump_size_t(StoreEntry * entry, const char *name, size_t var)
2245 {
2246 storeAppendPrintf(entry, "%s %d\n", name, (int) var);
2247 }
2248
2249 static void
2250 dump_b_size_t(StoreEntry * entry, const char *name, size_t var)
2251 {
2252 storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_BYTES_STR);
2253 }
2254
2255 static void
2256 dump_kb_size_t(StoreEntry * entry, const char *name, size_t var)
2257 {
2258 storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_KBYTES_STR);
2259 }
2260
2261 static void
2262 parse_size_t(size_t * var)
2263 {
2264 int i;
2265 i = GetInteger();
2266 *var = (size_t) i;
2267 }
2268
2269 static void
2270 parse_b_size_t(size_t * var)
2271 {
2272 parseBytesLine(var, B_BYTES_STR);
2273 }
2274
2275 static void
2276 parse_kb_size_t(size_t * var)
2277 {
2278 parseBytesLine(var, B_KBYTES_STR);
2279 }
2280
2281 static void
2282 free_size_t(size_t * var)
2283 {
2284 *var = 0;
2285 }
2286
2287 #define free_b_size_t free_size_t
2288 #define free_kb_size_t free_size_t
2289 #define free_mb_size_t free_size_t
2290 #define free_gb_size_t free_size_t
2291
2292 static void
2293 dump_ushort(StoreEntry * entry, const char *name, u_short var)
2294 {
2295 storeAppendPrintf(entry, "%s %d\n", name, var);
2296 }
2297
2298 static void
2299 free_ushort(u_short * u)
2300 {
2301 *u = 0;
2302 }
2303
2304 static void
2305 parse_ushort(u_short * var)
2306 {
2307 ConfigParser::ParseUShort(var);
2308 }
2309
2310 void
2311 ConfigParser::ParseUShort(u_short *var)
2312 {
2313 int i;
2314
2315 i = GetInteger();
2316
2317 if (i < 0)
2318 i = 0;
2319
2320 *var = (u_short) i;
2321 }
2322
2323 static void
2324 dump_wordlist(StoreEntry * entry, const char *name, wordlist * list)
2325 {
2326 while (list != NULL) {
2327 storeAppendPrintf(entry, "%s %s\n", name, list->key);
2328 list = list->next;
2329 }
2330 }
2331
2332 void
2333 parse_wordlist(wordlist ** list)
2334 {
2335 char *token;
2336 char *t = strtok(NULL, "");
2337
2338 while ((token = strwordtok(NULL, &t)))
2339 wordlistAdd(list, token);
2340 }
2341
2342 static int
2343 check_null_wordlist(wordlist * w)
2344 {
2345 return w == NULL;
2346 }
2347
2348 static int
2349 check_null_acl_access(acl_access * a)
2350 {
2351 return a == NULL;
2352 }
2353
2354 #define free_wordlist wordlistDestroy
2355
2356 #define free_uri_whitespace free_int
2357
2358 static void
2359 parse_uri_whitespace(int *var)
2360 {
2361 char *token = strtok(NULL, w_space);
2362
2363 if (token == NULL)
2364 self_destruct();
2365
2366 if (!strcasecmp(token, "strip"))
2367 *var = URI_WHITESPACE_STRIP;
2368 else if (!strcasecmp(token, "deny"))
2369 *var = URI_WHITESPACE_DENY;
2370 else if (!strcasecmp(token, "allow"))
2371 *var = URI_WHITESPACE_ALLOW;
2372 else if (!strcasecmp(token, "encode"))
2373 *var = URI_WHITESPACE_ENCODE;
2374 else if (!strcasecmp(token, "chop"))
2375 *var = URI_WHITESPACE_CHOP;
2376 else
2377 self_destruct();
2378 }
2379
2380
2381 static void
2382 dump_uri_whitespace(StoreEntry * entry, const char *name, int var)
2383 {
2384 const char *s;
2385
2386 if (var == URI_WHITESPACE_ALLOW)
2387 s = "allow";
2388 else if (var == URI_WHITESPACE_ENCODE)
2389 s = "encode";
2390 else if (var == URI_WHITESPACE_CHOP)
2391 s = "chop";
2392 else if (var == URI_WHITESPACE_DENY)
2393 s = "deny";
2394 else
2395 s = "strip";
2396
2397 storeAppendPrintf(entry, "%s %s\n", name, s);
2398 }
2399
2400 static void
2401 free_removalpolicy(RemovalPolicySettings ** settings)
2402 {
2403 if (!*settings)
2404 return;
2405
2406 free_string(&(*settings)->type);
2407
2408 free_wordlist(&(*settings)->args);
2409
2410 xfree(*settings);
2411
2412 *settings = NULL;
2413 }
2414
2415 static void
2416 parse_removalpolicy(RemovalPolicySettings ** settings)
2417 {
2418 if (*settings)
2419 free_removalpolicy(settings);
2420
2421 *settings = static_cast<RemovalPolicySettings *>(xcalloc(1, sizeof(**settings)));
2422
2423 parse_string(&(*settings)->type);
2424
2425 parse_wordlist(&(*settings)->args);
2426 }
2427
2428 static void
2429 dump_removalpolicy(StoreEntry * entry, const char *name, RemovalPolicySettings * settings)
2430 {
2431 wordlist *args;
2432 storeAppendPrintf(entry, "%s %s", name, settings->type);
2433 args = settings->args;
2434
2435 while (args) {
2436 storeAppendPrintf(entry, " %s", args->key);
2437 args = args->next;
2438 }
2439
2440 storeAppendPrintf(entry, "\n");
2441 }
2442
2443
2444 #include "cf_parser.h"
2445
2446 peer_t
2447 parseNeighborType(const char *s)
2448 {
2449 if (!strcasecmp(s, "parent"))
2450 return PEER_PARENT;
2451
2452 if (!strcasecmp(s, "neighbor"))
2453 return PEER_SIBLING;
2454
2455 if (!strcasecmp(s, "neighbour"))
2456 return PEER_SIBLING;
2457
2458 if (!strcasecmp(s, "sibling"))
2459 return PEER_SIBLING;
2460
2461 if (!strcasecmp(s, "multicast"))
2462 return PEER_MULTICAST;
2463
2464 debug(15, 0) ("WARNING: Unknown neighbor type: %s\n", s);
2465
2466 return PEER_SIBLING;
2467 }
2468
2469 #if CURRENTLY_UNUSED
2470 /* This code was previously used by http_port. Left as it really should
2471 * be used by icp_port and htcp_port
2472 */
2473 void
2474 parse_sockaddr_in_list_token(sockaddr_in_list ** head, char *token)
2475 {
2476 char *t;
2477 char *host;
2478
2479 const struct hostent *hp;
2480 unsigned short port;
2481 sockaddr_in_list *s;
2482
2483 host = NULL;
2484 port = 0;
2485
2486 if ((t = strchr(token, ':'))) {
2487 /* host:port */
2488 host = token;
2489 *t = '\0';
2490 port = (unsigned short) xatoi(t + 1);
2491
2492 if (0 == port)
2493 self_destruct();
2494 } else if ((port = xatoi(token)) > 0) {
2495 /* port */
2496 } else {
2497 self_destruct();
2498 }
2499
2500 s = static_cast<sockaddr_in_list *>(xcalloc(1, sizeof(*s)));
2501 s->s.sin_port = htons(port);
2502
2503 if (NULL == host)
2504 s->s.sin_addr = any_addr;
2505 else if (1 == safe_inet_addr(host, &s->s.sin_addr))
2506 (void) 0;
2507 else if ((hp = gethostbyname(host))) /* dont use ipcache */
2508 s->s.sin_addr = inaddrFromHostent(hp);
2509 else
2510 self_destruct();
2511
2512 while (*head)
2513 head = &(*head)->next;
2514
2515 *head = s;
2516 }
2517
2518 static void
2519 parse_sockaddr_in_list(sockaddr_in_list ** head)
2520 {
2521 char *token;
2522
2523 while ((token = strtok(NULL, w_space))) {
2524 parse_sockaddr_in_list_token(head, token);
2525 }
2526 }
2527
2528 static void
2529 dump_sockaddr_in_list(StoreEntry * e, const char *n, const sockaddr_in_list * s)
2530 {
2531 while (s) {
2532 storeAppendPrintf(e, "%s %s:%d\n",
2533 n,
2534 inet_ntoa(s->s.sin_addr),
2535 ntohs(s->s.sin_port));
2536 s = s->next;
2537 }
2538 }
2539
2540 static void
2541 free_sockaddr_in_list(sockaddr_in_list ** head)
2542 {
2543 sockaddr_in_list *s;
2544
2545 while ((s = *head) != NULL) {
2546 *head = s->next;
2547 xfree(s);
2548 }
2549 }
2550
2551 static int
2552 check_null_sockaddr_in_list(const sockaddr_in_list * s)
2553 {
2554 return NULL == s;
2555 }
2556
2557 #endif /* CURRENTLY_UNUSED */
2558
2559 static void
2560 parse_http_port_specification(http_port_list * s, char *token)
2561 {
2562 char *host = NULL;
2563
2564 const struct hostent *hp;
2565 unsigned short port = 0;
2566 char *t;
2567
2568 if ((t = strchr(token, ':'))) {
2569 /* host:port */
2570 host = token;
2571 *t = '\0';
2572 port = (unsigned short) atoi(t + 1);
2573
2574 if (0 == port)
2575 self_destruct();
2576 } else if ((port = atoi(token)) > 0) {
2577 /* port */
2578 } else {
2579 self_destruct();
2580 }
2581
2582 s->s.sin_port = htons(port);
2583
2584 if (NULL == host)
2585 s->s.sin_addr = any_addr;
2586 else if (1 == safe_inet_addr(host, &s->s.sin_addr))
2587 (void) 0;
2588 else if ((hp = gethostbyname(host))) {
2589 /* dont use ipcache */
2590 s->s.sin_addr = inaddrFromHostent(hp);
2591 s->defaultsite = xstrdup(host);
2592 } else
2593 self_destruct();
2594 }
2595
2596 static void
2597 parse_http_port_option(http_port_list * s, char *token)
2598 {
2599 if (strncmp(token, "defaultsite=", 12) == 0) {
2600 safe_free(s->defaultsite);
2601 s->defaultsite = xstrdup(token + 12);
2602 s->accel = 1;
2603 } else if (strncmp(token, "name=", 5) == 0) {
2604 safe_free(s->name);
2605 s->name = xstrdup(token + 5);
2606 } else if (strcmp(token, "transparent") == 0) {
2607 s->transparent = 1;
2608 } else if (strcmp(token, "vhost") == 0) {
2609 s->vhost = 1;
2610 s->accel = 1;
2611 } else if (strcmp(token, "vport") == 0) {
2612 s->vport = -1;
2613 s->accel = 1;
2614 } else if (strncmp(token, "vport=", 6) == 0) {
2615 s->vport = atoi(token + 6);
2616 s->accel = 1;
2617 } else if (strncmp(token, "protocol=", 9) == 0) {
2618 s->protocol = xstrdup(token + 9);
2619 s->accel = 1;
2620 } else if (strcmp(token, "accel") == 0) {
2621 s->accel = 1;
2622 } else {
2623 self_destruct();
2624 }
2625 }
2626
2627 static void
2628 free_generic_http_port_data(http_port_list * s)
2629 {
2630 safe_free(s->name);
2631 safe_free(s->defaultsite);
2632 }
2633
2634 static void
2635 cbdataFree_http_port(void *data)
2636 {
2637 free_generic_http_port_data((http_port_list *)data);
2638 }
2639
2640
2641 static http_port_list *
2642 create_http_port(char *portspec)
2643 {
2644 CBDATA_TYPE(http_port_list);
2645 CBDATA_INIT_TYPE_FREECB(http_port_list, cbdataFree_http_port);
2646
2647 http_port_list *s = cbdataAlloc(http_port_list);
2648 s->protocol = xstrdup("http");
2649 parse_http_port_specification(s, portspec);
2650 return s;
2651 }
2652
2653 void
2654 add_http_port(char *portspec)
2655 {
2656 http_port_list *s = create_http_port(portspec);
2657 s->next = Config.Sockaddr.http;
2658 Config.Sockaddr.http = s;
2659 }
2660
2661 static void
2662 parse_http_port_list(http_port_list ** head)
2663 {
2664 char *token = strtok(NULL, w_space);
2665
2666 if (!token)
2667 self_destruct();
2668
2669 http_port_list *s = create_http_port(token);
2670
2671 /* parse options ... */
2672 while ((token = strtok(NULL, w_space))) {
2673 parse_http_port_option(s, token);
2674 }
2675
2676 while (*head)
2677 head = &(*head)->next;
2678
2679 *head = s;
2680 }
2681
2682 static void
2683 dump_generic_http_port(StoreEntry * e, const char *n, const http_port_list * s)
2684 {
2685 storeAppendPrintf(e, "%s %s:%d",
2686 n,
2687 inet_ntoa(s->s.sin_addr),
2688 ntohs(s->s.sin_port));
2689
2690 if (s->defaultsite)
2691 storeAppendPrintf(e, " defaultsite=%s", s->defaultsite);
2692
2693 if (s->transparent)
2694 storeAppendPrintf(e, " transparent");
2695
2696 if (s->vhost)
2697 storeAppendPrintf(e, " vhost");
2698
2699 if (s->vport)
2700 storeAppendPrintf(e, " vport");
2701 }
2702
2703 static void
2704 dump_http_port_list(StoreEntry * e, const char *n, const http_port_list * s)
2705 {
2706 while (s) {
2707 dump_generic_http_port(e, n, s);
2708 storeAppendPrintf(e, "\n");
2709 s = s->next;
2710 }
2711 }
2712
2713 static void
2714 free_http_port_list(http_port_list ** head)
2715 {
2716 http_port_list *s;
2717
2718 while ((s = *head) != NULL) {
2719 *head = s->next;
2720 cbdataFree(s);
2721 }
2722 }
2723
2724 #if UNUSED_CODE
2725 static int
2726 check_null_http_port_list(const http_port_list * s)
2727 {
2728 return NULL == s;
2729 }
2730
2731 #endif
2732
2733 #if USE_SSL
2734 static void
2735 cbdataFree_https_port(void *data)
2736 {
2737 https_port_list *s = (https_port_list *)data;
2738 free_generic_http_port_data(&s->http);
2739 safe_free(s->cert);
2740 safe_free(s->key);
2741 }
2742
2743 static void
2744 parse_https_port_list(https_port_list ** head)
2745 {
2746 CBDATA_TYPE(https_port_list);
2747 char *token;
2748 https_port_list *s;
2749 CBDATA_INIT_TYPE_FREECB(https_port_list, cbdataFree_https_port);
2750 token = strtok(NULL, w_space);
2751
2752 if (!token)
2753 self_destruct();
2754
2755 s = cbdataAlloc(https_port_list);
2756
2757 s->http.protocol = xstrdup("https");
2758
2759 parse_http_port_specification(&s->http, token);
2760
2761 /* parse options ... */
2762 while ((token = strtok(NULL, w_space))) {
2763 if (strncmp(token, "cert=", 5) == 0) {
2764 safe_free(s->cert);
2765 s->cert = xstrdup(token + 5);
2766 } else if (strncmp(token, "key=", 4) == 0) {
2767 safe_free(s->key);
2768 s->key = xstrdup(token + 4);
2769 } else if (strncmp(token, "version=", 8) == 0) {
2770 s->version = xatoi(token + 8);
2771 } else if (strncmp(token, "options=", 8) == 0) {
2772 safe_free(s->options);
2773 s->options = xstrdup(token + 8);
2774 } else if (strncmp(token, "cipher=", 7) == 0) {
2775 safe_free(s->cipher);
2776 s->cipher = xstrdup(token + 7);
2777 } else if (strncmp(token, "clientca=", 9) == 0) {
2778 safe_free(s->clientca);
2779 s->clientca = xstrdup(token + 9);
2780 } else if (strncmp(token, "cafile=", 7) == 0) {
2781 safe_free(s->cafile);
2782 s->cafile = xstrdup(token + 7);
2783 } else if (strncmp(token, "capath=", 7) == 0) {
2784 safe_free(s->capath);
2785 s->capath = xstrdup(token + 7);
2786 } else if (strncmp(token, "dhparams=", 9) == 0) {
2787 safe_free(s->dhfile);
2788 s->dhfile = xstrdup(token + 9);
2789 } else if (strncmp(token, "sslflags=", 9) == 0) {
2790 safe_free(s->sslflags);
2791 s->sslflags = xstrdup(token + 9);
2792 } else {
2793 parse_http_port_option(&s->http, token);
2794 }
2795 }
2796
2797 s->sslContext = sslCreateServerContext(s->cert, s->key, s->version, s->cipher, s->options, s->sslflags, s->clientca, s->cafile, s->capath, s->dhfile);
2798
2799 if (!s->sslContext)
2800 self_destruct();
2801
2802 while (*head)
2803 head = (https_port_list **)&(*head)->http.next;
2804
2805 *head = s;
2806 }
2807
2808 static void
2809 dump_https_port_list(StoreEntry * e, const char *n, const https_port_list * s)
2810 {
2811 while (s) {
2812 dump_generic_http_port(e, n, &s->http);
2813
2814 if (s->cert)
2815 storeAppendPrintf(e, " cert=%s", s->cert);
2816
2817 if (s->key)
2818 storeAppendPrintf(e, " key=%s", s->cert);
2819
2820 if (s->version)
2821 storeAppendPrintf(e, " version=%d", s->version);
2822
2823 if (s->options)
2824 storeAppendPrintf(e, " options=%s", s->options);
2825
2826 if (s->cipher)
2827 storeAppendPrintf(e, " cipher=%s", s->cipher);
2828
2829 if (s->cafile)
2830 storeAppendPrintf(e, " cafile=%s", s->cafile);
2831
2832 if (s->capath)
2833 storeAppendPrintf(e, " capath=%s", s->capath);
2834
2835 if (s->dhfile)
2836 storeAppendPrintf(e, " dhparams=%s", s->dhfile);
2837
2838 if (s->sslflags)
2839 storeAppendPrintf(e, " sslflags=%s", s->sslflags);
2840
2841 storeAppendPrintf(e, "\n");
2842
2843 s = (https_port_list *) s->http.next;
2844 }
2845 }
2846
2847 static void
2848 free_https_port_list(https_port_list ** head)
2849 {
2850 https_port_list *s;
2851
2852 while ((s = *head) != NULL) {
2853 *head = (https_port_list *) s->http.next;
2854 cbdataFree(s);
2855 }
2856 }
2857
2858 #if 0
2859 static int
2860 check_null_https_port_list(const https_port_list * s)
2861 {
2862 return NULL == s;
2863 }
2864
2865 #endif
2866
2867 #endif /* USE_SSL */
2868
2869 void
2870 configFreeMemory(void)
2871 {
2872 free_all();
2873 }
2874
2875 void
2876 requirePathnameExists(const char *name, const char *path)
2877 {
2878
2879 struct stat sb;
2880 char pathbuf[BUFSIZ];
2881 assert(path != NULL);
2882
2883 if (Config.chroot_dir) {
2884 snprintf(pathbuf, BUFSIZ, "%s/%s", Config.chroot_dir, path);
2885 path = pathbuf;
2886 }
2887
2888 if (stat(path, &sb) < 0)
2889 fatalf("%s %s: %s", name, path, xstrerror());
2890 }
2891
2892 char *
2893 strtokFile(void)
2894 {
2895 static int fromFile = 0;
2896 static FILE *wordFile = NULL;
2897
2898 char *t, *fn;
2899 LOCAL_ARRAY(char, buf, 256);
2900
2901 strtok_again:
2902
2903 if (!fromFile) {
2904 t = (strtok(NULL, w_space));
2905
2906 if (!t || *t == '#') {
2907 return NULL;
2908 } else if (*t == '\"' || *t == '\'') {
2909 /* quote found, start reading from file */
2910 fn = ++t;
2911
2912 while (*t && *t != '\"' && *t != '\'')
2913 t++;
2914
2915 *t = '\0';
2916
2917 if ((wordFile = fopen(fn, "r")) == NULL) {
2918 debug(28, 0) ("strtokFile: %s not found\n", fn);
2919 return (NULL);
2920 }
2921
2922 #ifdef _SQUID_WIN32_
2923 setmode(fileno(wordFile), O_TEXT);
2924
2925 #endif
2926
2927 fromFile = 1;
2928 } else {
2929 return t;
2930 }
2931 }
2932
2933 /* fromFile */
2934 if (fgets(buf, 256, wordFile) == NULL) {
2935 /* stop reading from file */
2936 fclose(wordFile);
2937 wordFile = NULL;
2938 fromFile = 0;
2939 goto strtok_again;
2940 } else {
2941 char *t2, *t3;
2942 t = buf;
2943 /* skip leading and trailing white space */
2944 t += strspn(buf, w_space);
2945 t2 = t + strcspn(t, w_space);
2946 t3 = t2 + strspn(t2, w_space);
2947
2948 while (*t3 && *t3 != '#') {
2949 t2 = t3 + strcspn(t3, w_space);
2950 t3 = t2 + strspn(t2, w_space);
2951 }
2952
2953 *t2 = '\0';
2954 /* skip comments */
2955
2956 if (*t == '#')
2957 goto strtok_again;
2958
2959 /* skip blank lines */
2960 if (!*t)
2961 goto strtok_again;
2962
2963 return t;
2964 }
2965 }
2966
2967 #include "AccessLogEntry.h"
2968 /* TODO: split out parsing somehow ...*/
2969 static void
2970 parse_logformat(logformat ** logformat_definitions)
2971 {
2972 logformat *nlf;
2973 char *name, *def;
2974
2975 if ((name = strtok(NULL, w_space)) == NULL)
2976 self_destruct();
2977
2978 if ((def = strtok(NULL, "\r\n")) == NULL)
2979 self_destruct();
2980
2981 debug(3, 1) ("Logformat for '%s' is '%s'\n", name, def);
2982
2983 nlf = (logformat *)xcalloc(1, sizeof(logformat));
2984
2985 nlf->name = xstrdup(name);
2986
2987 if (!accessLogParseLogFormat(&nlf->format, def))
2988 self_destruct();
2989
2990 nlf->next = *logformat_definitions;
2991
2992 *logformat_definitions = nlf;
2993 }
2994
2995 static void
2996 parse_access_log(customlog ** logs)
2997 {
2998 const char *filename, *logdef_name;
2999 customlog *cl;
3000 logformat *lf;
3001
3002 cl = (customlog *)xcalloc(1, sizeof(*cl));
3003
3004 if ((filename = strtok(NULL, w_space)) == NULL)
3005 self_destruct();
3006
3007 if (strcmp(filename, "none") == 0) {
3008 cl->type = CLF_NONE;
3009 goto done;
3010 }
3011
3012 if ((logdef_name = strtok(NULL, w_space)) == NULL)
3013 logdef_name = "auto";
3014
3015 debug(3, 9) ("Log definition name '%s' file '%s'\n", logdef_name, filename);
3016
3017 cl->filename = xstrdup(filename);
3018
3019 /* look for the definition pointer corresponding to this name */
3020 lf = Config.Log.logformats;
3021
3022 while (lf != NULL) {
3023 debug(3, 9) ("Comparing against '%s'\n", lf->name);
3024
3025 if (strcmp(lf->name, logdef_name) == 0)
3026 break;
3027
3028 lf = lf->next;
3029 }
3030
3031 if (lf != NULL) {
3032 cl->type = CLF_CUSTOM;
3033 cl->logFormat = lf;
3034 } else if (strcmp(logdef_name, "auto") == 0) {
3035 cl->type = CLF_AUTO;
3036 } else if (strcmp(logdef_name, "squid") == 0) {
3037 cl->type = CLF_SQUID;
3038 } else if (strcmp(logdef_name, "common") == 0) {
3039 cl->type = CLF_COMMON;
3040 } else {
3041 debug(3, 0) ("Log format '%s' is not defined\n", logdef_name);
3042 self_destruct();
3043 }
3044
3045 done:
3046 aclParseAclList(&cl->aclList);
3047
3048 while (*logs)
3049 logs = &(*logs)->next;
3050
3051 *logs = cl;
3052 }
3053
3054 static int
3055 check_null_access_log(customlog *customlog_definitions)
3056 {
3057 return customlog_definitions == NULL;
3058 }
3059
3060 static void
3061 dump_logformat(StoreEntry * entry, const char *name, logformat * definitions)
3062 {
3063 accessLogDumpLogFormat(entry, name, definitions);
3064 }
3065
3066 static void
3067 dump_access_log(StoreEntry * entry, const char *name, customlog * logs)
3068 {
3069 customlog *log;
3070
3071 for (log = logs; log; log = log->next) {
3072 storeAppendPrintf(entry, "%s ", name);
3073
3074 switch (log->type) {
3075
3076 case CLF_CUSTOM:
3077 storeAppendPrintf(entry, "%s %s", log->filename, log->logFormat->name);
3078 break;
3079
3080 case CLF_NONE:
3081 storeAppendPrintf(entry, "none");
3082 break;
3083
3084 case CLF_SQUID:
3085 storeAppendPrintf(entry, "%s squid", log->filename);
3086 break;
3087
3088 case CLF_COMMON:
3089 storeAppendPrintf(entry, "%s squid", log->filename);
3090 break;
3091
3092 case CLF_AUTO:
3093
3094 if (log->aclList)
3095 storeAppendPrintf(entry, "%s auto", log->filename);
3096 else
3097 storeAppendPrintf(entry, "%s", log->filename);
3098
3099 break;
3100
3101 case CLF_UNKNOWN:
3102 break;
3103 }
3104
3105 if (log->aclList)
3106 dump_acl_list(entry, log->aclList);
3107
3108 storeAppendPrintf(entry, "\n");
3109 }
3110 }
3111
3112 static void
3113 free_logformat(logformat ** definitions)
3114 {
3115 while (*definitions) {
3116 logformat *format = *definitions;
3117 *definitions = format->next;
3118 accessLogFreeLogFormat(&format->format);
3119 xfree(format);
3120 }
3121 }
3122
3123 static void
3124 free_access_log(customlog ** definitions)
3125 {
3126 while (*definitions) {
3127 customlog *log = *definitions;
3128 *definitions = log->next;
3129
3130 log->logFormat = NULL;
3131 log->type = CLF_UNKNOWN;
3132
3133 if (log->aclList)
3134 aclDestroyAclList(&log->aclList);
3135
3136 safe_free(log->filename);
3137
3138 xfree(log);
3139 }
3140 }