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