]> git.ipfire.org Git - thirdparty/squid.git/blob - src/cache_cf.cc
Bug 2785: DNS needs to set EDNS options advertising Squid capabilities
[thirdparty/squid.git] / src / cache_cf.cc
1 /*
2 * $Id$
3 *
4 * DEBUG: section 03 Configuration File Parsing
5 * AUTHOR: Harvest Derived
6 *
7 * SQUID Web Proxy Cache http://www.squid-cache.org/
8 * ----------------------------------------------------------
9 *
10 * Squid is the result of efforts by numerous individuals from
11 * the Internet community; see the CONTRIBUTORS file for full
12 * details. Many organizations have provided support for Squid's
13 * development; see the SPONSORS file for full details. Squid is
14 * Copyrighted (C) 2001 by the Regents of the University of
15 * California; see the COPYRIGHT file for full details. Squid
16 * incorporates software developed and/or copyrighted by other
17 * sources; see the CREDITS file for full details.
18 *
19 * This program is free software; you can redistribute it and/or modify
20 * it under the terms of the GNU General Public License as published by
21 * the Free Software Foundation; either version 2 of the License, or
22 * (at your option) any later version.
23 *
24 * This program is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * You should have received a copy of the GNU General Public License
30 * along with this program; if not, write to the Free Software
31 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
32 *
33 */
34
35 #include "squid.h"
36
37 #include "acl/Acl.h"
38 #include "acl/Gadgets.h"
39 #include "acl/MethodData.h"
40 #if USE_ADAPTATION
41 #include "adaptation/Config.h"
42 #endif
43 #if ICAP_CLIENT
44 #include "adaptation/icap/Config.h"
45 #endif
46 #if USE_ECAP
47 #include "adaptation/ecap/Config.h"
48 #endif
49 #include "auth/Config.h"
50 #include "auth/Scheme.h"
51 #include "CacheManager.h"
52 #include "ConfigParser.h"
53 #include "CpuAffinityMap.h"
54 #include "eui/Config.h"
55 #if USE_SQUID_ESI
56 #include "esi/Parser.h"
57 #endif
58 #include "HttpRequestMethod.h"
59 #include "ident/Config.h"
60 #include "ip/Intercept.h"
61 #include "ip/QosConfig.h"
62 #include "ip/tools.h"
63 #include "log/Config.h"
64 #include "MemBuf.h"
65 #include "Parsing.h"
66 #include "ProtoPort.h"
67 #include "rfc1738.h"
68 #if SQUID_SNMP
69 #include "snmp.h"
70 #endif
71 #include "Store.h"
72 #include "StoreFileSystem.h"
73 #include "SwapDir.h"
74 #include "wordlist.h"
75 #include "ipc/Kids.h"
76
77 #if HAVE_GLOB_H
78 #include <glob.h>
79 #endif
80
81 #if HAVE_LIMITS_H
82 #include <limits>
83 #endif
84
85 #if USE_ADAPTATION
86 static void parse_adaptation_service_set_type();
87 static void parse_adaptation_service_chain_type();
88 static void parse_adaptation_access_type();
89 #endif
90
91 #if ICAP_CLIENT
92 static void parse_icap_service_type(Adaptation::Icap::Config *);
93 static void dump_icap_service_type(StoreEntry *, const char *, const Adaptation::Icap::Config &);
94 static void free_icap_service_type(Adaptation::Icap::Config *);
95 static void parse_icap_class_type();
96 static void parse_icap_access_type();
97
98 static void parse_icap_service_failure_limit(Adaptation::Icap::Config *);
99 static void dump_icap_service_failure_limit(StoreEntry *, const char *, const Adaptation::Icap::Config &);
100 static void free_icap_service_failure_limit(Adaptation::Icap::Config *);
101 #endif
102
103 #if USE_ECAP
104 static void parse_ecap_service_type(Adaptation::Ecap::Config *);
105 static void dump_ecap_service_type(StoreEntry *, const char *, const Adaptation::Ecap::Config &);
106 static void free_ecap_service_type(Adaptation::Ecap::Config *);
107 #endif
108
109 CBDATA_TYPE(peer);
110
111 static const char *const T_SECOND_STR = "second";
112 static const char *const T_MINUTE_STR = "minute";
113 static const char *const T_HOUR_STR = "hour";
114 static const char *const T_DAY_STR = "day";
115 static const char *const T_WEEK_STR = "week";
116 static const char *const T_FORTNIGHT_STR = "fortnight";
117 static const char *const T_MONTH_STR = "month";
118 static const char *const T_YEAR_STR = "year";
119 static const char *const T_DECADE_STR = "decade";
120
121 static const char *const B_BYTES_STR = "bytes";
122 static const char *const B_KBYTES_STR = "KB";
123 static const char *const B_MBYTES_STR = "MB";
124 static const char *const B_GBYTES_STR = "GB";
125
126 static const char *const list_sep = ", \t\n\r";
127
128 static void parse_logformat(logformat ** logformat_definitions);
129 static void parse_access_log(customlog ** customlog_definitions);
130 static int check_null_access_log(customlog *customlog_definitions);
131
132 static void dump_logformat(StoreEntry * entry, const char *name, logformat * definitions);
133 static void dump_access_log(StoreEntry * entry, const char *name, customlog * definitions);
134 static void free_logformat(logformat ** definitions);
135 static void free_access_log(customlog ** definitions);
136
137 static void update_maxobjsize(void);
138 static void configDoConfigure(void);
139 static void parse_refreshpattern(refresh_t **);
140 static int parseTimeUnits(const char *unit);
141 static void parseTimeLine(time_t * tptr, const char *units);
142 static void parse_ushort(u_short * var);
143 static void parse_string(char **);
144 static void default_all(void);
145 static void defaults_if_none(void);
146 static int parse_line(char *);
147 static void parseBytesLine(size_t * bptr, const char *units);
148 #if !USE_DNSSERVERS
149 static void parseBytesLineSigned(ssize_t * bptr, const char *units);
150 #endif
151 static size_t parseBytesUnits(const char *unit);
152 static void free_all(void);
153 void requirePathnameExists(const char *name, const char *path);
154 static OBJH dump_config;
155 #if USE_HTTP_VIOLATIONS
156 static void dump_http_header_access(StoreEntry * entry, const char *name, header_mangler header[]);
157 static void parse_http_header_access(header_mangler header[]);
158 static void free_http_header_access(header_mangler header[]);
159 static void dump_http_header_replace(StoreEntry * entry, const char *name, header_mangler header[]);
160 static void parse_http_header_replace(header_mangler * header);
161 static void free_http_header_replace(header_mangler * header);
162 #endif
163 static void parse_denyinfo(acl_deny_info_list ** var);
164 static void dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var);
165 static void free_denyinfo(acl_deny_info_list ** var);
166
167 #if USE_WCCPv2
168 static void parse_IpAddress_list(Ip::Address_list **);
169 static void dump_IpAddress_list(StoreEntry *, const char *, const Ip::Address_list *);
170 static void free_IpAddress_list(Ip::Address_list **);
171 #if CURRENTLY_UNUSED
172 static int check_null_IpAddress_list(const Ip::Address_list *);
173 #endif /* CURRENTLY_UNUSED */
174 #endif /* USE_WCCPv2 */
175
176 static void parse_http_port_list(http_port_list **);
177 static void dump_http_port_list(StoreEntry *, const char *, const http_port_list *);
178 static void free_http_port_list(http_port_list **);
179
180 #if USE_SSL
181 static void parse_https_port_list(https_port_list **);
182 static void dump_https_port_list(StoreEntry *, const char *, const https_port_list *);
183 static void free_https_port_list(https_port_list **);
184 #if 0
185 static int check_null_https_port_list(const https_port_list *);
186 #endif
187 #endif /* USE_SSL */
188
189 static void parse_b_size_t(size_t * var);
190 static void parse_b_int64_t(int64_t * var);
191
192 static bool parseNamedIntList(const char *data, const String &name, Vector<int> &list);
193
194 static void parse_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap);
195 static void dump_CpuAffinityMap(StoreEntry *const entry, const char *const name, const CpuAffinityMap *const cpuAffinityMap);
196 static void free_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap);
197
198 static int parseOneConfigFile(const char *file_name, unsigned int depth);
199
200 /*
201 * LegacyParser is a parser for legacy code that uses the global
202 * approach. This is static so that it is only exposed to cache_cf.
203 * Other modules needing access to a ConfigParser should have it
204 * provided to them in their parserFOO methods.
205 */
206 static ConfigParser LegacyParser = ConfigParser();
207
208 void
209 self_destruct(void)
210 {
211 LegacyParser.destruct();
212 }
213
214 static void
215 update_maxobjsize(void)
216 {
217 int i;
218 int64_t ms = -1;
219
220 for (i = 0; i < Config.cacheSwap.n_configured; i++) {
221 assert (Config.cacheSwap.swapDirs[i].getRaw());
222
223 if (dynamic_cast<SwapDir *>(Config.cacheSwap.swapDirs[i].getRaw())->
224 max_objsize > ms)
225 ms = dynamic_cast<SwapDir *>(Config.cacheSwap.swapDirs[i].getRaw())->max_objsize;
226 }
227 store_maxobjsize = ms;
228 }
229
230 static void
231 SetConfigFilename(char const *file_name, bool is_pipe)
232 {
233 cfg_filename = file_name;
234
235 char const *token;
236
237 if (is_pipe)
238 cfg_filename = file_name + 1;
239 else if ((token = strrchr(cfg_filename, '/')))
240 cfg_filename = token + 1;
241 }
242
243 static const char*
244 skip_ws(const char* s)
245 {
246 while (xisspace(*s))
247 ++s;
248
249 return s;
250 }
251
252 static int
253 parseManyConfigFiles(char* files, int depth)
254 {
255 int error_count = 0;
256 char* saveptr = NULL;
257 #if HAVE_GLOB
258 char *path;
259 glob_t globbuf;
260 int i;
261 memset(&globbuf, 0, sizeof(globbuf));
262 for (path = strwordtok(files, &saveptr); path; path = strwordtok(NULL, &saveptr)) {
263 if (glob(path, globbuf.gl_pathc ? GLOB_APPEND : 0, NULL, &globbuf) != 0) {
264 fatalf("Unable to find configuration file: %s: %s",
265 path, xstrerror());
266 }
267 }
268 for (i = 0; i < (int)globbuf.gl_pathc; i++) {
269 error_count += parseOneConfigFile(globbuf.gl_pathv[i], depth);
270 }
271 globfree(&globbuf);
272 #else
273 char* file = strwordtok(files, &saveptr);
274 while (file != NULL) {
275 error_count += parseOneConfigFile(file, depth);
276 file = strwordtok(NULL, &saveptr);
277 }
278 #endif /* HAVE_GLOB */
279 return error_count;
280 }
281
282 static void
283 ReplaceSubstr(char*& str, int& len, unsigned substrIdx, unsigned substrLen, const char* newSubstr)
284 {
285 assert(str != NULL);
286 assert(newSubstr != NULL);
287
288 unsigned newSubstrLen = strlen(newSubstr);
289 if (newSubstrLen > substrLen)
290 str = (char*)realloc(str, len - substrLen + newSubstrLen + 1);
291
292 // move tail part including zero
293 memmove(str + substrIdx + newSubstrLen, str + substrIdx + substrLen, len - substrIdx - substrLen + 1);
294 // copy new substring in place
295 memcpy(str + substrIdx, newSubstr, newSubstrLen);
296
297 len = strlen(str);
298 }
299
300 static void
301 SubstituteMacro(char*& line, int& len, const char* macroName, const char* substStr)
302 {
303 assert(line != NULL);
304 assert(macroName != NULL);
305 assert(substStr != NULL);
306 unsigned macroNameLen = strlen(macroName);
307 while (const char* macroPos = strstr(line, macroName)) // we would replace all occurrences
308 ReplaceSubstr(line, len, macroPos - line, macroNameLen, substStr);
309 }
310
311 static void
312 ProcessMacros(char*& line, int& len)
313 {
314 SubstituteMacro(line, len, "${process_name}", TheKidName);
315 SubstituteMacro(line, len, "${process_number}", xitoa(KidIdentifier));
316 }
317
318 static void
319 trim_trailing_ws(char* str)
320 {
321 assert(str != NULL);
322 unsigned i = strlen(str);
323 while ((i > 0) && xisspace(str[i - 1]))
324 --i;
325 str[i] = '\0';
326 }
327
328 static const char*
329 FindStatement(const char* line, const char* statement)
330 {
331 assert(line != NULL);
332 assert(statement != NULL);
333
334 const char* str = skip_ws(line);
335 unsigned len = strlen(statement);
336 if (strncmp(str, statement, len) == 0) {
337 str += len;
338 if (*str == '\0')
339 return str;
340 else if (xisspace(*str))
341 return skip_ws(str);
342 }
343
344 return NULL;
345 }
346
347 static bool
348 StrToInt(const char* str, long& number)
349 {
350 assert(str != NULL);
351
352 char* end;
353 number = strtol(str, &end, 0);
354
355 return (end != str) && (*end == '\0'); // returns true if string contains nothing except number
356 }
357
358 static bool
359 EvalBoolExpr(const char* expr)
360 {
361 assert(expr != NULL);
362 if (strcmp(expr, "true") == 0) {
363 return true;
364 } else if (strcmp(expr, "false") == 0) {
365 return false;
366 } else if (const char* equation = strchr(expr, '=')) {
367 const char* rvalue = skip_ws(equation + 1);
368 char* lvalue = (char*)xmalloc(equation - expr + 1);
369 xstrncpy(lvalue, expr, equation - expr + 1);
370 trim_trailing_ws(lvalue);
371
372 long number1;
373 if (!StrToInt(lvalue, number1))
374 fatalf("String is not a integer number: '%s'\n", lvalue);
375 long number2;
376 if (!StrToInt(rvalue, number2))
377 fatalf("String is not a integer number: '%s'\n", rvalue);
378
379 xfree(lvalue);
380 return number1 == number2;
381 }
382 fatalf("Unable to evaluate expression '%s'\n", expr);
383 return false; // this place cannot be reached
384 }
385
386 static int
387 parseOneConfigFile(const char *file_name, unsigned int depth)
388 {
389 FILE *fp = NULL;
390 const char *orig_cfg_filename = cfg_filename;
391 const int orig_config_lineno = config_lineno;
392 char *token = NULL;
393 char *tmp_line = NULL;
394 int tmp_line_len = 0;
395 int err_count = 0;
396 int is_pipe = 0;
397
398 debugs(3, 1, "Processing Configuration File: " << file_name << " (depth " << depth << ")");
399 if (depth > 16) {
400 fatalf("WARNING: can't include %s: includes are nested too deeply (>16)!\n", file_name);
401 return 1;
402 }
403
404 if (file_name[0] == '!' || file_name[0] == '|') {
405 fp = popen(file_name + 1, "r");
406 is_pipe = 1;
407 } else {
408 fp = fopen(file_name, "r");
409 }
410
411 if (fp == NULL)
412 fatalf("Unable to open configuration file: %s: %s", file_name, xstrerror());
413
414 #ifdef _SQUID_WIN32_
415
416 setmode(fileno(fp), O_TEXT);
417
418 #endif
419
420 SetConfigFilename(file_name, bool(is_pipe));
421
422 memset(config_input_line, '\0', BUFSIZ);
423
424 config_lineno = 0;
425
426 Vector<bool> if_states;
427 while (fgets(config_input_line, BUFSIZ, fp)) {
428 config_lineno++;
429
430 if ((token = strchr(config_input_line, '\n')))
431 *token = '\0';
432
433 if ((token = strchr(config_input_line, '\r')))
434 *token = '\0';
435
436 if (strncmp(config_input_line, "#line ", 6) == 0) {
437 static char new_file_name[1024];
438 static char *file;
439 static char new_lineno;
440 token = config_input_line + 6;
441 new_lineno = strtol(token, &file, 0) - 1;
442
443 if (file == token)
444 continue; /* Not a valid #line directive, may be a comment */
445
446 while (*file && xisspace((unsigned char) *file))
447 file++;
448
449 if (*file) {
450 if (*file != '"')
451 continue; /* Not a valid #line directive, may be a comment */
452
453 xstrncpy(new_file_name, file + 1, sizeof(new_file_name));
454
455 if ((token = strchr(new_file_name, '"')))
456 *token = '\0';
457
458 cfg_filename = new_file_name;
459 }
460
461 config_lineno = new_lineno;
462 }
463
464 if (config_input_line[0] == '#')
465 continue;
466
467 if (config_input_line[0] == '\0')
468 continue;
469
470 const char* append = tmp_line_len ? skip_ws(config_input_line) : config_input_line;
471
472 size_t append_len = strlen(append);
473
474 tmp_line = (char*)xrealloc(tmp_line, tmp_line_len + append_len + 1);
475
476 strcpy(tmp_line + tmp_line_len, append);
477
478 tmp_line_len += append_len;
479
480 if (tmp_line[tmp_line_len-1] == '\\') {
481 debugs(3, 5, "parseConfigFile: tmp_line='" << tmp_line << "'");
482 tmp_line[--tmp_line_len] = '\0';
483 continue;
484 }
485
486 trim_trailing_ws(tmp_line);
487 ProcessMacros(tmp_line, tmp_line_len);
488 debugs(3, 5, "Processing: '" << tmp_line << "'");
489
490 if (const char* expr = FindStatement(tmp_line, "if")) {
491 if_states.push_back(EvalBoolExpr(expr)); // store last if-statement meaning
492 } else if (FindStatement(tmp_line, "endif")) {
493 if (!if_states.empty())
494 if_states.pop_back(); // remove last if-statement meaning
495 else
496 fatalf("'endif' without 'if'\n");
497 } else if (FindStatement(tmp_line, "else")) {
498 if (!if_states.empty())
499 if_states.back() = !if_states.back();
500 else
501 fatalf("'else' without 'if'\n");
502 } else if (if_states.empty() || if_states.back()) { // test last if-statement meaning if present
503 /* Handle includes here */
504 if (tmp_line_len >= 9 && strncmp(tmp_line, "include", 7) == 0 && xisspace(tmp_line[7])) {
505 err_count += parseManyConfigFiles(tmp_line + 8, depth + 1);
506 } else if (!parse_line(tmp_line)) {
507 debugs(3, 0, HERE << cfg_filename << ":" << config_lineno << " unrecognized: '" << tmp_line << "'");
508 err_count++;
509 }
510 }
511
512 safe_free(tmp_line);
513 tmp_line_len = 0;
514
515 }
516 if (!if_states.empty())
517 fatalf("if-statement without 'endif'\n");
518
519 if (is_pipe) {
520 int ret = pclose(fp);
521
522 if (ret != 0)
523 fatalf("parseConfigFile: '%s' failed with exit code %d\n", file_name, ret);
524 } else {
525 fclose(fp);
526 }
527
528 cfg_filename = orig_cfg_filename;
529 config_lineno = orig_config_lineno;
530
531 return err_count;
532 }
533
534 int
535 parseConfigFile(const char *file_name)
536 {
537 int err_count = 0;
538 CacheManager *manager=CacheManager::GetInstance();
539
540 debugs(5, 4, HERE);
541
542 configFreeMemory();
543
544 ACLMethodData::ThePurgeCount = 0;
545 default_all();
546
547 err_count = parseOneConfigFile(file_name, 0);
548
549 defaults_if_none();
550
551 /*
552 * We must call configDoConfigure() before leave_suid() because
553 * configDoConfigure() is where we turn username strings into
554 * uid values.
555 */
556 configDoConfigure();
557
558 if (!Config.chroot_dir) {
559 leave_suid();
560 setUmask(Config.umask);
561 _db_init(Debug::cache_log, Debug::debugOptions);
562 enter_suid();
563 }
564
565 if (opt_send_signal == -1) {
566 manager->registerAction("config",
567 "Current Squid Configuration",
568 dump_config,
569 1, 1);
570 }
571
572 return err_count;
573 }
574
575
576 static void
577 configDoConfigure(void)
578 {
579 memset(&Config2, '\0', sizeof(SquidConfig2));
580 /* init memory as early as possible */
581 memConfigure();
582 /* Sanity checks */
583
584 if (Config.cacheSwap.swapDirs == NULL) {
585 /* Memory-only cache probably in effect. */
586 /* turn off the cache rebuild delays... */
587 StoreController::store_dirs_rebuilding = 0;
588 }
589
590 if (Debug::rotateNumber < 0) {
591 Debug::rotateNumber = Config.Log.rotateNumber;
592 }
593
594 #if SIZEOF_OFF_T <= 4
595 if (Config.Store.maxObjectSize > 0x7FFF0000) {
596 debugs(3, 0, "WARNING: This Squid binary can not handle files larger than 2GB. Limiting maximum_object_size to just below 2GB");
597 Config.Store.maxObjectSize = 0x7FFF0000;
598 }
599 #endif
600 if (0 == Store::Root().maxSize())
601 /* people might want a zero-sized cache on purpose */
602 (void) 0;
603 else if (Store::Root().maxSize() < (Config.memMaxSize >> 10))
604 /* This is bogus. folk with NULL caches will want this */
605 debugs(3, 0, "WARNING cache_mem is larger than total disk cache space!");
606
607 if (Config.Announce.period > 0) {
608 Config.onoff.announce = 1;
609 } else if (Config.Announce.period < 1) {
610 Config.Announce.period = 86400 * 365; /* one year */
611 Config.onoff.announce = 0;
612 }
613
614 if (Config.onoff.httpd_suppress_version_string)
615 visible_appname_string = (char *)appname_string;
616 else
617 visible_appname_string = (char const *)APP_FULLNAME;
618
619 #if USE_DNSSERVERS
620
621 if (Config.dnsChildren.n_max < 1)
622 fatal("No dnsservers allocated");
623
624 #endif
625
626 if (Config.Program.redirect) {
627 if (Config.redirectChildren.n_max < 1) {
628 Config.redirectChildren.n_max = 0;
629 wordlistDestroy(&Config.Program.redirect);
630 }
631 }
632
633 if (Config.appendDomain)
634 if (*Config.appendDomain != '.')
635 fatal("append_domain must begin with a '.'");
636
637 if (Config.errHtmlText == NULL)
638 Config.errHtmlText = xstrdup(null_string);
639
640 storeConfigure();
641
642 snprintf(ThisCache, sizeof(ThisCache), "%s (%s)",
643 uniqueHostname(),
644 visible_appname_string);
645
646 /*
647 * the extra space is for loop detection in client_side.c -- we search
648 * for substrings in the Via header.
649 */
650 snprintf(ThisCache2, sizeof(ThisCache), " %s (%s)",
651 uniqueHostname(),
652 visible_appname_string);
653
654 /* Use visible_hostname as default surrogate_id */
655 if (!Config.Accel.surrogate_id) {
656 const char *t = getMyHostname();
657 Config.Accel.surrogate_id = xstrdup( (t?t:"unset-id") );
658 }
659
660 if (!Config.udpMaxHitObjsz || Config.udpMaxHitObjsz > SQUID_UDP_SO_SNDBUF)
661 Config.udpMaxHitObjsz = SQUID_UDP_SO_SNDBUF;
662
663 if (Config.appendDomain)
664 Config.appendDomainLen = strlen(Config.appendDomain);
665 else
666 Config.appendDomainLen = 0;
667
668 if (Config.retry.maxtries > 10)
669 fatal("maximum_single_addr_tries cannot be larger than 10");
670
671 if (Config.retry.maxtries < 1) {
672 debugs(3, 0, "WARNING: resetting 'maximum_single_addr_tries to 1");
673 Config.retry.maxtries = 1;
674 }
675
676 requirePathnameExists("MIME Config Table", Config.mimeTablePathname);
677 #if USE_DNSSERVERS
678
679 requirePathnameExists("cache_dns_program", Config.Program.dnsserver);
680 #endif
681 #if USE_UNLINKD
682
683 requirePathnameExists("unlinkd_program", Config.Program.unlinkd);
684 #endif
685 requirePathnameExists("logfile_daemon", Log::TheConfig.logfile_daemon);
686 if (Config.Program.redirect)
687 requirePathnameExists("redirect_program", Config.Program.redirect->key);
688
689 requirePathnameExists("Icon Directory", Config.icons.directory);
690
691 if (Config.errorDirectory)
692 requirePathnameExists("Error Directory", Config.errorDirectory);
693
694 #if USE_HTTP_VIOLATIONS
695
696 {
697 const refresh_t *R;
698
699 for (R = Config.Refresh; R; R = R->next) {
700 if (!R->flags.override_expire)
701 continue;
702
703 debugs(22, 1, "WARNING: use of 'override-expire' in 'refresh_pattern' violates HTTP");
704
705 break;
706 }
707
708 for (R = Config.Refresh; R; R = R->next) {
709 if (!R->flags.override_lastmod)
710 continue;
711
712 debugs(22, 1, "WARNING: use of 'override-lastmod' in 'refresh_pattern' violates HTTP");
713
714 break;
715 }
716
717 for (R = Config.Refresh; R; R = R->next) {
718 if (!R->flags.reload_into_ims)
719 continue;
720
721 debugs(22, 1, "WARNING: use of 'reload-into-ims' in 'refresh_pattern' violates HTTP");
722
723 break;
724 }
725
726 for (R = Config.Refresh; R; R = R->next) {
727 if (!R->flags.ignore_reload)
728 continue;
729
730 debugs(22, 1, "WARNING: use of 'ignore-reload' in 'refresh_pattern' violates HTTP");
731
732 break;
733 }
734
735 for (R = Config.Refresh; R; R = R->next) {
736 if (!R->flags.ignore_no_cache)
737 continue;
738
739 debugs(22, 1, "WARNING: use of 'ignore-no-cache' in 'refresh_pattern' violates HTTP");
740
741 break;
742 }
743
744 for (R = Config.Refresh; R; R = R->next) {
745 if (!R->flags.ignore_no_store)
746 continue;
747
748 debugs(22, 1, "WARNING: use of 'ignore-no-store' in 'refresh_pattern' violates HTTP");
749
750 break;
751 }
752
753 for (R = Config.Refresh; R; R = R->next) {
754 if (!R->flags.ignore_must_revalidate)
755 continue;
756 debugs(22, 1, "WARNING: use of 'ignore-must-revalidate' in 'refresh_pattern' violates HTTP");
757 break;
758 }
759
760 for (R = Config.Refresh; R; R = R->next) {
761 if (!R->flags.ignore_private)
762 continue;
763
764 debugs(22, 1, "WARNING: use of 'ignore-private' in 'refresh_pattern' violates HTTP");
765
766 break;
767 }
768
769 for (R = Config.Refresh; R; R = R->next) {
770 if (!R->flags.ignore_auth)
771 continue;
772
773 debugs(22, 1, "WARNING: use of 'ignore-auth' in 'refresh_pattern' violates HTTP");
774
775 break;
776 }
777
778 }
779 #endif
780 #if !USE_HTTP_VIOLATIONS
781 Config.onoff.via = 1;
782 #else
783
784 if (!Config.onoff.via)
785 debugs(22, 1, "WARNING: HTTP requires the use of Via");
786
787 #endif
788
789 // we enable runtime PURGE checks if there is at least one PURGE method ACL
790 // TODO: replace with a dedicated "purge" ACL option?
791 Config2.onoff.enable_purge = (ACLMethodData::ThePurgeCount > 0);
792
793 Config2.onoff.mangle_request_headers = httpReqHdrManglersConfigured();
794
795 if (geteuid() == 0) {
796 if (NULL != Config.effectiveUser) {
797
798 struct passwd *pwd = getpwnam(Config.effectiveUser);
799
800 if (NULL == pwd) {
801 /*
802 * Andres Kroonmaa <andre@online.ee>:
803 * Some getpwnam() implementations (Solaris?) require
804 * an available FD < 256 for opening a FILE* to the
805 * passwd file.
806 * DW:
807 * This should be safe at startup, but might still fail
808 * during reconfigure.
809 */
810 fatalf("getpwnam failed to find userid for effective user '%s'",
811 Config.effectiveUser);
812 return;
813 }
814
815 Config2.effectiveUserID = pwd->pw_uid;
816
817 Config2.effectiveGroupID = pwd->pw_gid;
818
819 #if HAVE_PUTENV
820
821 if (pwd->pw_dir && *pwd->pw_dir) {
822 int len;
823 char *env_str = (char *)xcalloc((len = strlen(pwd->pw_dir) + 6), 1);
824 snprintf(env_str, len, "HOME=%s", pwd->pw_dir);
825 putenv(env_str);
826 }
827
828 #endif
829
830 }
831 } else {
832 Config2.effectiveUserID = geteuid();
833 Config2.effectiveGroupID = getegid();
834 }
835
836 if (NULL != Config.effectiveGroup) {
837
838 struct group *grp = getgrnam(Config.effectiveGroup);
839
840 if (NULL == grp) {
841 fatalf("getgrnam failed to find groupid for effective group '%s'",
842 Config.effectiveGroup);
843 return;
844 }
845
846 Config2.effectiveGroupID = grp->gr_gid;
847 }
848
849 HttpRequestMethod::Configure(Config);
850 #if USE_SSL
851
852 debugs(3, 1, "Initializing https proxy context");
853
854 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, Config.ssl_client.crlfile);
855
856 {
857
858 peer *p;
859
860 for (p = Config.peers; p != NULL; p = p->next) {
861 if (p->use_ssl) {
862 debugs(3, 1, "Initializing cache_peer " << p->name << " SSL context");
863 p->sslContext = sslCreateClientContext(p->sslcert, p->sslkey, p->sslversion, p->sslcipher, p->ssloptions, p->sslflags, p->sslcafile, p->sslcapath, p->sslcrlfile);
864 }
865 }
866 }
867
868 {
869
870 http_port_list *s;
871
872 for (s = Config.Sockaddr.http; s != NULL; s = (http_port_list *) s->next) {
873 if (!s->cert && !s->key)
874 continue;
875
876 debugs(3, 1, "Initializing http_port " << s->http.s << " SSL context");
877
878 s->sslContext = sslCreateServerContext(s->cert, s->key, s->version, s->cipher, s->options, s->sslflags, s->clientca, s->cafile, s->capath, s->crlfile, s->dhfile, s->sslcontext);
879 }
880 }
881
882 {
883
884 https_port_list *s;
885
886 for (s = Config.Sockaddr.https; s != NULL; s = (https_port_list *) s->http.next) {
887 debugs(3, 1, "Initializing https_port " << s->http.s << " SSL context");
888
889 s->sslContext = sslCreateServerContext(s->cert, s->key, s->version, s->cipher, s->options, s->sslflags, s->clientca, s->cafile, s->capath, s->crlfile, s->dhfile, s->sslcontext);
890 }
891 }
892
893 #endif
894 }
895
896 /* Parse a time specification from the config file. Store the
897 * result in 'tptr', after converting it to 'units' */
898 static void
899 parseTimeLine(time_t * tptr, const char *units)
900 {
901 char *token;
902 double d;
903 time_t m;
904 time_t u;
905
906 if ((u = parseTimeUnits(units)) == 0)
907 self_destruct();
908
909 if ((token = strtok(NULL, w_space)) == NULL)
910 self_destruct();
911
912 d = xatof(token);
913
914 m = u; /* default to 'units' if none specified */
915
916 if (0 == d)
917 (void) 0;
918 else if ((token = strtok(NULL, w_space)) == NULL)
919 debugs(3, 0, "WARNING: No units on '" <<
920 config_input_line << "', assuming " <<
921 d << " " << units );
922 else if ((m = parseTimeUnits(token)) == 0)
923 self_destruct();
924
925 *tptr = static_cast<time_t> (m * d / u);
926 }
927
928 static int
929 parseTimeUnits(const char *unit)
930 {
931 if (!strncasecmp(unit, T_SECOND_STR, strlen(T_SECOND_STR)))
932 return 1;
933
934 if (!strncasecmp(unit, T_MINUTE_STR, strlen(T_MINUTE_STR)))
935 return 60;
936
937 if (!strncasecmp(unit, T_HOUR_STR, strlen(T_HOUR_STR)))
938 return 3600;
939
940 if (!strncasecmp(unit, T_DAY_STR, strlen(T_DAY_STR)))
941 return 86400;
942
943 if (!strncasecmp(unit, T_WEEK_STR, strlen(T_WEEK_STR)))
944 return 86400 * 7;
945
946 if (!strncasecmp(unit, T_FORTNIGHT_STR, strlen(T_FORTNIGHT_STR)))
947 return 86400 * 14;
948
949 if (!strncasecmp(unit, T_MONTH_STR, strlen(T_MONTH_STR)))
950 return 86400 * 30;
951
952 if (!strncasecmp(unit, T_YEAR_STR, strlen(T_YEAR_STR)))
953 return static_cast<int>(86400 * 365.2522);
954
955 if (!strncasecmp(unit, T_DECADE_STR, strlen(T_DECADE_STR)))
956 return static_cast<int>(86400 * 365.2522 * 10);
957
958 debugs(3, 1, "parseTimeUnits: unknown time unit '" << unit << "'");
959
960 return 0;
961 }
962
963 static void
964 parseBytesLine64(int64_t * bptr, const char *units)
965 {
966 char *token;
967 double d;
968 int64_t m;
969 int64_t u;
970
971 if ((u = parseBytesUnits(units)) == 0) {
972 self_destruct();
973 return;
974 }
975
976 if ((token = strtok(NULL, w_space)) == NULL) {
977 self_destruct();
978 return;
979 }
980
981 if (strcmp(token, "none") == 0 || strcmp(token, "-1") == 0) {
982 *bptr = -1;
983 return;
984 }
985
986 d = xatof(token);
987
988 m = u; /* default to 'units' if none specified */
989
990 if (0.0 == d)
991 (void) 0;
992 else if ((token = strtok(NULL, w_space)) == NULL)
993 debugs(3, 0, "WARNING: No units on '" <<
994 config_input_line << "', assuming " <<
995 d << " " << units );
996 else if ((m = parseBytesUnits(token)) == 0) {
997 self_destruct();
998 return;
999 }
1000
1001 *bptr = static_cast<int64_t>(m * d / u);
1002
1003 if (static_cast<double>(*bptr) * 2 != m * d / u * 2)
1004 self_destruct();
1005 }
1006
1007
1008 static void
1009 parseBytesLine(size_t * bptr, const char *units)
1010 {
1011 char *token;
1012 double d;
1013 int m;
1014 int u;
1015
1016 if ((u = parseBytesUnits(units)) == 0) {
1017 self_destruct();
1018 return;
1019 }
1020
1021 if ((token = strtok(NULL, w_space)) == NULL) {
1022 self_destruct();
1023 return;
1024 }
1025
1026 if (strcmp(token, "none") == 0 || strcmp(token, "-1") == 0) {
1027 *bptr = static_cast<size_t>(-1);
1028 return;
1029 }
1030
1031 d = xatof(token);
1032
1033 m = u; /* default to 'units' if none specified */
1034
1035 if (0.0 == d)
1036 (void) 0;
1037 else if ((token = strtok(NULL, w_space)) == NULL)
1038 debugs(3, 0, "WARNING: No units on '" <<
1039 config_input_line << "', assuming " <<
1040 d << " " << units );
1041 else if ((m = parseBytesUnits(token)) == 0) {
1042 self_destruct();
1043 return;
1044 }
1045
1046 *bptr = static_cast<size_t>(m * d / u);
1047
1048 if (static_cast<double>(*bptr) * 2 != m * d / u * 2)
1049 self_destruct();
1050 }
1051
1052 #if !USE_DNSSERVERS
1053 static void
1054 parseBytesLineSigned(ssize_t * bptr, const char *units)
1055 {
1056 char *token;
1057 double d;
1058 int m;
1059 int u;
1060
1061 if ((u = parseBytesUnits(units)) == 0) {
1062 self_destruct();
1063 return;
1064 }
1065
1066 if ((token = strtok(NULL, w_space)) == NULL) {
1067 self_destruct();
1068 return;
1069 }
1070
1071 if (strcmp(token, "none") == 0 || token[0] == '-' /* -N */) {
1072 *bptr = -1;
1073 return;
1074 }
1075
1076 d = xatof(token);
1077
1078 m = u; /* default to 'units' if none specified */
1079
1080 if (0.0 == d)
1081 (void) 0;
1082 else if ((token = strtok(NULL, w_space)) == NULL)
1083 debugs(3, 0, "WARNING: No units on '" <<
1084 config_input_line << "', assuming " <<
1085 d << " " << units );
1086 else if ((m = parseBytesUnits(token)) == 0) {
1087 self_destruct();
1088 return;
1089 }
1090
1091 *bptr = static_cast<size_t>(m * d / u);
1092
1093 if (static_cast<double>(*bptr) * 2 != m * d / u * 2)
1094 self_destruct();
1095 }
1096 #endif
1097
1098 static size_t
1099 parseBytesUnits(const char *unit)
1100 {
1101 if (!strncasecmp(unit, B_BYTES_STR, strlen(B_BYTES_STR)))
1102 return 1;
1103
1104 if (!strncasecmp(unit, B_KBYTES_STR, strlen(B_KBYTES_STR)))
1105 return 1 << 10;
1106
1107 if (!strncasecmp(unit, B_MBYTES_STR, strlen(B_MBYTES_STR)))
1108 return 1 << 20;
1109
1110 if (!strncasecmp(unit, B_GBYTES_STR, strlen(B_GBYTES_STR)))
1111 return 1 << 30;
1112
1113 debugs(3, DBG_CRITICAL, "WARNING: Unknown bytes unit '" << unit << "'");
1114
1115 return 0;
1116 }
1117
1118 /*****************************************************************************
1119 * Max
1120 *****************************************************************************/
1121
1122 static void
1123 dump_acl(StoreEntry * entry, const char *name, ACL * ae)
1124 {
1125 wordlist *w;
1126 wordlist *v;
1127
1128 while (ae != NULL) {
1129 debugs(3, 3, "dump_acl: " << name << " " << ae->name);
1130 storeAppendPrintf(entry, "%s %s %s ",
1131 name,
1132 ae->name,
1133 ae->typeString());
1134 v = w = ae->dump();
1135
1136 while (v != NULL) {
1137 debugs(3, 3, "dump_acl: " << name << " " << ae->name << " " << v->key);
1138 storeAppendPrintf(entry, "%s ", v->key);
1139 v = v->next;
1140 }
1141
1142 storeAppendPrintf(entry, "\n");
1143 wordlistDestroy(&w);
1144 ae = ae->next;
1145 }
1146 }
1147
1148 static void
1149 parse_acl(ACL ** ae)
1150 {
1151 ACL::ParseAclLine(LegacyParser, ae);
1152 }
1153
1154 static void
1155 free_acl(ACL ** ae)
1156 {
1157 aclDestroyAcls(ae);
1158 }
1159
1160 void
1161 dump_acl_list(StoreEntry * entry, ACLList * head)
1162 {
1163 ACLList *l;
1164
1165 for (l = head; l; l = l->next) {
1166 storeAppendPrintf(entry, " %s%s",
1167 l->op ? null_string : "!",
1168 l->_acl->name);
1169 }
1170 }
1171
1172 void
1173 dump_acl_access(StoreEntry * entry, const char *name, acl_access * head)
1174 {
1175 acl_access *l;
1176
1177 for (l = head; l; l = l->next) {
1178 storeAppendPrintf(entry, "%s %s",
1179 name,
1180 l->allow ? "Allow" : "Deny");
1181 dump_acl_list(entry, l->aclList);
1182 storeAppendPrintf(entry, "\n");
1183 }
1184 }
1185
1186 static void
1187 parse_acl_access(acl_access ** head)
1188 {
1189 aclParseAccessLine(LegacyParser, head);
1190 }
1191
1192 static void
1193 free_acl_access(acl_access ** head)
1194 {
1195 aclDestroyAccessList(head);
1196 }
1197
1198 static void
1199 dump_address(StoreEntry * entry, const char *name, Ip::Address &addr)
1200 {
1201 char buf[MAX_IPSTRLEN];
1202 storeAppendPrintf(entry, "%s %s\n", name, addr.NtoA(buf,MAX_IPSTRLEN) );
1203 }
1204
1205 static void
1206 parse_address(Ip::Address *addr)
1207 {
1208 char *token = strtok(NULL, w_space);
1209
1210 if (!token) {
1211 self_destruct();
1212 return;
1213 }
1214
1215 if (!strcmp(token,"any_addr")) {
1216 addr->SetAnyAddr();
1217 (void) 0;
1218 } else if ( (!strcmp(token,"no_addr")) || (!strcmp(token,"full_mask")) ) {
1219 addr->SetNoAddr();
1220 (void) 0;
1221 } else
1222 *addr = token;
1223 }
1224
1225 static void
1226 free_address(Ip::Address *addr)
1227 {
1228 addr->SetEmpty();
1229 }
1230
1231 CBDATA_TYPE(acl_address);
1232
1233 static void
1234 dump_acl_address(StoreEntry * entry, const char *name, acl_address * head)
1235 {
1236 char buf[MAX_IPSTRLEN];
1237 acl_address *l;
1238
1239 for (l = head; l; l = l->next) {
1240 if (!l->addr.IsAnyAddr())
1241 storeAppendPrintf(entry, "%s %s", name, l->addr.NtoA(buf,MAX_IPSTRLEN));
1242 else
1243 storeAppendPrintf(entry, "%s autoselect", name);
1244
1245 dump_acl_list(entry, l->aclList);
1246
1247 storeAppendPrintf(entry, "\n");
1248 }
1249 }
1250
1251 static void
1252 freed_acl_address(void *data)
1253 {
1254 acl_address *l = static_cast<acl_address *>(data);
1255 aclDestroyAclList(&l->aclList);
1256 }
1257
1258 static void
1259 parse_acl_address(acl_address ** head)
1260 {
1261 acl_address *l;
1262 acl_address **tail = head; /* sane name below */
1263 CBDATA_INIT_TYPE_FREECB(acl_address, freed_acl_address);
1264 l = cbdataAlloc(acl_address);
1265 parse_address(&l->addr);
1266 aclParseAclList(LegacyParser, &l->aclList);
1267
1268 while (*tail)
1269 tail = &(*tail)->next;
1270
1271 *tail = l;
1272 }
1273
1274 static void
1275 free_acl_address(acl_address ** head)
1276 {
1277 while (*head) {
1278 acl_address *l = *head;
1279 *head = l->next;
1280 cbdataFree(l);
1281 }
1282 }
1283
1284 CBDATA_TYPE(acl_tos);
1285
1286 static void
1287 dump_acl_tos(StoreEntry * entry, const char *name, acl_tos * head)
1288 {
1289 acl_tos *l;
1290
1291 for (l = head; l; l = l->next) {
1292 if (l->tos > 0)
1293 storeAppendPrintf(entry, "%s 0x%02X", name, l->tos);
1294 else
1295 storeAppendPrintf(entry, "%s none", name);
1296
1297 dump_acl_list(entry, l->aclList);
1298
1299 storeAppendPrintf(entry, "\n");
1300 }
1301 }
1302
1303 static void
1304 freed_acl_tos(void *data)
1305 {
1306 acl_tos *l = static_cast<acl_tos *>(data);
1307 aclDestroyAclList(&l->aclList);
1308 }
1309
1310 static void
1311 parse_acl_tos(acl_tos ** head)
1312 {
1313 acl_tos *l;
1314 acl_tos **tail = head; /* sane name below */
1315 unsigned int tos; /* Initially uint for strtoui. Casted to tos_t before return */
1316 char *token = strtok(NULL, w_space);
1317
1318 if (!token) {
1319 self_destruct();
1320 return;
1321 }
1322
1323 if (!xstrtoui(token, NULL, &tos, 0, std::numeric_limits<tos_t>::max())) {
1324 self_destruct();
1325 return;
1326 }
1327
1328 CBDATA_INIT_TYPE_FREECB(acl_tos, freed_acl_tos);
1329
1330 l = cbdataAlloc(acl_tos);
1331
1332 l->tos = (tos_t)tos;
1333
1334 aclParseAclList(LegacyParser, &l->aclList);
1335
1336 while (*tail)
1337 tail = &(*tail)->next;
1338
1339 *tail = l;
1340 }
1341
1342 static void
1343 free_acl_tos(acl_tos ** head)
1344 {
1345 while (*head) {
1346 acl_tos *l = *head;
1347 *head = l->next;
1348 l->next = NULL;
1349 cbdataFree(l);
1350 }
1351 }
1352
1353 #if defined(SO_MARK)
1354
1355 CBDATA_TYPE(acl_nfmark);
1356
1357 static void
1358 dump_acl_nfmark(StoreEntry * entry, const char *name, acl_nfmark * head)
1359 {
1360 acl_nfmark *l;
1361
1362 for (l = head; l; l = l->next) {
1363 if (l->nfmark > 0)
1364 storeAppendPrintf(entry, "%s 0x%02X", name, l->nfmark);
1365 else
1366 storeAppendPrintf(entry, "%s none", name);
1367
1368 dump_acl_list(entry, l->aclList);
1369
1370 storeAppendPrintf(entry, "\n");
1371 }
1372 }
1373
1374 static void
1375 freed_acl_nfmark(void *data)
1376 {
1377 acl_nfmark *l = static_cast<acl_nfmark *>(data);
1378 aclDestroyAclList(&l->aclList);
1379 }
1380
1381 static void
1382 parse_acl_nfmark(acl_nfmark ** head)
1383 {
1384 acl_nfmark *l;
1385 acl_nfmark **tail = head; /* sane name below */
1386 nfmark_t mark;
1387 char *token = strtok(NULL, w_space);
1388
1389 if (!token) {
1390 self_destruct();
1391 return;
1392 }
1393
1394 if (!xstrtoui(token, NULL, &mark, 0, std::numeric_limits<nfmark_t>::max())) {
1395 self_destruct();
1396 return;
1397 }
1398
1399 CBDATA_INIT_TYPE_FREECB(acl_nfmark, freed_acl_nfmark);
1400
1401 l = cbdataAlloc(acl_nfmark);
1402
1403 l->nfmark = mark;
1404
1405 aclParseAclList(LegacyParser, &l->aclList);
1406
1407 while (*tail)
1408 tail = &(*tail)->next;
1409
1410 *tail = l;
1411 }
1412
1413 static void
1414 free_acl_nfmark(acl_nfmark ** head)
1415 {
1416 while (*head) {
1417 acl_nfmark *l = *head;
1418 *head = l->next;
1419 l->next = NULL;
1420 cbdataFree(l);
1421 }
1422 }
1423 #endif /* SO_MARK */
1424
1425 CBDATA_TYPE(acl_size_t);
1426
1427 static void
1428 dump_acl_b_size_t(StoreEntry * entry, const char *name, acl_size_t * head)
1429 {
1430 acl_size_t *l;
1431
1432 for (l = head; l; l = l->next) {
1433 if (l->size != -1)
1434 storeAppendPrintf(entry, "%s %d %s\n", name, (int) l->size, B_BYTES_STR);
1435 else
1436 storeAppendPrintf(entry, "%s none", name);
1437
1438 dump_acl_list(entry, l->aclList);
1439
1440 storeAppendPrintf(entry, "\n");
1441 }
1442 }
1443
1444 static void
1445 freed_acl_b_size_t(void *data)
1446 {
1447 acl_size_t *l = static_cast<acl_size_t *>(data);
1448 aclDestroyAclList(&l->aclList);
1449 }
1450
1451 static void
1452 parse_acl_b_size_t(acl_size_t ** head)
1453 {
1454 acl_size_t *l;
1455 acl_size_t **tail = head; /* sane name below */
1456
1457 CBDATA_INIT_TYPE_FREECB(acl_size_t, freed_acl_b_size_t);
1458
1459 l = cbdataAlloc(acl_size_t);
1460
1461 parse_b_int64_t(&l->size);
1462
1463 aclParseAclList(LegacyParser, &l->aclList);
1464
1465 while (*tail)
1466 tail = &(*tail)->next;
1467
1468 *tail = l;
1469 }
1470
1471 static void
1472 free_acl_b_size_t(acl_size_t ** head)
1473 {
1474 while (*head) {
1475 acl_size_t *l = *head;
1476 *head = l->next;
1477 l->next = NULL;
1478 cbdataFree(l);
1479 }
1480 }
1481
1482 #if DELAY_POOLS
1483
1484 #include "DelayPools.h"
1485 #include "DelayConfig.h"
1486 /* do nothing - free_delay_pool_count is the magic free function.
1487 * this is why delay_pool_count isn't just marked TYPE: ushort
1488 */
1489 #define free_delay_pool_class(X)
1490 #define free_delay_pool_access(X)
1491 #define free_delay_pool_rates(X)
1492 #define dump_delay_pool_class(X, Y, Z)
1493 #define dump_delay_pool_access(X, Y, Z)
1494 #define dump_delay_pool_rates(X, Y, Z)
1495
1496 static void
1497 free_delay_pool_count(DelayConfig * cfg)
1498 {
1499 cfg->freePoolCount();
1500 }
1501
1502 static void
1503 dump_delay_pool_count(StoreEntry * entry, const char *name, DelayConfig &cfg)
1504 {
1505 cfg.dumpPoolCount (entry, name);
1506 }
1507
1508 static void
1509 parse_delay_pool_count(DelayConfig * cfg)
1510 {
1511 cfg->parsePoolCount();
1512 }
1513
1514 static void
1515 parse_delay_pool_class(DelayConfig * cfg)
1516 {
1517 cfg->parsePoolClass();
1518 }
1519
1520 static void
1521 parse_delay_pool_rates(DelayConfig * cfg)
1522 {
1523 cfg->parsePoolRates();
1524 }
1525
1526 static void
1527 parse_delay_pool_access(DelayConfig * cfg)
1528 {
1529 cfg->parsePoolAccess(LegacyParser);
1530 }
1531
1532 #endif
1533
1534 #if USE_HTTP_VIOLATIONS
1535 static void
1536 dump_http_header_access(StoreEntry * entry, const char *name, header_mangler header[])
1537 {
1538 int i;
1539
1540 for (i = 0; i < HDR_ENUM_END; i++) {
1541 if (header[i].access_list != NULL) {
1542 storeAppendPrintf(entry, "%s ", name);
1543 dump_acl_access(entry, httpHeaderNameById(i),
1544 header[i].access_list);
1545 }
1546 }
1547 }
1548
1549 static void
1550 parse_http_header_access(header_mangler header[])
1551 {
1552 int id, i;
1553 char *t = NULL;
1554
1555 if ((t = strtok(NULL, w_space)) == NULL) {
1556 debugs(3, 0, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
1557 debugs(3, 0, "parse_http_header_access: missing header name.");
1558 return;
1559 }
1560
1561 /* Now lookup index of header. */
1562 id = httpHeaderIdByNameDef(t, strlen(t));
1563
1564 if (strcmp(t, "All") == 0)
1565 id = HDR_ENUM_END;
1566 else if (strcmp(t, "Other") == 0)
1567 id = HDR_OTHER;
1568 else if (id == -1) {
1569 debugs(3, 0, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
1570 debugs(3, 0, "parse_http_header_access: unknown header name '" << t << "'");
1571 return;
1572 }
1573
1574 if (id != HDR_ENUM_END) {
1575 parse_acl_access(&header[id].access_list);
1576 } else {
1577 char *next_string = t + strlen(t) - 1;
1578 *next_string = 'A';
1579 *(next_string + 1) = ' ';
1580
1581 for (i = 0; i < HDR_ENUM_END; i++) {
1582 char *new_string = xstrdup(next_string);
1583 strtok(new_string, w_space);
1584 parse_acl_access(&header[i].access_list);
1585 safe_free(new_string);
1586 }
1587 }
1588 }
1589
1590 static void
1591 free_http_header_access(header_mangler header[])
1592 {
1593 int i;
1594
1595 for (i = 0; i < HDR_ENUM_END; i++) {
1596 free_acl_access(&header[i].access_list);
1597 }
1598 }
1599
1600 static void
1601 dump_http_header_replace(StoreEntry * entry, const char *name, header_mangler
1602 header[])
1603 {
1604 int i;
1605
1606 for (i = 0; i < HDR_ENUM_END; i++) {
1607 if (NULL == header[i].replacement)
1608 continue;
1609
1610 storeAppendPrintf(entry, "%s %s %s\n", name, httpHeaderNameById(i),
1611 header[i].replacement);
1612 }
1613 }
1614
1615 static void
1616 parse_http_header_replace(header_mangler header[])
1617 {
1618 int id, i;
1619 char *t = NULL;
1620
1621 if ((t = strtok(NULL, w_space)) == NULL) {
1622 debugs(3, 0, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
1623 debugs(3, 0, "parse_http_header_replace: missing header name.");
1624 return;
1625 }
1626
1627 /* Now lookup index of header. */
1628 id = httpHeaderIdByNameDef(t, strlen(t));
1629
1630 if (strcmp(t, "All") == 0)
1631 id = HDR_ENUM_END;
1632 else if (strcmp(t, "Other") == 0)
1633 id = HDR_OTHER;
1634 else if (id == -1) {
1635 debugs(3, 0, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
1636 debugs(3, 0, "parse_http_header_replace: unknown header name " << t << ".");
1637
1638 return;
1639 }
1640
1641 if (id != HDR_ENUM_END) {
1642 if (header[id].replacement != NULL)
1643 safe_free(header[id].replacement);
1644
1645 header[id].replacement = xstrdup(t + strlen(t) + 1);
1646 } else {
1647 for (i = 0; i < HDR_ENUM_END; i++) {
1648 if (header[i].replacement != NULL)
1649 safe_free(header[i].replacement);
1650
1651 header[i].replacement = xstrdup(t + strlen(t) + 1);
1652 }
1653 }
1654 }
1655
1656 static void
1657 free_http_header_replace(header_mangler header[])
1658 {
1659 int i;
1660
1661 for (i = 0; i < HDR_ENUM_END; i++) {
1662 if (header[i].replacement != NULL)
1663 safe_free(header[i].replacement);
1664 }
1665 }
1666
1667 #endif
1668
1669 static void
1670 dump_cachedir(StoreEntry * entry, const char *name, SquidConfig::_cacheSwap swap)
1671 {
1672 SwapDir *s;
1673 int i;
1674 assert (entry);
1675
1676 for (i = 0; i < swap.n_configured; i++) {
1677 s = dynamic_cast<SwapDir *>(swap.swapDirs[i].getRaw());
1678 if (!s) continue;
1679 storeAppendPrintf(entry, "%s %s %s", name, s->type(), s->path);
1680 s->dump(*entry);
1681 storeAppendPrintf(entry, "\n");
1682 }
1683 }
1684
1685 static int
1686 check_null_string(char *s)
1687 {
1688 return s == NULL;
1689 }
1690
1691 static void
1692 parse_authparam(Auth::authConfig * config)
1693 {
1694 char *type_str;
1695 char *param_str;
1696
1697 if ((type_str = strtok(NULL, w_space)) == NULL)
1698 self_destruct();
1699
1700 if ((param_str = strtok(NULL, w_space)) == NULL)
1701 self_destruct();
1702
1703 /* find a configuration for the scheme in the currently parsed configs... */
1704 AuthConfig *schemeCfg = AuthConfig::Find(type_str);
1705
1706 if (schemeCfg == NULL) {
1707 /* Create a configuration based on the scheme info */
1708 AuthScheme::Pointer theScheme = AuthScheme::Find(type_str);
1709
1710 if (theScheme == NULL) {
1711 debugs(3, DBG_CRITICAL, "Parsing Config File: Unknown authentication scheme '" << type_str << "'.");
1712 self_destruct();
1713 }
1714
1715 config->push_back(theScheme->createConfig());
1716 schemeCfg = AuthConfig::Find(type_str);
1717 if (schemeCfg == NULL) {
1718 debugs(3, DBG_CRITICAL, "Parsing Config File: Corruption configuring authentication scheme '" << type_str << "'.");
1719 self_destruct();
1720 }
1721 }
1722
1723 schemeCfg->parse(schemeCfg, config->size(), param_str);
1724 }
1725
1726 static void
1727 free_authparam(Auth::authConfig * cfg)
1728 {
1729 /* Wipe the Auth globals and Detach/Destruct component config + state. */
1730 cfg->clean();
1731
1732 /* remove our pointers to the probably-dead sub-configs */
1733 while (cfg->size()) {
1734 cfg->pop_back();
1735 }
1736
1737 /* on reconfigure initialize new auth schemes for the new config. */
1738 if (reconfiguring) {
1739 InitAuthSchemes();
1740 }
1741 }
1742
1743 static void
1744 dump_authparam(StoreEntry * entry, const char *name, authConfig cfg)
1745 {
1746 for (authConfig::iterator i = cfg.begin(); i != cfg.end(); ++i)
1747 (*i)->dump(entry, name, (*i));
1748 }
1749
1750 /* TODO: just return the object, the # is irrelevant */
1751 static int
1752 find_fstype(char *type)
1753 {
1754 for (size_t i = 0; i < StoreFileSystem::FileSystems().size(); ++i)
1755 if (strcasecmp(type, StoreFileSystem::FileSystems().items[i]->type()) == 0)
1756 return (int)i;
1757
1758 return (-1);
1759 }
1760
1761 static void
1762 parse_cachedir(SquidConfig::_cacheSwap * swap)
1763 {
1764 // The workers option must preceed cache_dir for the IamWorkerProcess check
1765 // below to work. TODO: Redo IamWorkerProcess to work w/o Config and remove
1766 if (KidIdentifier > 1 && Config.workers == 1) {
1767 debugs(3, DBG_CRITICAL,
1768 "FATAL: cache_dir found before the workers option. Reorder.");
1769 self_destruct();
1770 }
1771
1772 // Among all processes, only workers may need and can handle cache_dir.
1773 if (!IamWorkerProcess())
1774 return;
1775
1776 char *type_str;
1777 char *path_str;
1778 RefCount<SwapDir> sd;
1779 int i;
1780 int fs;
1781
1782 if ((type_str = strtok(NULL, w_space)) == NULL)
1783 self_destruct();
1784
1785 if ((path_str = strtok(NULL, w_space)) == NULL)
1786 self_destruct();
1787
1788 fs = find_fstype(type_str);
1789
1790 if (fs < 0)
1791 self_destruct();
1792
1793 /* reconfigure existing dir */
1794
1795 for (i = 0; i < swap->n_configured; i++) {
1796 assert (swap->swapDirs[i].getRaw());
1797
1798 if ((strcasecmp(path_str, dynamic_cast<SwapDir *>(swap->swapDirs[i].getRaw())->path)) == 0) {
1799 /* this is specific to on-fs Stores. The right
1800 * way to handle this is probably to have a mapping
1801 * from paths to stores, and have on-fs stores
1802 * register with that, and lookip in that in their
1803 * own setup logic. RBC 20041225. TODO.
1804 */
1805
1806 sd = dynamic_cast<SwapDir *>(swap->swapDirs[i].getRaw());
1807
1808 if (sd->type() != StoreFileSystem::FileSystems().items[fs]->type()) {
1809 debugs(3, 0, "ERROR: Can't change type of existing cache_dir " <<
1810 sd->type() << " " << sd->path << " to " << type_str << ". Restart required");
1811 return;
1812 }
1813
1814 sd->reconfigure (i, path_str);
1815
1816 update_maxobjsize();
1817
1818 return;
1819 }
1820 }
1821
1822 /* new cache_dir */
1823 if (swap->n_configured > 63) {
1824 /* 7 bits, signed */
1825 debugs(3, DBG_CRITICAL, "WARNING: There is a fixed maximum of 63 cache_dir entries Squid can handle.");
1826 debugs(3, DBG_CRITICAL, "WARNING: '" << path_str << "' is one to many.");
1827 self_destruct();
1828 return;
1829 }
1830
1831 allocate_new_swapdir(swap);
1832
1833 swap->swapDirs[swap->n_configured] = StoreFileSystem::FileSystems().items[fs]->createSwapDir();
1834
1835 sd = dynamic_cast<SwapDir *>(swap->swapDirs[swap->n_configured].getRaw());
1836
1837 /* parse the FS parameters and options */
1838 sd->parse(swap->n_configured, path_str);
1839
1840 ++swap->n_configured;
1841
1842 /* Update the max object size */
1843 update_maxobjsize();
1844 }
1845
1846 static const char *
1847 peer_type_str(const peer_t type)
1848 {
1849 const char * result;
1850
1851 switch (type) {
1852
1853 case PEER_PARENT:
1854 result = "parent";
1855 break;
1856
1857 case PEER_SIBLING:
1858 result = "sibling";
1859 break;
1860
1861 case PEER_MULTICAST:
1862 result = "multicast";
1863 break;
1864
1865 default:
1866 result = "unknown";
1867 break;
1868 }
1869
1870 return result;
1871 }
1872
1873 static void
1874 dump_peer(StoreEntry * entry, const char *name, peer * p)
1875 {
1876 domain_ping *d;
1877 domain_type *t;
1878 LOCAL_ARRAY(char, xname, 128);
1879
1880 while (p != NULL) {
1881 storeAppendPrintf(entry, "%s %s %s %d %d name=%s",
1882 name,
1883 p->host,
1884 neighborTypeStr(p),
1885 p->http_port,
1886 p->icp.port,
1887 p->name);
1888 dump_peer_options(entry, p);
1889
1890 for (d = p->peer_domain; d; d = d->next) {
1891 storeAppendPrintf(entry, "cache_peer_domain %s %s%s\n",
1892 p->host,
1893 d->do_ping ? null_string : "!",
1894 d->domain);
1895 }
1896
1897 if (p->access) {
1898 snprintf(xname, 128, "cache_peer_access %s", p->name);
1899 dump_acl_access(entry, xname, p->access);
1900 }
1901
1902 for (t = p->typelist; t; t = t->next) {
1903 storeAppendPrintf(entry, "neighbor_type_domain %s %s %s\n",
1904 p->host,
1905 peer_type_str(t->type),
1906 t->domain);
1907 }
1908
1909 p = p->next;
1910 }
1911 }
1912
1913 /**
1914 * utility function to prevent getservbyname() being called with a numeric value
1915 * on Windows at least it returns garage results.
1916 */
1917 static bool
1918 isUnsignedNumeric(const char *str, size_t len)
1919 {
1920 if (len < 1) return false;
1921
1922 for (; len >0 && *str; str++, len--) {
1923 if (! isdigit(*str))
1924 return false;
1925 }
1926 return true;
1927 }
1928
1929 /**
1930 \param proto 'tcp' or 'udp' for protocol
1931 \returns Port the named service is supposed to be listening on.
1932 */
1933 static u_short
1934 GetService(const char *proto)
1935 {
1936 struct servent *port = NULL;
1937 /** Parses a port number or service name from the squid.conf */
1938 char *token = strtok(NULL, w_space);
1939 if (token == NULL) {
1940 self_destruct();
1941 return 0; /* NEVER REACHED */
1942 }
1943 /** Returns either the service port number from /etc/services */
1944 if ( !isUnsignedNumeric(token, strlen(token)) )
1945 port = getservbyname(token, proto);
1946 if (port != NULL) {
1947 return ntohs((u_short)port->s_port);
1948 }
1949 /** Or a numeric translation of the config text. */
1950 return xatos(token);
1951 }
1952
1953 /**
1954 \returns Port the named TCP service is supposed to be listening on.
1955 \copydoc GetService(const char *proto)
1956 */
1957 inline u_short
1958 GetTcpService(void)
1959 {
1960 return GetService("tcp");
1961 }
1962
1963 /**
1964 \returns Port the named UDP service is supposed to be listening on.
1965 \copydoc GetService(const char *proto)
1966 */
1967 inline u_short
1968 GetUdpService(void)
1969 {
1970 return GetService("udp");
1971 }
1972
1973 static void
1974 parse_peer(peer ** head)
1975 {
1976 char *token = NULL;
1977 peer *p;
1978 CBDATA_INIT_TYPE_FREECB(peer, peerDestroy);
1979 p = cbdataAlloc(peer);
1980 p->http_port = CACHE_HTTP_PORT;
1981 p->icp.port = CACHE_ICP_PORT;
1982 p->weight = 1;
1983 p->basetime = 0;
1984 p->stats.logged_state = PEER_ALIVE;
1985
1986 if ((token = strtok(NULL, w_space)) == NULL)
1987 self_destruct();
1988
1989 p->host = xstrdup(token);
1990
1991 p->name = xstrdup(token);
1992
1993 if ((token = strtok(NULL, w_space)) == NULL)
1994 self_destruct();
1995
1996 p->type = parseNeighborType(token);
1997
1998 if (p->type == PEER_MULTICAST) {
1999 p->options.no_digest = 1;
2000 p->options.no_netdb_exchange = 1;
2001 }
2002
2003 p->http_port = GetTcpService();
2004
2005 if (!p->http_port)
2006 self_destruct();
2007
2008 p->icp.port = GetUdpService();
2009 p->connection_auth = 2; /* auto */
2010
2011 while ((token = strtok(NULL, w_space))) {
2012 if (!strcasecmp(token, "proxy-only")) {
2013 p->options.proxy_only = 1;
2014 } else if (!strcasecmp(token, "no-query")) {
2015 p->options.no_query = 1;
2016 } else if (!strcasecmp(token, "background-ping")) {
2017 p->options.background_ping = 1;
2018 } else if (!strcasecmp(token, "no-digest")) {
2019 p->options.no_digest = 1;
2020 } else if (!strcasecmp(token, "no-tproxy")) {
2021 p->options.no_tproxy = 1;
2022 } else if (!strcasecmp(token, "multicast-responder")) {
2023 p->options.mcast_responder = 1;
2024 #if PEER_MULTICAST_SIBLINGS
2025 } else if (!strcasecmp(token, "multicast-siblings")) {
2026 p->options.mcast_siblings = 1;
2027 #endif
2028 } else if (!strncasecmp(token, "weight=", 7)) {
2029 p->weight = xatoi(token + 7);
2030 } else if (!strncasecmp(token, "basetime=", 9)) {
2031 p->basetime = xatoi(token + 9);
2032 } else if (!strcasecmp(token, "closest-only")) {
2033 p->options.closest_only = 1;
2034 } else if (!strncasecmp(token, "ttl=", 4)) {
2035 p->mcast.ttl = xatoi(token + 4);
2036
2037 if (p->mcast.ttl < 0)
2038 p->mcast.ttl = 0;
2039
2040 if (p->mcast.ttl > 128)
2041 p->mcast.ttl = 128;
2042 } else if (!strcasecmp(token, "default")) {
2043 p->options.default_parent = 1;
2044 } else if (!strcasecmp(token, "round-robin")) {
2045 p->options.roundrobin = 1;
2046 } else if (!strcasecmp(token, "weighted-round-robin")) {
2047 p->options.weighted_roundrobin = 1;
2048 #if USE_HTCP
2049 } else if (!strcasecmp(token, "htcp")) {
2050 p->options.htcp = 1;
2051 } else if (!strncasecmp(token, "htcp=", 5) || !strncasecmp(token, "htcp-", 5)) {
2052 /* Note: The htcp- form is deprecated, replaced by htcp= */
2053 p->options.htcp = 1;
2054 char *tmp = xstrdup(token+5);
2055 char *mode, *nextmode;
2056 for (mode = nextmode = tmp; mode; mode = nextmode) {
2057 nextmode = strchr(mode, ',');
2058 if (nextmode)
2059 *nextmode++ = '\0';
2060 if (!strcasecmp(mode, "no-clr")) {
2061 if (p->options.htcp_only_clr)
2062 fatalf("parse_peer: can't set htcp-no-clr and htcp-only-clr simultaneously");
2063 p->options.htcp_no_clr = 1;
2064 } else if (!strcasecmp(mode, "no-purge-clr")) {
2065 p->options.htcp_no_purge_clr = 1;
2066 } else if (!strcasecmp(mode, "only-clr")) {
2067 if (p->options.htcp_no_clr)
2068 fatalf("parse_peer: can't set htcp no-clr and only-clr simultaneously");
2069 p->options.htcp_only_clr = 1;
2070 } else if (!strcasecmp(mode, "forward-clr")) {
2071 p->options.htcp_forward_clr = 1;
2072 } else if (!strcasecmp(mode, "oldsquid")) {
2073 p->options.htcp_oldsquid = 1;
2074 } else {
2075 fatalf("invalid HTCP mode '%s'", mode);
2076 }
2077 }
2078 safe_free(tmp);
2079 #endif
2080 } else if (!strcasecmp(token, "no-netdb-exchange")) {
2081 p->options.no_netdb_exchange = 1;
2082
2083 } else if (!strcasecmp(token, "carp")) {
2084 if (p->type != PEER_PARENT)
2085 fatalf("parse_peer: non-parent carp peer %s/%d\n", p->host, p->http_port);
2086
2087 p->options.carp = 1;
2088
2089 } else if (!strcasecmp(token, "userhash")) {
2090 if (p->type != PEER_PARENT)
2091 fatalf("parse_peer: non-parent userhash peer %s/%d\n", p->host, p->http_port);
2092
2093 p->options.userhash = 1;
2094
2095 } else if (!strcasecmp(token, "sourcehash")) {
2096 if (p->type != PEER_PARENT)
2097 fatalf("parse_peer: non-parent sourcehash peer %s/%d\n", p->host, p->http_port);
2098
2099 p->options.sourcehash = 1;
2100
2101 #if DELAY_POOLS
2102
2103 } else if (!strcasecmp(token, "no-delay")) {
2104 p->options.no_delay = 1;
2105 #endif
2106
2107 } else if (!strncasecmp(token, "login=", 6)) {
2108 p->login = xstrdup(token + 6);
2109 rfc1738_unescape(p->login);
2110 } else if (!strncasecmp(token, "connect-timeout=", 16)) {
2111 p->connect_timeout = xatoi(token + 16);
2112 } else if (!strncasecmp(token, "connect-fail-limit=", 19)) {
2113 p->connect_fail_limit = xatoi(token + 19);
2114 #if USE_CACHE_DIGESTS
2115 } else if (!strncasecmp(token, "digest-url=", 11)) {
2116 p->digest_url = xstrdup(token + 11);
2117 #endif
2118
2119 } else if (!strcasecmp(token, "allow-miss")) {
2120 p->options.allow_miss = 1;
2121 } else if (!strncasecmp(token, "max-conn=", 9)) {
2122 p->max_conn = xatoi(token + 9);
2123 } else if (!strcasecmp(token, "originserver")) {
2124 p->options.originserver = 1;
2125 } else if (!strncasecmp(token, "name=", 5)) {
2126 safe_free(p->name);
2127
2128 if (token[5])
2129 p->name = xstrdup(token + 5);
2130 } else if (!strncasecmp(token, "forceddomain=", 13)) {
2131 safe_free(p->domain);
2132
2133 if (token[13])
2134 p->domain = xstrdup(token + 13);
2135
2136 #if USE_SSL
2137
2138 } else if (strcmp(token, "ssl") == 0) {
2139 p->use_ssl = 1;
2140 } else if (strncmp(token, "sslcert=", 8) == 0) {
2141 safe_free(p->sslcert);
2142 p->sslcert = xstrdup(token + 8);
2143 } else if (strncmp(token, "sslkey=", 7) == 0) {
2144 safe_free(p->sslkey);
2145 p->sslkey = xstrdup(token + 7);
2146 } else if (strncmp(token, "sslversion=", 11) == 0) {
2147 p->sslversion = atoi(token + 11);
2148 } else if (strncmp(token, "ssloptions=", 11) == 0) {
2149 safe_free(p->ssloptions);
2150 p->ssloptions = xstrdup(token + 11);
2151 } else if (strncmp(token, "sslcipher=", 10) == 0) {
2152 safe_free(p->sslcipher);
2153 p->sslcipher = xstrdup(token + 10);
2154 } else if (strncmp(token, "sslcafile=", 10) == 0) {
2155 safe_free(p->sslcafile);
2156 p->sslcafile = xstrdup(token + 10);
2157 } else if (strncmp(token, "sslcapath=", 10) == 0) {
2158 safe_free(p->sslcapath);
2159 p->sslcapath = xstrdup(token + 10);
2160 } else if (strncmp(token, "sslcrlfile=", 11) == 0) {
2161 safe_free(p->sslcrlfile);
2162 p->sslcapath = xstrdup(token + 10);
2163 } else if (strncmp(token, "sslflags=", 9) == 0) {
2164 safe_free(p->sslflags);
2165 p->sslflags = xstrdup(token + 9);
2166 } else if (strncmp(token, "ssldomain=", 10) == 0) {
2167 safe_free(p->ssldomain);
2168 p->ssldomain = xstrdup(token + 10);
2169 #endif
2170
2171 } else if (strcmp(token, "front-end-https") == 0) {
2172 p->front_end_https = 1;
2173 } else if (strcmp(token, "front-end-https=on") == 0) {
2174 p->front_end_https = 1;
2175 } else if (strcmp(token, "front-end-https=auto") == 0) {
2176 p->front_end_https = 2;
2177 } else if (strcmp(token, "connection-auth=off") == 0) {
2178 p->connection_auth = 0;
2179 } else if (strcmp(token, "connection-auth") == 0) {
2180 p->connection_auth = 1;
2181 } else if (strcmp(token, "connection-auth=on") == 0) {
2182 p->connection_auth = 1;
2183 } else if (strcmp(token, "connection-auth=auto") == 0) {
2184 p->connection_auth = 2;
2185 } else {
2186 debugs(3, 0, "parse_peer: token='" << token << "'");
2187 self_destruct();
2188 }
2189 }
2190
2191 if (peerFindByName(p->name))
2192 fatalf("ERROR: cache_peer %s specified twice\n", p->name);
2193
2194 if (p->weight < 1)
2195 p->weight = 1;
2196
2197 if (p->connect_fail_limit < 1)
2198 p->connect_fail_limit = 10;
2199
2200 p->icp.version = ICP_VERSION_CURRENT;
2201
2202 p->test_fd = -1;
2203
2204 #if USE_CACHE_DIGESTS
2205
2206 if (!p->options.no_digest) {
2207 /* XXX This looks odd.. who has the original pointer
2208 * then?
2209 */
2210 PeerDigest *pd = peerDigestCreate(p);
2211 p->digest = cbdataReference(pd);
2212 }
2213
2214 #endif
2215
2216 p->index = ++Config.npeers;
2217
2218 while (*head != NULL)
2219 head = &(*head)->next;
2220
2221 *head = p;
2222
2223 peerClearRRStart();
2224 }
2225
2226 static void
2227 free_peer(peer ** P)
2228 {
2229 peer *p;
2230
2231 while ((p = *P) != NULL) {
2232 *P = p->next;
2233 #if USE_CACHE_DIGESTS
2234
2235 cbdataReferenceDone(p->digest);
2236 #endif
2237
2238 cbdataFree(p);
2239 }
2240
2241 Config.npeers = 0;
2242 }
2243
2244 static void
2245 dump_cachemgrpasswd(StoreEntry * entry, const char *name, cachemgr_passwd * list)
2246 {
2247 wordlist *w;
2248
2249 while (list != NULL) {
2250 if (strcmp(list->passwd, "none") && strcmp(list->passwd, "disable"))
2251 storeAppendPrintf(entry, "%s XXXXXXXXXX", name);
2252 else
2253 storeAppendPrintf(entry, "%s %s", name, list->passwd);
2254
2255 for (w = list->actions; w != NULL; w = w->next) {
2256 storeAppendPrintf(entry, " %s", w->key);
2257 }
2258
2259 storeAppendPrintf(entry, "\n");
2260 list = list->next;
2261 }
2262 }
2263
2264 static void
2265 parse_cachemgrpasswd(cachemgr_passwd ** head)
2266 {
2267 char *passwd = NULL;
2268 wordlist *actions = NULL;
2269 cachemgr_passwd *p;
2270 cachemgr_passwd **P;
2271 parse_string(&passwd);
2272 parse_wordlist(&actions);
2273 p = static_cast<cachemgr_passwd *>(xcalloc(1, sizeof(cachemgr_passwd)));
2274 p->passwd = passwd;
2275 p->actions = actions;
2276
2277 for (P = head; *P; P = &(*P)->next) {
2278 /*
2279 * See if any of the actions from this line already have a
2280 * password from previous lines. The password checking
2281 * routines in cache_manager.c take the the password from
2282 * the first cachemgr_passwd struct that contains the
2283 * requested action. Thus, we should warn users who might
2284 * think they can have two passwords for the same action.
2285 */
2286 wordlist *w;
2287 wordlist *u;
2288
2289 for (w = (*P)->actions; w; w = w->next) {
2290 for (u = actions; u; u = u->next) {
2291 if (strcmp(w->key, u->key))
2292 continue;
2293
2294 debugs(0, 0, "WARNING: action '" << u->key << "' (line " << config_lineno << ") already has a password");
2295 }
2296 }
2297 }
2298
2299 *P = p;
2300 }
2301
2302 static void
2303 free_cachemgrpasswd(cachemgr_passwd ** head)
2304 {
2305 cachemgr_passwd *p;
2306
2307 while ((p = *head) != NULL) {
2308 *head = p->next;
2309 xfree(p->passwd);
2310 wordlistDestroy(&p->actions);
2311 xfree(p);
2312 }
2313 }
2314
2315 static void
2316 dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var)
2317 {
2318 acl_name_list *a;
2319
2320 while (var != NULL) {
2321 storeAppendPrintf(entry, "%s %s", name, var->err_page_name);
2322
2323 for (a = var->acl_list; a != NULL; a = a->next)
2324 storeAppendPrintf(entry, " %s", a->name);
2325
2326 storeAppendPrintf(entry, "\n");
2327
2328 var = var->next;
2329 }
2330 }
2331
2332 static void
2333 parse_denyinfo(acl_deny_info_list ** var)
2334 {
2335 aclParseDenyInfoLine(var);
2336 }
2337
2338 void
2339 free_denyinfo(acl_deny_info_list ** list)
2340 {
2341 acl_deny_info_list *a = NULL;
2342 acl_deny_info_list *a_next = NULL;
2343 acl_name_list *l = NULL;
2344 acl_name_list *l_next = NULL;
2345
2346 for (a = *list; a; a = a_next) {
2347 for (l = a->acl_list; l; l = l_next) {
2348 l_next = l->next;
2349 memFree(l, MEM_ACL_NAME_LIST);
2350 l = NULL;
2351 }
2352
2353 a_next = a->next;
2354 memFree(a, MEM_ACL_DENY_INFO_LIST);
2355 a = NULL;
2356 }
2357
2358 *list = NULL;
2359 }
2360
2361 static void
2362 parse_peer_access(void)
2363 {
2364 char *host = NULL;
2365 peer *p;
2366
2367 if (!(host = strtok(NULL, w_space)))
2368 self_destruct();
2369
2370 if ((p = peerFindByName(host)) == NULL) {
2371 debugs(15, 0, "" << cfg_filename << ", line " << config_lineno << ": No cache_peer '" << host << "'");
2372 return;
2373 }
2374
2375 aclParseAccessLine(LegacyParser, &p->access);
2376 }
2377
2378 static void
2379 parse_hostdomain(void)
2380 {
2381 char *host = NULL;
2382 char *domain = NULL;
2383
2384 if (!(host = strtok(NULL, w_space)))
2385 self_destruct();
2386
2387 while ((domain = strtok(NULL, list_sep))) {
2388 domain_ping *l = NULL;
2389 domain_ping **L = NULL;
2390 peer *p;
2391
2392 if ((p = peerFindByName(host)) == NULL) {
2393 debugs(15, 0, "" << cfg_filename << ", line " << config_lineno << ": No cache_peer '" << host << "'");
2394 continue;
2395 }
2396
2397 l = static_cast<domain_ping *>(xcalloc(1, sizeof(domain_ping)));
2398 l->do_ping = 1;
2399
2400 if (*domain == '!') { /* check for !.edu */
2401 l->do_ping = 0;
2402 domain++;
2403 }
2404
2405 l->domain = xstrdup(domain);
2406
2407 for (L = &(p->peer_domain); *L; L = &((*L)->next));
2408 *L = l;
2409 }
2410 }
2411
2412 static void
2413 parse_hostdomaintype(void)
2414 {
2415 char *host = NULL;
2416 char *type = NULL;
2417 char *domain = NULL;
2418
2419 if (!(host = strtok(NULL, w_space)))
2420 self_destruct();
2421
2422 if (!(type = strtok(NULL, w_space)))
2423 self_destruct();
2424
2425 while ((domain = strtok(NULL, list_sep))) {
2426 domain_type *l = NULL;
2427 domain_type **L = NULL;
2428 peer *p;
2429
2430 if ((p = peerFindByName(host)) == NULL) {
2431 debugs(15, 0, "" << cfg_filename << ", line " << config_lineno << ": No cache_peer '" << host << "'");
2432 return;
2433 }
2434
2435 l = static_cast<domain_type *>(xcalloc(1, sizeof(domain_type)));
2436 l->type = parseNeighborType(type);
2437 l->domain = xstrdup(domain);
2438
2439 for (L = &(p->typelist); *L; L = &((*L)->next));
2440 *L = l;
2441 }
2442 }
2443
2444 static void
2445 dump_int(StoreEntry * entry, const char *name, int var)
2446 {
2447 storeAppendPrintf(entry, "%s %d\n", name, var);
2448 }
2449
2450 void
2451 parse_int(int *var)
2452 {
2453 int i;
2454 i = GetInteger();
2455 *var = i;
2456 }
2457
2458 static void
2459 free_int(int *var)
2460 {
2461 *var = 0;
2462 }
2463
2464 static void
2465 dump_onoff(StoreEntry * entry, const char *name, int var)
2466 {
2467 storeAppendPrintf(entry, "%s %s\n", name, var ? "on" : "off");
2468 }
2469
2470 void
2471 parse_onoff(int *var)
2472 {
2473 char *token = strtok(NULL, w_space);
2474
2475 if (token == NULL)
2476 self_destruct();
2477
2478 if (!strcasecmp(token, "on") || !strcasecmp(token, "enable"))
2479 *var = 1;
2480 else
2481 *var = 0;
2482 }
2483
2484 #define free_onoff free_int
2485
2486 static void
2487 dump_tristate(StoreEntry * entry, const char *name, int var)
2488 {
2489 const char *state;
2490
2491 if (var > 0)
2492 state = "on";
2493 else if (var < 0)
2494 state = "warn";
2495 else
2496 state = "off";
2497
2498 storeAppendPrintf(entry, "%s %s\n", name, state);
2499 }
2500
2501 static void
2502 parse_tristate(int *var)
2503 {
2504 char *token = strtok(NULL, w_space);
2505
2506 if (token == NULL)
2507 self_destruct();
2508
2509 if (!strcasecmp(token, "on") || !strcasecmp(token, "enable"))
2510 *var = 1;
2511 else if (!strcasecmp(token, "warn"))
2512 *var = -1;
2513 else
2514 *var = 0;
2515 }
2516
2517 #define free_tristate free_int
2518
2519 static void
2520 dump_refreshpattern(StoreEntry * entry, const char *name, refresh_t * head)
2521 {
2522 while (head != NULL) {
2523 storeAppendPrintf(entry, "%s%s %s %d %d%% %d",
2524 name,
2525 head->flags.icase ? " -i" : null_string,
2526 head->pattern,
2527 (int) head->min / 60,
2528 (int) (100.0 * head->pct + 0.5),
2529 (int) head->max / 60);
2530
2531 if (head->flags.refresh_ims)
2532 storeAppendPrintf(entry, " refresh-ims");
2533
2534 if (head->flags.store_stale)
2535 storeAppendPrintf(entry, " store-stale");
2536
2537 #if USE_HTTP_VIOLATIONS
2538
2539 if (head->flags.override_expire)
2540 storeAppendPrintf(entry, " override-expire");
2541
2542 if (head->flags.override_lastmod)
2543 storeAppendPrintf(entry, " override-lastmod");
2544
2545 if (head->flags.reload_into_ims)
2546 storeAppendPrintf(entry, " reload-into-ims");
2547
2548 if (head->flags.ignore_reload)
2549 storeAppendPrintf(entry, " ignore-reload");
2550
2551 if (head->flags.ignore_no_cache)
2552 storeAppendPrintf(entry, " ignore-no-cache");
2553
2554 if (head->flags.ignore_no_store)
2555 storeAppendPrintf(entry, " ignore-no-store");
2556
2557 if (head->flags.ignore_must_revalidate)
2558 storeAppendPrintf(entry, " ignore-must-revalidate");
2559
2560 if (head->flags.ignore_private)
2561 storeAppendPrintf(entry, " ignore-private");
2562
2563 if (head->flags.ignore_auth)
2564 storeAppendPrintf(entry, " ignore-auth");
2565
2566 #endif
2567
2568 storeAppendPrintf(entry, "\n");
2569
2570 head = head->next;
2571 }
2572 }
2573
2574 static void
2575 parse_refreshpattern(refresh_t ** head)
2576 {
2577 char *token;
2578 char *pattern;
2579 time_t min = 0;
2580 double pct = 0.0;
2581 time_t max = 0;
2582 int refresh_ims = 0;
2583 int store_stale = 0;
2584
2585 #if USE_HTTP_VIOLATIONS
2586
2587 int override_expire = 0;
2588 int override_lastmod = 0;
2589 int reload_into_ims = 0;
2590 int ignore_reload = 0;
2591 int ignore_no_cache = 0;
2592 int ignore_no_store = 0;
2593 int ignore_must_revalidate = 0;
2594 int ignore_private = 0;
2595 int ignore_auth = 0;
2596 #endif
2597
2598 int i;
2599 refresh_t *t;
2600 regex_t comp;
2601 int errcode;
2602 int flags = REG_EXTENDED | REG_NOSUB;
2603
2604 if ((token = strtok(NULL, w_space)) == NULL) {
2605 self_destruct();
2606 return;
2607 }
2608
2609 if (strcmp(token, "-i") == 0) {
2610 flags |= REG_ICASE;
2611 token = strtok(NULL, w_space);
2612 } else if (strcmp(token, "+i") == 0) {
2613 flags &= ~REG_ICASE;
2614 token = strtok(NULL, w_space);
2615 }
2616
2617 if (token == NULL) {
2618 self_destruct();
2619 return;
2620 }
2621
2622 pattern = xstrdup(token);
2623
2624 i = GetInteger(); /* token: min */
2625
2626 /* catch negative and insanely huge values close to 32-bit wrap */
2627 if (i < 0) {
2628 debugs(3, DBG_IMPORTANT, "WARNING: refresh_pattern minimum age negative. Cropped back to zero.");
2629 i = 0;
2630 }
2631 if (i > 60*24*365) {
2632 debugs(3, DBG_IMPORTANT, "WARNING: refresh_pattern minimum age too high. Cropped back to 1 year.");
2633 i = 60*24*365;
2634 }
2635
2636 min = (time_t) (i * 60); /* convert minutes to seconds */
2637
2638 i = GetInteger(); /* token: pct */
2639
2640 pct = (double) i / 100.0;
2641
2642 i = GetInteger(); /* token: max */
2643
2644 /* catch negative and insanely huge values close to 32-bit wrap */
2645 if (i < 0) {
2646 debugs(3, DBG_IMPORTANT, "WARNING: refresh_pattern maximum age negative. Cropped back to zero.");
2647 i = 0;
2648 }
2649 if (i > 60*24*365) {
2650 debugs(3, DBG_IMPORTANT, "WARNING: refresh_pattern maximum age too high. Cropped back to 1 year.");
2651 i = 60*24*365;
2652 }
2653
2654 max = (time_t) (i * 60); /* convert minutes to seconds */
2655
2656 /* Options */
2657 while ((token = strtok(NULL, w_space)) != NULL) {
2658 if (!strcmp(token, "refresh-ims")) {
2659 refresh_ims = 1;
2660 } else if (!strcmp(token, "store-stale")) {
2661 store_stale = 1;
2662 #if USE_HTTP_VIOLATIONS
2663
2664 } else if (!strcmp(token, "override-expire"))
2665 override_expire = 1;
2666 else if (!strcmp(token, "override-lastmod"))
2667 override_lastmod = 1;
2668 else if (!strcmp(token, "ignore-no-cache"))
2669 ignore_no_cache = 1;
2670 else if (!strcmp(token, "ignore-no-store"))
2671 ignore_no_store = 1;
2672 else if (!strcmp(token, "ignore-must-revalidate"))
2673 ignore_must_revalidate = 1;
2674 else if (!strcmp(token, "ignore-private"))
2675 ignore_private = 1;
2676 else if (!strcmp(token, "ignore-auth"))
2677 ignore_auth = 1;
2678 else if (!strcmp(token, "reload-into-ims")) {
2679 reload_into_ims = 1;
2680 refresh_nocache_hack = 1;
2681 /* tell client_side.c that this is used */
2682 } else if (!strcmp(token, "ignore-reload")) {
2683 ignore_reload = 1;
2684 refresh_nocache_hack = 1;
2685 /* tell client_side.c that this is used */
2686 #endif
2687
2688 } else
2689 debugs(22, 0, "redreshAddToList: Unknown option '" << pattern << "': " << token);
2690 }
2691
2692 if ((errcode = regcomp(&comp, pattern, flags)) != 0) {
2693 char errbuf[256];
2694 regerror(errcode, &comp, errbuf, sizeof errbuf);
2695 debugs(22, 0, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
2696 debugs(22, 0, "refreshAddToList: Invalid regular expression '" << pattern << "': " << errbuf);
2697 return;
2698 }
2699
2700 pct = pct < 0.0 ? 0.0 : pct;
2701 max = max < 0 ? 0 : max;
2702 t = static_cast<refresh_t *>(xcalloc(1, sizeof(refresh_t)));
2703 t->pattern = (char *) xstrdup(pattern);
2704 t->compiled_pattern = comp;
2705 t->min = min;
2706 t->pct = pct;
2707 t->max = max;
2708
2709 if (flags & REG_ICASE)
2710 t->flags.icase = 1;
2711
2712 if (refresh_ims)
2713 t->flags.refresh_ims = 1;
2714
2715 if (store_stale)
2716 t->flags.store_stale = 1;
2717
2718 #if USE_HTTP_VIOLATIONS
2719
2720 if (override_expire)
2721 t->flags.override_expire = 1;
2722
2723 if (override_lastmod)
2724 t->flags.override_lastmod = 1;
2725
2726 if (reload_into_ims)
2727 t->flags.reload_into_ims = 1;
2728
2729 if (ignore_reload)
2730 t->flags.ignore_reload = 1;
2731
2732 if (ignore_no_cache)
2733 t->flags.ignore_no_cache = 1;
2734
2735 if (ignore_no_store)
2736 t->flags.ignore_no_store = 1;
2737
2738 if (ignore_must_revalidate)
2739 t->flags.ignore_must_revalidate = 1;
2740
2741 if (ignore_private)
2742 t->flags.ignore_private = 1;
2743
2744 if (ignore_auth)
2745 t->flags.ignore_auth = 1;
2746
2747 #endif
2748
2749 t->next = NULL;
2750
2751 while (*head)
2752 head = &(*head)->next;
2753
2754 *head = t;
2755
2756 safe_free(pattern);
2757 }
2758
2759 static void
2760 free_refreshpattern(refresh_t ** head)
2761 {
2762 refresh_t *t;
2763
2764 while ((t = *head) != NULL) {
2765 *head = t->next;
2766 safe_free(t->pattern);
2767 regfree(&t->compiled_pattern);
2768 safe_free(t);
2769 }
2770
2771 #if USE_HTTP_VIOLATIONS
2772 refresh_nocache_hack = 0;
2773
2774 #endif
2775 }
2776
2777 static void
2778 dump_string(StoreEntry * entry, const char *name, char *var)
2779 {
2780 if (var != NULL)
2781 storeAppendPrintf(entry, "%s %s\n", name, var);
2782 }
2783
2784 static void
2785 parse_string(char **var)
2786 {
2787 char *token = strtok(NULL, w_space);
2788 safe_free(*var);
2789
2790 if (token == NULL)
2791 self_destruct();
2792
2793 *var = xstrdup(token);
2794 }
2795
2796 void
2797 ConfigParser::ParseString(char **var)
2798 {
2799 parse_string(var);
2800 }
2801
2802 void
2803 ConfigParser::ParseString(String *var)
2804 {
2805 char *token = strtok(NULL, w_space);
2806
2807 if (token == NULL)
2808 self_destruct();
2809
2810 var->reset(token);
2811 }
2812
2813 static void
2814 free_string(char **var)
2815 {
2816 safe_free(*var);
2817 }
2818
2819 void
2820 parse_eol(char *volatile *var)
2821 {
2822 unsigned char *token = (unsigned char *) strtok(NULL, null_string);
2823 safe_free(*var);
2824
2825 if (!token) {
2826 self_destruct();
2827 return;
2828 }
2829
2830 while (*token && xisspace(*token))
2831 token++;
2832
2833 if (!*token) {
2834 self_destruct();
2835 return;
2836 }
2837
2838 *var = xstrdup((char *) token);
2839 }
2840
2841 #define dump_eol dump_string
2842 #define free_eol free_string
2843
2844 static void
2845 dump_time_t(StoreEntry * entry, const char *name, time_t var)
2846 {
2847 storeAppendPrintf(entry, "%s %d seconds\n", name, (int) var);
2848 }
2849
2850 void
2851 parse_time_t(time_t * var)
2852 {
2853 parseTimeLine(var, T_SECOND_STR);
2854 }
2855
2856 static void
2857 free_time_t(time_t * var)
2858 {
2859 *var = 0;
2860 }
2861
2862 #if UNUSED_CODE
2863 static void
2864 dump_size_t(StoreEntry * entry, const char *name, size_t var)
2865 {
2866 storeAppendPrintf(entry, "%s %d\n", name, (int) var);
2867 }
2868 #endif
2869
2870 static void
2871 dump_b_size_t(StoreEntry * entry, const char *name, size_t var)
2872 {
2873 storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_BYTES_STR);
2874 }
2875
2876 #if !USE_DNSSERVERS
2877 static void
2878 dump_b_ssize_t(StoreEntry * entry, const char *name, ssize_t var)
2879 {
2880 storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_BYTES_STR);
2881 }
2882 #endif
2883
2884 #if UNUSED_CODE
2885 static void
2886 dump_kb_size_t(StoreEntry * entry, const char *name, size_t var)
2887 {
2888 storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_KBYTES_STR);
2889 }
2890 #endif
2891
2892 static void
2893 dump_b_int64_t(StoreEntry * entry, const char *name, int64_t var)
2894 {
2895 storeAppendPrintf(entry, "%s %"PRId64" %s\n", name, var, B_BYTES_STR);
2896 }
2897
2898 static void
2899 dump_kb_int64_t(StoreEntry * entry, const char *name, int64_t var)
2900 {
2901 storeAppendPrintf(entry, "%s %"PRId64" %s\n", name, var, B_KBYTES_STR);
2902 }
2903
2904 #if UNUSED_CODE
2905 static void
2906 parse_size_t(size_t * var)
2907 {
2908 int i;
2909 i = GetInteger();
2910 *var = (size_t) i;
2911 }
2912 #endif
2913
2914 static void
2915 parse_b_size_t(size_t * var)
2916 {
2917 parseBytesLine(var, B_BYTES_STR);
2918 }
2919
2920 #if !USE_DNSSERVERS
2921 static void
2922 parse_b_ssize_t(ssize_t * var)
2923 {
2924 parseBytesLineSigned(var, B_BYTES_STR);
2925 }
2926 #endif
2927
2928 #if UNUSED_CODE
2929 static void
2930 parse_kb_size_t(size_t * var)
2931 {
2932 parseBytesLine(var, B_KBYTES_STR);
2933 }
2934 #endif
2935
2936 static void
2937 parse_b_int64_t(int64_t * var)
2938 {
2939 parseBytesLine64(var, B_BYTES_STR);
2940 }
2941
2942 static void
2943 parse_kb_int64_t(int64_t * var)
2944 {
2945 parseBytesLine64(var, B_KBYTES_STR);
2946 }
2947
2948 static void
2949 free_size_t(size_t * var)
2950 {
2951 *var = 0;
2952 }
2953
2954 #if !USE_DNSSERVERS
2955 static void
2956 free_ssize_t(ssize_t * var)
2957 {
2958 *var = 0;
2959 }
2960 #endif
2961
2962 static void
2963 free_b_int64_t(int64_t * var)
2964 {
2965 *var = 0;
2966 }
2967
2968 #define free_b_size_t free_size_t
2969 #define free_b_ssize_t free_ssize_t
2970 #define free_kb_size_t free_size_t
2971 #define free_mb_size_t free_size_t
2972 #define free_gb_size_t free_size_t
2973 #define free_kb_int64_t free_b_int64_t
2974
2975 static void
2976 dump_ushort(StoreEntry * entry, const char *name, u_short var)
2977 {
2978 storeAppendPrintf(entry, "%s %d\n", name, var);
2979 }
2980
2981 static void
2982 free_ushort(u_short * u)
2983 {
2984 *u = 0;
2985 }
2986
2987 static void
2988 parse_ushort(u_short * var)
2989 {
2990 ConfigParser::ParseUShort(var);
2991 }
2992
2993 void
2994 ConfigParser::ParseUShort(u_short *var)
2995 {
2996 *var = GetShort();
2997 }
2998
2999 void
3000 ConfigParser::ParseBool(bool *var)
3001 {
3002 int i = GetInteger();
3003
3004 if (0 == i)
3005 *var = false;
3006 else if (1 == i)
3007 *var = true;
3008 else
3009 self_destruct();
3010 }
3011
3012 static void
3013 dump_wordlist(StoreEntry * entry, const char *name, wordlist * list)
3014 {
3015 while (list != NULL) {
3016 storeAppendPrintf(entry, "%s %s\n", name, list->key);
3017 list = list->next;
3018 }
3019 }
3020
3021 void
3022 ConfigParser::ParseWordList(wordlist ** list)
3023 {
3024 parse_wordlist(list);
3025 }
3026
3027 void
3028 parse_wordlist(wordlist ** list)
3029 {
3030 char *token;
3031 char *t = strtok(NULL, "");
3032
3033 while ((token = strwordtok(NULL, &t)))
3034 wordlistAdd(list, token);
3035 }
3036
3037 #if 0 /* now unused */
3038 static int
3039 check_null_wordlist(wordlist * w)
3040 {
3041 return w == NULL;
3042 }
3043 #endif
3044
3045 static int
3046 check_null_acl_access(acl_access * a)
3047 {
3048 return a == NULL;
3049 }
3050
3051 #define free_wordlist wordlistDestroy
3052
3053 #define free_uri_whitespace free_int
3054
3055 static void
3056 parse_uri_whitespace(int *var)
3057 {
3058 char *token = strtok(NULL, w_space);
3059
3060 if (token == NULL)
3061 self_destruct();
3062
3063 if (!strcasecmp(token, "strip"))
3064 *var = URI_WHITESPACE_STRIP;
3065 else if (!strcasecmp(token, "deny"))
3066 *var = URI_WHITESPACE_DENY;
3067 else if (!strcasecmp(token, "allow"))
3068 *var = URI_WHITESPACE_ALLOW;
3069 else if (!strcasecmp(token, "encode"))
3070 *var = URI_WHITESPACE_ENCODE;
3071 else if (!strcasecmp(token, "chop"))
3072 *var = URI_WHITESPACE_CHOP;
3073 else
3074 self_destruct();
3075 }
3076
3077 static void
3078 dump_uri_whitespace(StoreEntry * entry, const char *name, int var)
3079 {
3080 const char *s;
3081
3082 if (var == URI_WHITESPACE_ALLOW)
3083 s = "allow";
3084 else if (var == URI_WHITESPACE_ENCODE)
3085 s = "encode";
3086 else if (var == URI_WHITESPACE_CHOP)
3087 s = "chop";
3088 else if (var == URI_WHITESPACE_DENY)
3089 s = "deny";
3090 else
3091 s = "strip";
3092
3093 storeAppendPrintf(entry, "%s %s\n", name, s);
3094 }
3095
3096 static void
3097 free_removalpolicy(RemovalPolicySettings ** settings)
3098 {
3099 if (!*settings)
3100 return;
3101
3102 free_string(&(*settings)->type);
3103
3104 free_wordlist(&(*settings)->args);
3105
3106 delete *settings;
3107
3108 *settings = NULL;
3109 }
3110
3111 static void
3112 parse_removalpolicy(RemovalPolicySettings ** settings)
3113 {
3114 if (*settings)
3115 free_removalpolicy(settings);
3116
3117 *settings = new RemovalPolicySettings;
3118
3119 parse_string(&(*settings)->type);
3120
3121 parse_wordlist(&(*settings)->args);
3122 }
3123
3124 static void
3125 dump_removalpolicy(StoreEntry * entry, const char *name, RemovalPolicySettings * settings)
3126 {
3127 wordlist *args;
3128 storeAppendPrintf(entry, "%s %s", name, settings->type);
3129 args = settings->args;
3130
3131 while (args) {
3132 storeAppendPrintf(entry, " %s", args->key);
3133 args = args->next;
3134 }
3135
3136 storeAppendPrintf(entry, "\n");
3137 }
3138
3139 static void
3140 free_memcachemode(SquidConfig * config)
3141 {
3142 return;
3143 }
3144
3145 static void
3146 parse_memcachemode(SquidConfig * config)
3147 {
3148 char *token = strtok(NULL, w_space);
3149 if (!token)
3150 self_destruct();
3151
3152 if (strcmp(token, "always") == 0) {
3153 Config.onoff.memory_cache_first = 1;
3154 Config.onoff.memory_cache_disk = 1;
3155 } else if (strcmp(token, "disk") == 0) {
3156 Config.onoff.memory_cache_first = 0;
3157 Config.onoff.memory_cache_disk = 1;
3158 } else if (strncmp(token, "net", 3) == 0) {
3159 Config.onoff.memory_cache_first = 1;
3160 Config.onoff.memory_cache_disk = 0;
3161 } else if (strcmp(token, "never") == 0) {
3162 Config.onoff.memory_cache_first = 0;
3163 Config.onoff.memory_cache_disk = 0;
3164 } else
3165 self_destruct();
3166 }
3167
3168 static void
3169 dump_memcachemode(StoreEntry * entry, const char *name, SquidConfig &config)
3170 {
3171 storeAppendPrintf(entry, "%s ", name);
3172 if (Config.onoff.memory_cache_first && Config.onoff.memory_cache_disk)
3173 storeAppendPrintf(entry, "always");
3174 else if (!Config.onoff.memory_cache_first && Config.onoff.memory_cache_disk)
3175 storeAppendPrintf(entry, "disk");
3176 else if (Config.onoff.memory_cache_first && !Config.onoff.memory_cache_disk)
3177 storeAppendPrintf(entry, "network");
3178 else if (!Config.onoff.memory_cache_first && !Config.onoff.memory_cache_disk)
3179 storeAppendPrintf(entry, "none");
3180 storeAppendPrintf(entry, "\n");
3181 }
3182
3183 #include "cf_parser.cci"
3184
3185 peer_t
3186 parseNeighborType(const char *s)
3187 {
3188 if (!strcasecmp(s, "parent"))
3189 return PEER_PARENT;
3190
3191 if (!strcasecmp(s, "neighbor"))
3192 return PEER_SIBLING;
3193
3194 if (!strcasecmp(s, "neighbour"))
3195 return PEER_SIBLING;
3196
3197 if (!strcasecmp(s, "sibling"))
3198 return PEER_SIBLING;
3199
3200 if (!strcasecmp(s, "multicast"))
3201 return PEER_MULTICAST;
3202
3203 debugs(15, 0, "WARNING: Unknown neighbor type: " << s);
3204
3205 return PEER_SIBLING;
3206 }
3207
3208 #if USE_WCCPv2
3209 static void
3210 parse_IpAddress_list(Ip::Address_list ** head)
3211 {
3212 char *token;
3213 Ip::Address_list *s;
3214 Ip::Address ipa;
3215
3216 while ((token = strtok(NULL, w_space))) {
3217 if (GetHostWithPort(token, &ipa)) {
3218
3219 while (*head)
3220 head = &(*head)->next;
3221
3222 s = static_cast<Ip::Address_list *>(xcalloc(1, sizeof(*s)));
3223 s->s = ipa;
3224
3225 *head = s;
3226 } else
3227 self_destruct();
3228 }
3229 }
3230
3231 static void
3232 dump_IpAddress_list(StoreEntry * e, const char *n, const Ip::Address_list * s)
3233 {
3234 char ntoabuf[MAX_IPSTRLEN];
3235
3236 while (s) {
3237 storeAppendPrintf(e, "%s %s\n",
3238 n,
3239 s->s.NtoA(ntoabuf,MAX_IPSTRLEN));
3240 s = s->next;
3241 }
3242 }
3243
3244 static void
3245 free_IpAddress_list(Ip::Address_list ** head)
3246 {
3247 if (*head) delete *head;
3248 *head = NULL;
3249 }
3250
3251 #if CURRENTLY_UNUSED
3252 /* This code was previously used by http_port. Left as it really should
3253 * be used by icp_port and htcp_port
3254 */
3255 static int
3256 check_null_IpAddress_list(const Ip::Address_list * s)
3257 {
3258 return NULL == s;
3259 }
3260
3261 #endif /* CURRENTLY_UNUSED */
3262 #endif /* USE_WCCPv2 */
3263
3264 CBDATA_CLASS_INIT(http_port_list);
3265
3266 static void
3267 parse_http_port_specification(http_port_list * s, char *token)
3268 {
3269 char *host = NULL;
3270 unsigned short port = 0;
3271 char *t = NULL;
3272 char *junk = NULL;
3273
3274 s->disable_pmtu_discovery = DISABLE_PMTU_OFF;
3275 s->name = xstrdup(token);
3276 s->connection_auth_disabled = false;
3277
3278 if (*token == '[') {
3279 /* [ipv6]:port */
3280 host = token + 1;
3281 t = strchr(host, ']');
3282 if (!t) {
3283 debugs(3, 0, "http(s)_port: missing ']' on IPv6 address: " << token);
3284 self_destruct();
3285 }
3286 *t++ = '\0';
3287 if (*t != ':') {
3288 debugs(3, 0, "http(s)_port: missing Port in: " << token);
3289 self_destruct();
3290 }
3291 if (!Ip::EnableIpv6) {
3292 debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: IPv6 is not available.");
3293 self_destruct();
3294 }
3295 port = xatos(t + 1);
3296 } else if ((t = strchr(token, ':'))) {
3297 /* host:port */
3298 /* ipv4:port */
3299 host = token;
3300 *t = '\0';
3301 port = xatos(t + 1);
3302
3303 } else if ((port = strtol(token, &junk, 10)), !*junk) {
3304 /* port */
3305 debugs(3, 3, "http(s)_port: found Listen on Port: " << port);
3306 } else {
3307 debugs(3, 0, "http(s)_port: missing Port: " << token);
3308 self_destruct();
3309 }
3310
3311 if (port == 0) {
3312 debugs(3, 0, "http(s)_port: Port cannot be 0: " << token);
3313 self_destruct();
3314 }
3315
3316 if (NULL == host) {
3317 s->s.SetAnyAddr();
3318 s->s.SetPort(port);
3319 if (!Ip::EnableIpv6)
3320 s->s.SetIPv4();
3321 debugs(3, 3, "http(s)_port: found Listen on wildcard address: *:" << s->s.GetPort() );
3322 } else if ( s->s = host ) { /* check/parse numeric IPA */
3323 s->s.SetPort(port);
3324 if (!Ip::EnableIpv6)
3325 s->s.SetIPv4();
3326 debugs(3, 3, "http(s)_port: Listen on Host/IP: " << host << " --> " << s->s);
3327 } else if ( s->s.GetHostByName(host) ) { /* check/parse for FQDN */
3328 /* dont use ipcache */
3329 s->defaultsite = xstrdup(host);
3330 s->s.SetPort(port);
3331 if (!Ip::EnableIpv6)
3332 s->s.SetIPv4();
3333 debugs(3, 3, "http(s)_port: found Listen as Host " << s->defaultsite << " on IP: " << s->s);
3334 } else {
3335 debugs(3, 0, "http(s)_port: failed to resolve Host/IP: " << host);
3336 self_destruct();
3337 }
3338 }
3339
3340 static void
3341 parse_http_port_option(http_port_list * s, char *token)
3342 {
3343 /* modes first */
3344
3345 if (strcmp(token, "accel") == 0) {
3346 if (s->intercepted || s->spoof_client_ip) {
3347 debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: Accelerator mode requires its own port. It cannot be shared with other modes.");
3348 self_destruct();
3349 }
3350 s->accel = 1;
3351 } else if (strcmp(token, "transparent") == 0 || strcmp(token, "intercept") == 0) {
3352 if (s->accel || s->spoof_client_ip) {
3353 debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: Intercept mode requires its own interception port. It cannot be shared with other modes.");
3354 self_destruct();
3355 }
3356 s->intercepted = 1;
3357 Ip::Interceptor.StartInterception();
3358 /* Log information regarding the port modes under interception. */
3359 debugs(3, DBG_IMPORTANT, "Starting Authentication on port " << s->s);
3360 debugs(3, DBG_IMPORTANT, "Disabling Authentication on port " << s->s << " (interception enabled)");
3361
3362 /* INET6: until transparent REDIRECT works on IPv6 SOCKET, force wildcard to IPv4 */
3363 if (Ip::EnableIpv6)
3364 debugs(3, DBG_IMPORTANT, "Disabling IPv6 on port " << s->s << " (interception enabled)");
3365 if ( !s->s.SetIPv4() ) {
3366 debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: IPv6 addresses cannot be transparent (protocol does not provide NAT)" << s->s );
3367 self_destruct();
3368 }
3369 } else if (strcmp(token, "tproxy") == 0) {
3370 if (s->intercepted || s->accel) {
3371 debugs(3,DBG_CRITICAL, "FATAL: http(s)_port: TPROXY option requires its own interception port. It cannot be shared with other modes.");
3372 self_destruct();
3373 }
3374 s->spoof_client_ip = 1;
3375 Ip::Interceptor.StartTransparency();
3376 /* Log information regarding the port modes under transparency. */
3377 debugs(3, DBG_IMPORTANT, "Starting IP Spoofing on port " << s->s);
3378 debugs(3, DBG_IMPORTANT, "Disabling Authentication on port " << s->s << " (IP spoofing enabled)");
3379
3380 if (!Ip::Interceptor.ProbeForTproxy(s->s)) {
3381 debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: TPROXY support in the system does not work.");
3382 self_destruct();
3383 }
3384
3385 } else if (strncmp(token, "defaultsite=", 12) == 0) {
3386 if (!s->accel) {
3387 debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: defaultsite option requires Acceleration mode flag.");
3388 self_destruct();
3389 }
3390 safe_free(s->defaultsite);
3391 s->defaultsite = xstrdup(token + 12);
3392 } else if (strcmp(token, "vhost") == 0) {
3393 if (!s->accel) {
3394 debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: vhost option requires Acceleration mode flag.");
3395 self_destruct();
3396 }
3397 s->vhost = 1;
3398 } else if (strcmp(token, "vport") == 0) {
3399 if (!s->accel) {
3400 debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: vport option requires Acceleration mode flag.");
3401 self_destruct();
3402 }
3403 s->vport = -1;
3404 } else if (strncmp(token, "vport=", 6) == 0) {
3405 if (!s->accel) {
3406 debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: vport option requires Acceleration mode flag.");
3407 self_destruct();
3408 }
3409 s->vport = xatos(token + 6);
3410 } else if (strncmp(token, "protocol=", 9) == 0) {
3411 if (!s->accel) {
3412 debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: protocol option requires Acceleration mode flag.");
3413 self_destruct();
3414 }
3415 s->protocol = xstrdup(token + 9);
3416 } else if (strcmp(token, "allow-direct") == 0) {
3417 if (!s->accel) {
3418 debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: vport option requires Acceleration mode flag.");
3419 self_destruct();
3420 }
3421 s->allow_direct = 1;
3422 } else if (strcmp(token, "ignore-cc") == 0) {
3423 #if !USE_HTTP_VIOLATIONS
3424 if (!s->accel) {
3425 debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: ignore-cc option requires Scceleration mode flag.");
3426 self_destruct();
3427 }
3428 #endif
3429 s->ignore_cc = 1;
3430 } else if (strncmp(token, "name=", 5) == 0) {
3431 safe_free(s->name);
3432 s->name = xstrdup(token + 5);
3433 } else if (strcmp(token, "no-connection-auth") == 0) {
3434 s->connection_auth_disabled = true;
3435 } else if (strcmp(token, "connection-auth=off") == 0) {
3436 s->connection_auth_disabled = true;
3437 } else if (strcmp(token, "connection-auth") == 0) {
3438 s->connection_auth_disabled = false;
3439 } else if (strcmp(token, "connection-auth=on") == 0) {
3440 s->connection_auth_disabled = false;
3441 } else if (strncmp(token, "disable-pmtu-discovery=", 23) == 0) {
3442 if (!strcasecmp(token + 23, "off"))
3443 s->disable_pmtu_discovery = DISABLE_PMTU_OFF;
3444 else if (!strcasecmp(token + 23, "transparent"))
3445 s->disable_pmtu_discovery = DISABLE_PMTU_TRANSPARENT;
3446 else if (!strcasecmp(token + 23, "always"))
3447 s->disable_pmtu_discovery = DISABLE_PMTU_ALWAYS;
3448 else
3449 self_destruct();
3450 } else if (strcmp(token, "ipv4") == 0) {
3451 if ( !s->s.SetIPv4() ) {
3452 debugs(3, DBG_CRITICAL, "FATAL: http(s)_port: IPv6 addresses cannot be used as IPv4-Only. " << s->s );
3453 self_destruct();
3454 }
3455 } else if (strcmp(token, "tcpkeepalive") == 0) {
3456 s->tcp_keepalive.enabled = 1;
3457 } else if (strncmp(token, "tcpkeepalive=", 13) == 0) {
3458 char *t = token + 13;
3459 s->tcp_keepalive.enabled = 1;
3460 s->tcp_keepalive.idle = atoi(t);
3461 t = strchr(t, ',');
3462 if (t) {
3463 t++;
3464 s->tcp_keepalive.interval = atoi(t);
3465 t = strchr(t, ',');
3466 }
3467 if (t) {
3468 t++;
3469 s->tcp_keepalive.timeout = atoi(t);
3470 t = strchr(t, ',');
3471 }
3472 #if USE_SSL
3473 } else if (strcasecmp(token, "sslBump") == 0) {
3474 debugs(3, DBG_CRITICAL, "WARNING: '" << token << "' is deprecated " <<
3475 "in http_port. Use 'ssl-bump' instead.");
3476 s->sslBump = 1; // accelerated when bumped, otherwise not
3477 } else if (strcmp(token, "ssl-bump") == 0) {
3478 s->sslBump = 1; // accelerated when bumped, otherwise not
3479 } else if (strncmp(token, "cert=", 5) == 0) {
3480 safe_free(s->cert);
3481 s->cert = xstrdup(token + 5);
3482 } else if (strncmp(token, "key=", 4) == 0) {
3483 safe_free(s->key);
3484 s->key = xstrdup(token + 4);
3485 } else if (strncmp(token, "version=", 8) == 0) {
3486 s->version = xatoi(token + 8);
3487 if (s->version < 1 || s->version > 4)
3488 self_destruct();
3489 } else if (strncmp(token, "options=", 8) == 0) {
3490 safe_free(s->options);
3491 s->options = xstrdup(token + 8);
3492 } else if (strncmp(token, "cipher=", 7) == 0) {
3493 safe_free(s->cipher);
3494 s->cipher = xstrdup(token + 7);
3495 } else if (strncmp(token, "clientca=", 9) == 0) {
3496 safe_free(s->clientca);
3497 s->clientca = xstrdup(token + 9);
3498 } else if (strncmp(token, "cafile=", 7) == 0) {
3499 safe_free(s->cafile);
3500 s->cafile = xstrdup(token + 7);
3501 } else if (strncmp(token, "capath=", 7) == 0) {
3502 safe_free(s->capath);
3503 s->capath = xstrdup(token + 7);
3504 } else if (strncmp(token, "crlfile=", 8) == 0) {
3505 safe_free(s->crlfile);
3506 s->crlfile = xstrdup(token + 8);
3507 } else if (strncmp(token, "dhparams=", 9) == 0) {
3508 safe_free(s->dhfile);
3509 s->dhfile = xstrdup(token + 9);
3510 } else if (strncmp(token, "sslflags=", 9) == 0) {
3511 safe_free(s->sslflags);
3512 s->sslflags = xstrdup(token + 9);
3513 } else if (strncmp(token, "sslcontext=", 11) == 0) {
3514 safe_free(s->sslcontext);
3515 s->sslcontext = xstrdup(token + 11);
3516 #endif
3517 } else {
3518 self_destruct();
3519 }
3520 }
3521
3522 static http_port_list *
3523 create_http_port(char *portspec)
3524 {
3525 http_port_list *s = new http_port_list("http");
3526 parse_http_port_specification(s, portspec);
3527 return s;
3528 }
3529
3530 void
3531 add_http_port(char *portspec)
3532 {
3533 http_port_list *s = create_http_port(portspec);
3534 // we may need to merge better of the above returns a list with clones
3535 assert(s->next == NULL);
3536 s->next = Config.Sockaddr.http;
3537 Config.Sockaddr.http = s;
3538 }
3539
3540 http_port_list *
3541 clone_http_port_list(http_port_list *a)
3542 {
3543 http_port_list *b = new http_port_list(a->protocol);
3544
3545 b->s = a->s;
3546 if (a->name)
3547 b->name = xstrdup(a->name);
3548 if (a->defaultsite)
3549 b->defaultsite = xstrdup(a->defaultsite);
3550
3551 b->intercepted = a->intercepted;
3552 b->spoof_client_ip = a->spoof_client_ip;
3553 b->accel = a->accel;
3554 b->allow_direct = a->allow_direct;
3555 b->vhost = a->vhost;
3556 b->sslBump = a->sslBump;
3557 b->vport = a->vport;
3558 b->connection_auth_disabled = a->connection_auth_disabled;
3559 b->disable_pmtu_discovery = a->disable_pmtu_discovery;
3560
3561 memcpy( &(b->tcp_keepalive), &(a->tcp_keepalive), sizeof(a->tcp_keepalive));
3562
3563 #if 0
3564 // AYJ: 2009-07-18: for now SSL does not clone. Configure separate ports with IPs and SSL settings
3565
3566 #if USE_SSL
3567 // XXX: temporary hack to ease move of SSL options to http_port
3568 http_port_list &http;
3569
3570 char *cert;
3571 char *key;
3572 int version;
3573 char *cipher;
3574 char *options;
3575 char *clientca;
3576 char *cafile;
3577 char *capath;
3578 char *crlfile;
3579 char *dhfile;
3580 char *sslflags;
3581 char *sslcontext;
3582 SSL_CTX *sslContext;
3583 #endif
3584
3585 #endif /*0*/
3586
3587 return b;
3588 }
3589
3590 static void
3591 parse_http_port_list(http_port_list ** head)
3592 {
3593 char *token = strtok(NULL, w_space);
3594
3595 if (!token) {
3596 self_destruct();
3597 return;
3598 }
3599
3600 http_port_list *s = create_http_port(token);
3601
3602 /* parse options ... */
3603 while ((token = strtok(NULL, w_space))) {
3604 parse_http_port_option(s, token);
3605 }
3606
3607 if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && s->s.IsAnyAddr()) {
3608 // clone the port options from *s to *(s->next)
3609 s->next = clone_http_port_list(s);
3610 s->next->s.SetIPv4();
3611 debugs(3, 3, "http(s)_port: clone wildcard address for split-stack: " << s->s << " and " << s->next->s);
3612 }
3613
3614 while (*head)
3615 head = &(*head)->next;
3616
3617 *head = s;
3618 }
3619
3620 static void
3621 dump_generic_http_port(StoreEntry * e, const char *n, const http_port_list * s)
3622 {
3623 char buf[MAX_IPSTRLEN];
3624
3625 storeAppendPrintf(e, "%s %s",
3626 n,
3627 s->s.ToURL(buf,MAX_IPSTRLEN));
3628
3629 if (s->intercepted)
3630 storeAppendPrintf(e, " intercept");
3631
3632 if (s->spoof_client_ip)
3633 storeAppendPrintf(e, " tproxy");
3634
3635 if (s->accel)
3636 storeAppendPrintf(e, " accel");
3637
3638 if (s->vhost)
3639 storeAppendPrintf(e, " vhost");
3640
3641 if (s->vport)
3642 storeAppendPrintf(e, " vport");
3643
3644 if (s->defaultsite)
3645 storeAppendPrintf(e, " defaultsite=%s", s->defaultsite);
3646
3647 if (s->connection_auth_disabled)
3648 storeAppendPrintf(e, " connection-auth=off");
3649 else
3650 storeAppendPrintf(e, " connection-auth=on");
3651
3652 if (s->disable_pmtu_discovery != DISABLE_PMTU_OFF) {
3653 const char *pmtu;
3654
3655 if (s->disable_pmtu_discovery == DISABLE_PMTU_ALWAYS)
3656 pmtu = "always";
3657 else
3658 pmtu = "transparent";
3659
3660 storeAppendPrintf(e, " disable-pmtu-discovery=%s", pmtu);
3661 }
3662
3663 if (s->tcp_keepalive.enabled) {
3664 if (s->tcp_keepalive.idle || s->tcp_keepalive.interval || s->tcp_keepalive.timeout) {
3665 storeAppendPrintf(e, " tcpkeepalive=%d,%d,%d", s->tcp_keepalive.idle, s->tcp_keepalive.interval, s->tcp_keepalive.timeout);
3666 } else {
3667 storeAppendPrintf(e, " tcpkeepalive");
3668 }
3669 }
3670
3671 #if USE_SSL
3672 if (s->sslBump)
3673 storeAppendPrintf(e, " sslBump");
3674
3675 if (s->cert)
3676 storeAppendPrintf(e, " cert=%s", s->cert);
3677
3678 if (s->key)
3679 storeAppendPrintf(e, " key=%s", s->key);
3680
3681 if (s->version)
3682 storeAppendPrintf(e, " version=%d", s->version);
3683
3684 if (s->options)
3685 storeAppendPrintf(e, " options=%s", s->options);
3686
3687 if (s->cipher)
3688 storeAppendPrintf(e, " cipher=%s", s->cipher);
3689
3690 if (s->cafile)
3691 storeAppendPrintf(e, " cafile=%s", s->cafile);
3692
3693 if (s->capath)
3694 storeAppendPrintf(e, " capath=%s", s->capath);
3695
3696 if (s->crlfile)
3697 storeAppendPrintf(e, " crlfile=%s", s->crlfile);
3698
3699 if (s->dhfile)
3700 storeAppendPrintf(e, " dhparams=%s", s->dhfile);
3701
3702 if (s->sslflags)
3703 storeAppendPrintf(e, " sslflags=%s", s->sslflags);
3704
3705 if (s->sslcontext)
3706 storeAppendPrintf(e, " sslcontext=%s", s->sslcontext);
3707 #endif
3708 }
3709
3710 static void
3711 dump_http_port_list(StoreEntry * e, const char *n, const http_port_list * s)
3712 {
3713 while (s) {
3714 dump_generic_http_port(e, n, s);
3715 storeAppendPrintf(e, "\n");
3716 s = s->next;
3717 }
3718 }
3719
3720 static void
3721 free_http_port_list(http_port_list ** head)
3722 {
3723 http_port_list *s;
3724
3725 while ((s = *head) != NULL) {
3726 *head = s->next;
3727 delete s;
3728 }
3729 }
3730
3731 #if USE_SSL
3732
3733 // TODO: merge better with parse_http_port_list
3734 static void
3735 parse_https_port_list(https_port_list ** head)
3736 {
3737 char *token;
3738 https_port_list *s;
3739
3740 token = strtok(NULL, w_space);
3741
3742 if (!token)
3743 self_destruct();
3744
3745 s = new https_port_list;
3746 parse_http_port_specification(&s->http, token);
3747
3748 /* parse options ... */
3749 while ((token = strtok(NULL, w_space))) {
3750 parse_http_port_option(s, token);
3751 }
3752
3753 while (*head) {
3754 http_port_list ** headTmp = &(*head)->http.next;
3755 head = (https_port_list **)headTmp;
3756 }
3757
3758 *head = s;
3759 }
3760
3761 static void
3762 dump_https_port_list(StoreEntry * e, const char *n, const https_port_list * s)
3763 {
3764 dump_http_port_list(e, n, s);
3765 }
3766
3767 static void
3768 free_https_port_list(https_port_list ** head)
3769 {
3770 free_http_port_list((http_port_list**)head);
3771 }
3772
3773 #if 0
3774 static int
3775 check_null_https_port_list(const https_port_list * s)
3776 {
3777 return NULL == s;
3778 }
3779
3780 #endif
3781
3782 #endif /* USE_SSL */
3783
3784 void
3785 configFreeMemory(void)
3786 {
3787 free_all();
3788 }
3789
3790 void
3791 requirePathnameExists(const char *name, const char *path)
3792 {
3793
3794 struct stat sb;
3795 char pathbuf[BUFSIZ];
3796 assert(path != NULL);
3797
3798 if (Config.chroot_dir && (geteuid() == 0)) {
3799 snprintf(pathbuf, BUFSIZ, "%s/%s", Config.chroot_dir, path);
3800 path = pathbuf;
3801 }
3802
3803 if (stat(path, &sb) < 0) {
3804 if (opt_send_signal == -1 || opt_send_signal == SIGHUP)
3805 fatalf("%s %s: %s", name, path, xstrerror());
3806 else
3807 fprintf(stderr, "WARNING: %s %s: %s\n", name, path, xstrerror());
3808 }
3809 }
3810
3811 char *
3812 strtokFile(void)
3813 {
3814 return ConfigParser::strtokFile();
3815 }
3816
3817 #include "AccessLogEntry.h"
3818 /* TODO: split out parsing somehow ...*/
3819 static void
3820 parse_logformat(logformat ** logformat_definitions)
3821 {
3822 logformat *nlf;
3823 char *name, *def;
3824
3825 if ((name = strtok(NULL, w_space)) == NULL)
3826 self_destruct();
3827
3828 if ((def = strtok(NULL, "\r\n")) == NULL) {
3829 self_destruct();
3830 return;
3831 }
3832
3833 debugs(3, 2, "Logformat for '" << name << "' is '" << def << "'");
3834
3835 nlf = (logformat *)xcalloc(1, sizeof(logformat));
3836
3837 nlf->name = xstrdup(name);
3838
3839 if (!accessLogParseLogFormat(&nlf->format, def)) {
3840 self_destruct();
3841 return;
3842 }
3843
3844 nlf->next = *logformat_definitions;
3845
3846 *logformat_definitions = nlf;
3847 }
3848
3849 static void
3850 parse_access_log(customlog ** logs)
3851 {
3852 const char *filename, *logdef_name;
3853 customlog *cl;
3854 logformat *lf;
3855
3856 cl = (customlog *)xcalloc(1, sizeof(*cl));
3857
3858 if ((filename = strtok(NULL, w_space)) == NULL) {
3859 self_destruct();
3860 return;
3861 }
3862
3863 if (strcmp(filename, "none") == 0) {
3864 cl->type = CLF_NONE;
3865 goto done;
3866 }
3867
3868 if ((logdef_name = strtok(NULL, w_space)) == NULL)
3869 logdef_name = "auto";
3870
3871 debugs(3, 9, "Log definition name '" << logdef_name << "' file '" << filename << "'");
3872
3873 cl->filename = xstrdup(filename);
3874
3875 /* look for the definition pointer corresponding to this name */
3876 lf = Config.Log.logformats;
3877
3878 while (lf != NULL) {
3879 debugs(3, 9, "Comparing against '" << lf->name << "'");
3880
3881 if (strcmp(lf->name, logdef_name) == 0)
3882 break;
3883
3884 lf = lf->next;
3885 }
3886
3887 if (lf != NULL) {
3888 cl->type = CLF_CUSTOM;
3889 cl->logFormat = lf;
3890 } else if (strcmp(logdef_name, "auto") == 0) {
3891 cl->type = CLF_AUTO;
3892 } else if (strcmp(logdef_name, "squid") == 0) {
3893 cl->type = CLF_SQUID;
3894 } else if (strcmp(logdef_name, "common") == 0) {
3895 cl->type = CLF_COMMON;
3896 #if ICAP_CLIENT
3897 } else if (strcmp(logdef_name, "icap_squid") == 0) {
3898 cl->type = CLF_ICAP_SQUID;
3899 #endif
3900 } else {
3901 debugs(3, 0, "Log format '" << logdef_name << "' is not defined");
3902 self_destruct();
3903 return;
3904 }
3905
3906 done:
3907 aclParseAclList(LegacyParser, &cl->aclList);
3908
3909 while (*logs)
3910 logs = &(*logs)->next;
3911
3912 *logs = cl;
3913 }
3914
3915 static int
3916 check_null_access_log(customlog *customlog_definitions)
3917 {
3918 return customlog_definitions == NULL;
3919 }
3920
3921 static void
3922 dump_logformat(StoreEntry * entry, const char *name, logformat * definitions)
3923 {
3924 accessLogDumpLogFormat(entry, name, definitions);
3925 }
3926
3927 static void
3928 dump_access_log(StoreEntry * entry, const char *name, customlog * logs)
3929 {
3930 customlog *log;
3931
3932 for (log = logs; log; log = log->next) {
3933 storeAppendPrintf(entry, "%s ", name);
3934
3935 switch (log->type) {
3936
3937 case CLF_CUSTOM:
3938 storeAppendPrintf(entry, "%s %s", log->filename, log->logFormat->name);
3939 break;
3940
3941 case CLF_NONE:
3942 storeAppendPrintf(entry, "none");
3943 break;
3944
3945 case CLF_SQUID:
3946 storeAppendPrintf(entry, "%s squid", log->filename);
3947 break;
3948
3949 case CLF_COMMON:
3950 storeAppendPrintf(entry, "%s squid", log->filename);
3951 break;
3952 #if ICAP_CLIENT
3953 case CLF_ICAP_SQUID:
3954 storeAppendPrintf(entry, "%s icap_squid", log->filename);
3955 break;
3956 #endif
3957 case CLF_AUTO:
3958
3959 if (log->aclList)
3960 storeAppendPrintf(entry, "%s auto", log->filename);
3961 else
3962 storeAppendPrintf(entry, "%s", log->filename);
3963
3964 break;
3965
3966 case CLF_UNKNOWN:
3967 break;
3968 }
3969
3970 if (log->aclList)
3971 dump_acl_list(entry, log->aclList);
3972
3973 storeAppendPrintf(entry, "\n");
3974 }
3975 }
3976
3977 static void
3978 free_logformat(logformat ** definitions)
3979 {
3980 while (*definitions) {
3981 logformat *format = *definitions;
3982 *definitions = format->next;
3983 safe_free(format->name);
3984 accessLogFreeLogFormat(&format->format);
3985 xfree(format);
3986 }
3987 }
3988
3989 static void
3990 free_access_log(customlog ** definitions)
3991 {
3992 while (*definitions) {
3993 customlog *log = *definitions;
3994 *definitions = log->next;
3995
3996 log->logFormat = NULL;
3997 log->type = CLF_UNKNOWN;
3998
3999 if (log->aclList)
4000 aclDestroyAclList(&log->aclList);
4001
4002 safe_free(log->filename);
4003
4004 xfree(log);
4005 }
4006 }
4007
4008 /// parses list of integers form name=N1,N2,N3,...
4009 static bool
4010 parseNamedIntList(const char *data, const String &name, Vector<int> &list)
4011 {
4012 if (data && (strncmp(data, name.rawBuf(), name.size()) == 0)) {
4013 data += name.size();
4014 if (*data == '=') {
4015 while (true) {
4016 ++data;
4017 int value = 0;
4018 if (!StringToInt(data, value, &data, 10))
4019 break;
4020 list.push_back(value);
4021 if (*data == '\0' || *data != ',')
4022 break;
4023 }
4024 }
4025 }
4026 return data && *data == '\0';
4027 }
4028
4029 static void
4030 parse_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap)
4031 {
4032 #if !HAVE_CPU_AFFINITY
4033 debugs(3, DBG_CRITICAL, "FATAL: Squid built with no CPU affinity " <<
4034 "support, do not set 'cpu_affinity_map'");
4035 self_destruct();
4036 #endif /* HAVE_CPU_AFFINITY */
4037
4038 if (!*cpuAffinityMap)
4039 *cpuAffinityMap = new CpuAffinityMap;
4040
4041 const char *const pToken = strtok(NULL, w_space);
4042 const char *const cToken = strtok(NULL, w_space);
4043 Vector<int> processes, cores;
4044 if (!parseNamedIntList(pToken, "process_numbers", processes)) {
4045 debugs(3, DBG_CRITICAL, "FATAL: bad 'process_numbers' parameter " <<
4046 "in 'cpu_affinity_map'");
4047 self_destruct();
4048 } else if (!parseNamedIntList(cToken, "cores", cores)) {
4049 debugs(3, DBG_CRITICAL, "FATAL: bad 'cores' parameter in " <<
4050 "'cpu_affinity_map'");
4051 self_destruct();
4052 } else if (!(*cpuAffinityMap)->add(processes, cores)) {
4053 debugs(3, DBG_CRITICAL, "FATAL: bad 'cpu_affinity_map'; " <<
4054 "process_numbers and cores lists differ in length or " <<
4055 "contain numbers <= 0");
4056 self_destruct();
4057 }
4058 }
4059
4060 static void
4061 dump_CpuAffinityMap(StoreEntry *const entry, const char *const name, const CpuAffinityMap *const cpuAffinityMap)
4062 {
4063 if (cpuAffinityMap) {
4064 storeAppendPrintf(entry, "%s process_numbers=", name);
4065 for (size_t i = 0; i < cpuAffinityMap->processes().size(); ++i) {
4066 storeAppendPrintf(entry, "%s%i", (i ? "," : ""),
4067 cpuAffinityMap->processes()[i]);
4068 }
4069 storeAppendPrintf(entry, " cores=");
4070 for (size_t i = 0; i < cpuAffinityMap->processes().size(); ++i) {
4071 storeAppendPrintf(entry, "%s%i", (i ? "," : ""),
4072 cpuAffinityMap->cores()[i]);
4073 }
4074 storeAppendPrintf(entry, "\n");
4075 }
4076 }
4077
4078 static void
4079 free_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap)
4080 {
4081 delete *cpuAffinityMap;
4082 *cpuAffinityMap = NULL;
4083 }
4084
4085 #if USE_ADAPTATION
4086
4087 static void
4088 parse_adaptation_service_set_type()
4089 {
4090 Adaptation::Config::ParseServiceSet();
4091 }
4092
4093 static void
4094 parse_adaptation_service_chain_type()
4095 {
4096 Adaptation::Config::ParseServiceChain();
4097 }
4098
4099 static void
4100 parse_adaptation_access_type()
4101 {
4102 Adaptation::Config::ParseAccess(LegacyParser);
4103 }
4104
4105 #endif /* USE_ADAPTATION */
4106
4107
4108 #if ICAP_CLIENT
4109
4110 static void
4111 parse_icap_service_type(Adaptation::Icap::Config * cfg)
4112 {
4113 cfg->parseService();
4114 }
4115
4116 static void
4117 free_icap_service_type(Adaptation::Icap::Config * cfg)
4118 {
4119 cfg->freeService();
4120 }
4121
4122 static void
4123 dump_icap_service_type(StoreEntry * entry, const char *name, const Adaptation::Icap::Config &cfg)
4124 {
4125 cfg.dumpService(entry, name);
4126 }
4127
4128 static void
4129 parse_icap_class_type()
4130 {
4131 debugs(93, 0, "WARNING: 'icap_class' is depricated. " <<
4132 "Use 'adaptation_service_set' instead");
4133 Adaptation::Config::ParseServiceSet();
4134 }
4135
4136 static void
4137 parse_icap_access_type()
4138 {
4139 debugs(93, 0, "WARNING: 'icap_access' is depricated. " <<
4140 "Use 'adaptation_access' instead");
4141 Adaptation::Config::ParseAccess(LegacyParser);
4142 }
4143
4144 #endif
4145
4146
4147 #if USE_ECAP
4148
4149 static void
4150 parse_ecap_service_type(Adaptation::Ecap::Config * cfg)
4151 {
4152 cfg->parseService();
4153 }
4154
4155 static void
4156 free_ecap_service_type(Adaptation::Ecap::Config * cfg)
4157 {
4158 cfg->freeService();
4159 }
4160
4161 static void
4162 dump_ecap_service_type(StoreEntry * entry, const char *name, const Adaptation::Ecap::Config &cfg)
4163 {
4164 cfg.dumpService(entry, name);
4165 }
4166
4167 #endif /* USE_ECAP */
4168
4169 #if ICAP_CLIENT
4170 static void parse_icap_service_failure_limit(Adaptation::Icap::Config *cfg)
4171 {
4172 char *token;
4173 time_t d;
4174 time_t m;
4175 cfg->service_failure_limit = GetInteger();
4176
4177 if ((token = strtok(NULL, w_space)) == NULL)
4178 return;
4179
4180 if (strcmp(token,"in") != 0) {
4181 debugs(3, 0, "expecting 'in' on'" << config_input_line << "'");
4182 self_destruct();
4183 }
4184
4185 if ((token = strtok(NULL, w_space)) == NULL) {
4186 self_destruct();
4187 }
4188
4189 d = static_cast<time_t> (xatoi(token));
4190
4191 m = static_cast<time_t> (1);
4192
4193 if (0 == d)
4194 (void) 0;
4195 else if ((token = strtok(NULL, w_space)) == NULL) {
4196 debugs(3, 0, "No time-units on '" << config_input_line << "'");
4197 self_destruct();
4198 } else if ((m = parseTimeUnits(token)) == 0)
4199 self_destruct();
4200
4201 cfg->oldest_service_failure = (m * d);
4202 }
4203
4204 static void dump_icap_service_failure_limit(StoreEntry *entry, const char *name, const Adaptation::Icap::Config &cfg)
4205 {
4206 storeAppendPrintf(entry, "%s %d", name, cfg.service_failure_limit);
4207 if (cfg.oldest_service_failure > 0) {
4208 storeAppendPrintf(entry, " in %d seconds", (int)cfg.oldest_service_failure);
4209 }
4210 storeAppendPrintf(entry, "\n");
4211 }
4212
4213 static void free_icap_service_failure_limit(Adaptation::Icap::Config *cfg)
4214 {
4215 cfg->oldest_service_failure = 0;
4216 cfg->service_failure_limit = 0;
4217 }
4218
4219 #endif