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