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