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