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