cache_cf.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2020 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /* DEBUG: section 03 Configuration File Parsing */
10 
11 #include "squid.h"
12 #include "acl/Acl.h"
13 #include "acl/AclDenyInfoList.h"
14 #include "acl/AclSizeLimit.h"
15 #include "acl/Address.h"
16 #include "acl/Gadgets.h"
17 #include "acl/MethodData.h"
18 #include "acl/Tree.h"
19 #include "anyp/PortCfg.h"
20 #include "anyp/UriScheme.h"
21 #include "auth/Config.h"
22 #include "auth/Scheme.h"
23 #include "AuthReg.h"
24 #include "base/RunnersRegistry.h"
25 #include "cache_cf.h"
26 #include "CachePeer.h"
27 #include "ConfigParser.h"
28 #include "CpuAffinityMap.h"
29 #include "DiskIO/DiskIOModule.h"
30 #include "eui/Config.h"
31 #include "ExternalACL.h"
32 #include "format/Format.h"
33 #include "ftp/Elements.h"
34 #include "globals.h"
35 #include "HttpHeaderTools.h"
37 #include "icmp/IcmpConfig.h"
38 #include "ident/Config.h"
39 #include "ip/Intercept.h"
40 #include "ip/NfMarkConfig.h"
41 #include "ip/QosConfig.h"
42 #include "ip/tools.h"
43 #include "ipc/Kids.h"
44 #include "log/Config.h"
45 #include "log/CustomLog.h"
46 #include "MemBuf.h"
47 #include "MessageDelayPools.h"
48 #include "mgr/ActionPasswordList.h"
49 #include "mgr/Registration.h"
50 #include "neighbors.h"
51 #include "NeighborTypeDomainList.h"
52 #include "Parsing.h"
53 #include "pconn.h"
54 #include "PeerDigest.h"
55 #include "PeerPoolMgr.h"
56 #include "redirect.h"
57 #include "RefreshPattern.h"
58 #include "rfc1738.h"
59 #include "sbuf/List.h"
60 #include "sbuf/Stream.h"
61 #include "SquidConfig.h"
62 #include "SquidString.h"
63 #include "ssl/ProxyCerts.h"
64 #include "Store.h"
65 #include "store/Disks.h"
66 #include "tools.h"
67 #include "util.h"
68 #include "wordlist.h"
69 /* wccp2 has its own conditional definitions */
70 #include "wccp2.h"
71 #if USE_ADAPTATION
72 #include "adaptation/Config.h"
73 #endif
74 #if ICAP_CLIENT
75 #include "adaptation/icap/Config.h"
76 #endif
77 #if USE_ECAP
78 #include "adaptation/ecap/Config.h"
79 #endif
80 #if USE_OPENSSL
81 #include "ssl/Config.h"
82 #include "ssl/support.h"
83 #endif
84 #if USE_SQUID_ESI
85 #include "esi/Parser.h"
86 #endif
87 #if SQUID_SNMP
88 #include "snmp.h"
89 #endif
90 
91 #if HAVE_GLOB_H
92 #include <glob.h>
93 #endif
94 #include <chrono>
95 #include <limits>
96 #include <list>
97 #if HAVE_PWD_H
98 #include <pwd.h>
99 #endif
100 #if HAVE_GRP_H
101 #include <grp.h>
102 #endif
103 #if HAVE_SYS_SOCKET_H
104 #include <sys/socket.h>
105 #endif
106 #if HAVE_SYS_STAT_H
107 #include <sys/stat.h>
108 #endif
109 
110 #if USE_OPENSSL
111 #include "ssl/gadgets.h"
112 #endif
113 
114 #if USE_ADAPTATION
117 static void parse_adaptation_access_type();
118 #endif
119 
120 #if ICAP_CLIENT
122 static void dump_icap_service_type(StoreEntry *, const char *, const Adaptation::Icap::Config &);
124 static void parse_icap_class_type();
125 static void parse_icap_access_type();
126 
128 static void dump_icap_service_failure_limit(StoreEntry *, const char *, const Adaptation::Icap::Config &);
130 #endif
131 
132 #if USE_ECAP
134 static void dump_ecap_service_type(StoreEntry *, const char *, const Adaptation::Ecap::Config &);
136 #endif
137 
138 static peer_t parseNeighborType(const char *s);
139 
140 static const char *const T_NANOSECOND_STR = "nanosecond";
141 static const char *const T_MICROSECOND_STR = "microsecond";
142 static const char *const T_MILLISECOND_STR = "millisecond";
143 static const char *const T_SECOND_STR = "second";
144 static const char *const T_MINUTE_STR = "minute";
145 static const char *const T_HOUR_STR = "hour";
146 static const char *const T_DAY_STR = "day";
147 static const char *const T_WEEK_STR = "week";
148 static const char *const T_FORTNIGHT_STR = "fortnight";
149 static const char *const T_MONTH_STR = "month";
150 static const char *const T_YEAR_STR = "year";
151 static const char *const T_DECADE_STR = "decade";
152 
153 static const char *const B_BYTES_STR = "bytes";
154 static const char *const B_KBYTES_STR = "KB";
155 static const char *const B_MBYTES_STR = "MB";
156 static const char *const B_GBYTES_STR = "GB";
157 
158 static const char *const list_sep = ", \t\n\r";
159 
160 // std::chrono::years requires C++20. Do our own rough calculation for now.
161 static const double HoursPerYear = 24*365.2522;
162 
163 static void parse_access_log(CustomLog ** customlog_definitions);
164 static int check_null_access_log(CustomLog *customlog_definitions);
165 static void dump_access_log(StoreEntry * entry, const char *name, CustomLog * definitions);
166 static void free_access_log(CustomLog ** definitions);
167 static bool setLogformat(CustomLog *cl, const char *name, const bool dieWhenMissing);
168 
169 static void configDoConfigure(void);
170 static void parse_refreshpattern(RefreshPattern **);
171 static void parse_u_short(unsigned short * var);
172 static void parse_string(char **);
173 static void default_all(void);
174 static void defaults_if_none(void);
175 static void defaults_postscriptum(void);
176 static int parse_line(char *);
177 static void parse_obsolete(const char *);
178 static void parseBytesLine(size_t * bptr, const char *units);
179 static void parseBytesLineSigned(ssize_t * bptr, const char *units);
180 static size_t parseBytesUnits(const char *unit);
181 static void free_all(void);
182 void requirePathnameExists(const char *name, const char *path);
184 #if USE_HTTP_VIOLATIONS
185 static void free_HeaderManglers(HeaderManglers **pm);
186 static void dump_http_header_access(StoreEntry * entry, const char *name, const HeaderManglers *manglers);
187 static void parse_http_header_access(HeaderManglers **manglers);
188 #define free_http_header_access free_HeaderManglers
189 static void dump_http_header_replace(StoreEntry * entry, const char *name, const HeaderManglers *manglers);
190 static void parse_http_header_replace(HeaderManglers **manglers);
191 #define free_http_header_replace free_HeaderManglers
192 #endif
193 static void dump_HeaderWithAclList(StoreEntry * entry, const char *name, HeaderWithAclList *headers);
194 static void parse_HeaderWithAclList(HeaderWithAclList **header);
195 static void free_HeaderWithAclList(HeaderWithAclList **header);
196 static void parse_note(Notes *);
197 static void dump_note(StoreEntry *, const char *, Notes &);
198 static void free_note(Notes *);
199 static void parse_denyinfo(AclDenyInfoList ** var);
200 static void dump_denyinfo(StoreEntry * entry, const char *name, AclDenyInfoList * var);
201 static void free_denyinfo(AclDenyInfoList ** var);
202 
203 #if USE_WCCPv2
204 static void parse_IpAddress_list(Ip::Address_list **);
205 static void dump_IpAddress_list(StoreEntry *, const char *, const Ip::Address_list *);
206 static void free_IpAddress_list(Ip::Address_list **);
207 #if CURRENTLY_UNUSED
208 static int check_null_IpAddress_list(const Ip::Address_list *);
209 #endif /* CURRENTLY_UNUSED */
210 #endif /* USE_WCCPv2 */
211 
212 static void parsePortCfg(AnyP::PortCfgPointer *, const char *protocol);
213 #define parse_PortCfg(l) parsePortCfg((l), token)
214 static void dump_PortCfg(StoreEntry *, const char *, const AnyP::PortCfgPointer &);
215 #define free_PortCfg(h) *(h)=NULL
216 
217 #if USE_OPENSSL
218 static void parse_sslproxy_cert_sign(sslproxy_cert_sign **cert_sign);
219 static void dump_sslproxy_cert_sign(StoreEntry *entry, const char *name, sslproxy_cert_sign *cert_sign);
220 static void free_sslproxy_cert_sign(sslproxy_cert_sign **cert_sign);
221 static void parse_sslproxy_cert_adapt(sslproxy_cert_adapt **cert_adapt);
222 static void dump_sslproxy_cert_adapt(StoreEntry *entry, const char *name, sslproxy_cert_adapt *cert_adapt);
223 static void free_sslproxy_cert_adapt(sslproxy_cert_adapt **cert_adapt);
224 static void parse_sslproxy_ssl_bump(acl_access **ssl_bump);
225 static void dump_sslproxy_ssl_bump(StoreEntry *entry, const char *name, acl_access *ssl_bump);
226 static void free_sslproxy_ssl_bump(acl_access **ssl_bump);
227 #endif /* USE_OPENSSL */
228 
229 static void parse_ftp_epsv(acl_access **ftp_epsv);
230 static void dump_ftp_epsv(StoreEntry *entry, const char *name, acl_access *ftp_epsv);
231 static void free_ftp_epsv(acl_access **ftp_epsv);
232 
233 static void parse_b_size_t(size_t * var);
234 static void parse_b_int64_t(int64_t * var);
235 
236 static void parse_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap);
237 static void dump_CpuAffinityMap(StoreEntry *const entry, const char *const name, const CpuAffinityMap *const cpuAffinityMap);
238 static void free_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap);
239 
241 static void dump_UrlHelperTimeout(StoreEntry *, const char *, SquidConfig::UrlHelperTimeout &);
243 
244 static int parseOneConfigFile(const char *file_name, unsigned int depth);
245 
246 static void parse_configuration_includes_quoted_values(bool *recognizeQuotedValues);
247 static void dump_configuration_includes_quoted_values(StoreEntry *const entry, const char *const name, bool recognizeQuotedValues);
248 static void free_configuration_includes_quoted_values(bool *recognizeQuotedValues);
249 static void parse_on_unsupported_protocol(acl_access **access);
250 static void dump_on_unsupported_protocol(StoreEntry *entry, const char *name, acl_access *access);
251 static void free_on_unsupported_protocol(acl_access **access);
252 static void ParseAclWithAction(acl_access **access, const Acl::Answer &action, const char *desc, ACL *acl = nullptr);
254 static void dump_http_upgrade_request_protocols(StoreEntry *entry, const char *name, HttpUpgradeProtocolAccess *protoGuards);
256 
257 /*
258  * LegacyParser is a parser for legacy code that uses the global
259  * approach. This is static so that it is only exposed to cache_cf.
260  * Other modules needing access to a ConfigParser should have it
261  * provided to them in their parserFOO methods.
262  */
264 
265 void
267 {
269 }
270 
271 static void
272 SetConfigFilename(char const *file_name, bool is_pipe)
273 {
274  if (is_pipe)
275  cfg_filename = file_name + 1;
276  else
277  cfg_filename = file_name;
278 }
279 
280 static const char*
281 skip_ws(const char* s)
282 {
283  while (xisspace(*s))
284  ++s;
285 
286  return s;
287 }
288 
289 static int
290 parseManyConfigFiles(char* files, int depth)
291 {
292  int error_count = 0;
293  char* saveptr = NULL;
294 #if HAVE_GLOB
295  char *path;
296  glob_t globbuf;
297  int i;
298  memset(&globbuf, 0, sizeof(globbuf));
299  for (path = strwordtok(files, &saveptr); path; path = strwordtok(NULL, &saveptr)) {
300  if (glob(path, globbuf.gl_pathc ? GLOB_APPEND : 0, NULL, &globbuf) != 0) {
301  int xerrno = errno;
302  fatalf("Unable to find configuration file: %s: %s", path, xstrerr(xerrno));
303  }
304  }
305  for (i = 0; i < (int)globbuf.gl_pathc; ++i) {
306  error_count += parseOneConfigFile(globbuf.gl_pathv[i], depth);
307  }
308  globfree(&globbuf);
309 #else
310  char* file = strwordtok(files, &saveptr);
311  while (file != NULL) {
312  error_count += parseOneConfigFile(file, depth);
313  file = strwordtok(NULL, &saveptr);
314  }
315 #endif /* HAVE_GLOB */
316  return error_count;
317 }
318 
319 static void
320 ReplaceSubstr(char*& str, int& len, unsigned substrIdx, unsigned substrLen, const char* newSubstr)
321 {
322  assert(str != NULL);
323  assert(newSubstr != NULL);
324 
325  unsigned newSubstrLen = strlen(newSubstr);
326  if (newSubstrLen > substrLen)
327  str = (char*)realloc(str, len - substrLen + newSubstrLen + 1);
328 
329  // move tail part including zero
330  memmove(str + substrIdx + newSubstrLen, str + substrIdx + substrLen, len - substrIdx - substrLen + 1);
331  // copy new substring in place
332  memcpy(str + substrIdx, newSubstr, newSubstrLen);
333 
334  len = strlen(str);
335 }
336 
337 static void
338 SubstituteMacro(char*& line, int& len, const char* macroName, const char* substStr)
339 {
340  assert(line != NULL);
341  assert(macroName != NULL);
342  assert(substStr != NULL);
343  unsigned macroNameLen = strlen(macroName);
344  while (const char* macroPos = strstr(line, macroName)) // we would replace all occurrences
345  ReplaceSubstr(line, len, macroPos - line, macroNameLen, substStr);
346 }
347 
348 static void
349 ProcessMacros(char*& line, int& len)
350 {
351  SubstituteMacro(line, len, "${service_name}", service_name.c_str());
352  SubstituteMacro(line, len, "${process_name}", TheKidName.c_str());
353  SubstituteMacro(line, len, "${process_number}", xitoa(KidIdentifier));
354 }
355 
356 static void
358 {
359  assert(str != NULL);
360  unsigned i = strlen(str);
361  while ((i > 0) && xisspace(str[i - 1]))
362  --i;
363  str[i] = '\0';
364 }
365 
366 static const char*
367 FindStatement(const char* line, const char* statement)
368 {
369  assert(line != NULL);
370  assert(statement != NULL);
371 
372  const char* str = skip_ws(line);
373  unsigned len = strlen(statement);
374  if (strncmp(str, statement, len) == 0) {
375  str += len;
376  if (*str == '\0')
377  return str;
378  else if (xisspace(*str))
379  return skip_ws(str);
380  }
381 
382  return NULL;
383 }
384 
385 static bool
386 StrToInt(const char* str, long& number)
387 {
388  assert(str != NULL);
389 
390  char* end;
391  number = strtol(str, &end, 0);
392 
393  return (end != str) && (*end == '\0'); // returns true if string contains nothing except number
394 }
395 
396 static bool
397 EvalBoolExpr(const char* expr)
398 {
399  assert(expr != NULL);
400  if (strcmp(expr, "true") == 0) {
401  return true;
402  } else if (strcmp(expr, "false") == 0) {
403  return false;
404  } else if (const char* equation = strchr(expr, '=')) {
405  const char* rvalue = skip_ws(equation + 1);
406  char* lvalue = (char*)xmalloc(equation - expr + 1);
407  xstrncpy(lvalue, expr, equation - expr + 1);
408  trim_trailing_ws(lvalue);
409 
410  long number1;
411  if (!StrToInt(lvalue, number1))
412  fatalf("String is not a integer number: '%s'\n", lvalue);
413  long number2;
414  if (!StrToInt(rvalue, number2))
415  fatalf("String is not a integer number: '%s'\n", rvalue);
416 
417  xfree(lvalue);
418  return number1 == number2;
419  }
420  fatalf("Unable to evaluate expression '%s'\n", expr);
421  return false; // this place cannot be reached
422 }
423 
424 static int
425 parseOneConfigFile(const char *file_name, unsigned int depth)
426 {
427  FILE *fp = NULL;
428  const char *orig_cfg_filename = cfg_filename;
429  const int orig_config_lineno = config_lineno;
430  char *token = NULL;
431  char *tmp_line = NULL;
432  int tmp_line_len = 0;
433  int err_count = 0;
434  int is_pipe = 0;
435 
436  debugs(3, DBG_IMPORTANT, "Processing Configuration File: " << file_name << " (depth " << depth << ")");
437  if (depth > 16) {
438  fatalf("WARNING: can't include %s: includes are nested too deeply (>16)!\n", file_name);
439  return 1;
440  }
441 
442  if (file_name[0] == '!' || file_name[0] == '|') {
443  fp = popen(file_name + 1, "r");
444  is_pipe = 1;
445  } else {
446  fp = fopen(file_name, "r");
447  }
448 
449  if (!fp) {
450  int xerrno = errno;
451  fatalf("Unable to open configuration file: %s: %s", file_name, xstrerr(xerrno));
452  }
453 
454 #if _SQUID_WINDOWS_
455  setmode(fileno(fp), O_TEXT);
456 #endif
457 
458  SetConfigFilename(file_name, bool(is_pipe));
459 
460  memset(config_input_line, '\0', BUFSIZ);
461 
462  config_lineno = 0;
463 
464  std::vector<bool> if_states;
465  while (fgets(config_input_line, BUFSIZ, fp)) {
466  ++config_lineno;
467 
468  if ((token = strchr(config_input_line, '\n')))
469  *token = '\0';
470 
471  if ((token = strchr(config_input_line, '\r')))
472  *token = '\0';
473 
474  // strip any prefix whitespace off the line.
475  const char *p = skip_ws(config_input_line);
476  if (config_input_line != p)
477  memmove(config_input_line, p, strlen(p)+1);
478 
479  if (strncmp(config_input_line, "#line ", 6) == 0) {
480  static char new_file_name[1024];
481  static char *file;
482  static char new_lineno;
483  token = config_input_line + 6;
484  new_lineno = strtol(token, &file, 0) - 1;
485 
486  if (file == token)
487  continue; /* Not a valid #line directive, may be a comment */
488 
489  while (*file && xisspace((unsigned char) *file))
490  ++file;
491 
492  if (*file) {
493  if (*file != '"')
494  continue; /* Not a valid #line directive, may be a comment */
495 
496  xstrncpy(new_file_name, file + 1, sizeof(new_file_name));
497 
498  if ((token = strchr(new_file_name, '"')))
499  *token = '\0';
500 
501  SetConfigFilename(new_file_name, false);
502  }
503 
504  config_lineno = new_lineno;
505  }
506 
507  if (config_input_line[0] == '#')
508  continue;
509 
510  if (config_input_line[0] == '\0')
511  continue;
512 
513  const char* append = tmp_line_len ? skip_ws(config_input_line) : config_input_line;
514 
515  size_t append_len = strlen(append);
516 
517  tmp_line = (char*)xrealloc(tmp_line, tmp_line_len + append_len + 1);
518 
519  strcpy(tmp_line + tmp_line_len, append);
520 
521  tmp_line_len += append_len;
522 
523  if (tmp_line[tmp_line_len-1] == '\\') {
524  debugs(3, 5, "parseConfigFile: tmp_line='" << tmp_line << "'");
525  tmp_line[--tmp_line_len] = '\0';
526  continue;
527  }
528 
529  trim_trailing_ws(tmp_line);
530  ProcessMacros(tmp_line, tmp_line_len);
531  debugs(3, (opt_parse_cfg_only?1:5), "Processing: " << tmp_line);
532 
533  if (const char* expr = FindStatement(tmp_line, "if")) {
534  if_states.push_back(EvalBoolExpr(expr)); // store last if-statement meaning
535  } else if (FindStatement(tmp_line, "endif")) {
536  if (!if_states.empty())
537  if_states.pop_back(); // remove last if-statement meaning
538  else
539  fatalf("'endif' without 'if'\n");
540  } else if (FindStatement(tmp_line, "else")) {
541  if (!if_states.empty())
542  if_states.back() = !if_states.back();
543  else
544  fatalf("'else' without 'if'\n");
545  } else if (if_states.empty() || if_states.back()) { // test last if-statement meaning if present
546  /* Handle includes here */
547  if (tmp_line_len >= 9 && strncmp(tmp_line, "include", 7) == 0 && xisspace(tmp_line[7])) {
548  err_count += parseManyConfigFiles(tmp_line + 8, depth + 1);
549  } else {
550  try {
551  if (!parse_line(tmp_line)) {
552  debugs(3, DBG_CRITICAL, ConfigParser::CurrentLocation() << ": unrecognized: '" << tmp_line << "'");
553  ++err_count;
554  }
555  } catch (...) {
556  // fatal for now
557  debugs(3, DBG_CRITICAL, "configuration error: " << CurrentException);
558  self_destruct();
559  }
560  }
561  }
562 
563  safe_free(tmp_line);
564  tmp_line_len = 0;
565 
566  }
567  if (!if_states.empty())
568  fatalf("if-statement without 'endif'\n");
569 
570  if (is_pipe) {
571  int ret = pclose(fp);
572 
573  if (ret != 0)
574  fatalf("parseConfigFile: '%s' failed with exit code %d\n", file_name, ret);
575  } else {
576  fclose(fp);
577  }
578 
579  SetConfigFilename(orig_cfg_filename, false);
580  config_lineno = orig_config_lineno;
581 
582  xfree(tmp_line);
583  return err_count;
584 }
585 
586 static
587 int
588 parseConfigFileOrThrow(const char *file_name)
589 {
590  int err_count = 0;
591 
592  debugs(5, 4, HERE);
593 
595 
597  default_all();
598 
599  err_count = parseOneConfigFile(file_name, 0);
600 
602 
604 
605  /*
606  * We must call configDoConfigure() before leave_suid() because
607  * configDoConfigure() is where we turn username strings into
608  * uid values.
609  */
611 
612  if (opt_send_signal == -1) {
613  Mgr::RegisterAction("config",
614  "Current Squid Configuration",
615  dump_config,
616  1, 1);
617  }
618 
619  return err_count;
620 }
621 
622 // TODO: Refactor main.cc to centrally handle (and report) all exceptions.
623 int
624 parseConfigFile(const char *file_name)
625 {
626  try {
627  return parseConfigFileOrThrow(file_name);
628  }
629  catch (const std::exception &ex) {
630  debugs(3, DBG_CRITICAL, "FATAL: bad configuration: " << ex.what());
631  self_destruct();
632  return 1; // not reached
633  }
634 }
635 
636 static void
638 {
639  Config2.clear();
640  /* init memory as early as possible */
641  memConfigure();
642  /* Sanity checks */
643 
644  if (Debug::rotateNumber < 0) {
646  }
647 
648 #if SIZEOF_OFF_T <= 4
649  if (Config.Store.maxObjectSize > 0x7FFF0000) {
650  debugs(3, DBG_CRITICAL, "WARNING: This Squid binary can not handle files larger than 2GB. Limiting maximum_object_size to just below 2GB");
651  Config.Store.maxObjectSize = 0x7FFF0000;
652  }
653 #endif
654 
655  if (Config.Announce.period > 0) {
656  Config.onoff.announce = 1;
657  } else {
658  Config.Announce.period = 86400 * 365; /* one year */
659  Config.onoff.announce = 0;
660  }
661 
664  else
665  visible_appname_string = (char const *)APP_FULLNAME;
666 
667  if (Config.Program.redirect) {
668  if (Config.redirectChildren.n_max < 1) {
671  }
672  }
673 
674  if (Config.Program.store_id) {
675  if (Config.storeIdChildren.n_max < 1) {
678  }
679  }
680 
681  if (Config.appendDomain)
682  if (*Config.appendDomain != '.')
683  fatal("append_domain must begin with a '.'");
684 
685  if (Config.errHtmlText == NULL)
687 
688 #if !HAVE_SETRLIMIT || !defined(RLIMIT_NOFILE)
689  if (Config.max_filedescriptors > 0) {
690  debugs(0, DBG_IMPORTANT, "WARNING: max_filedescriptors disabled. Operating System setrlimit(RLIMIT_NOFILE) is missing.");
691  }
692 #elif USE_SELECT || USE_SELECT_WIN32
693  if (Config.max_filedescriptors > FD_SETSIZE) {
694  debugs(0, DBG_IMPORTANT, "WARNING: max_filedescriptors limited to " << FD_SETSIZE << " by select() algorithm.");
695  }
696 #endif
697 
698  storeConfigure();
699 
700  snprintf(ThisCache, sizeof(ThisCache), "%s (%s)",
701  uniqueHostname(),
703 
704  /*
705  * the extra space is for loop detection in client_side.c -- we search
706  * for substrings in the Via header.
707  */
708  snprintf(ThisCache2, sizeof(ThisCache), " %s (%s)",
709  uniqueHostname(),
711 
712  /* Use visible_hostname as default surrogate_id */
713  if (!Config.Accel.surrogate_id) {
714  const char *t = getMyHostname();
715  Config.Accel.surrogate_id = xstrdup( (t?t:"unset-id") );
716  }
717 
720 
721  if (Config.appendDomain)
723  else
725 
726  if (Config.connect_retries > 10) {
727  debugs(0,DBG_CRITICAL, "WARNING: connect_retries cannot be larger than 10. Resetting to 10.");
728  Config.connect_retries = 10;
729  }
730 
731  requirePathnameExists("MIME Config Table", Config.mimeTablePathname);
732 #if USE_UNLINKD
733 
734  requirePathnameExists("unlinkd_program", Config.Program.unlinkd);
735 #endif
736  bool logDaemonUsed = false;
737  for (const auto *log = Config.Log.accesslogs; !logDaemonUsed && log; log = log->next)
738  logDaemonUsed = log->usesDaemon();
739 #if ICAP_CLIENT
740  for (const auto *log = Config.Log.icaplogs; !logDaemonUsed && log; log = log->next)
741  logDaemonUsed = log->usesDaemon();
742 #endif
743  if (logDaemonUsed)
744  requirePathnameExists("logfile_daemon", Log::TheConfig.logfile_daemon);
745 
746  if (Config.Program.redirect)
747  requirePathnameExists("redirect_program", Config.Program.redirect->key);
748 
749  if (Config.Program.store_id)
750  requirePathnameExists("store_id_program", Config.Program.store_id->key);
751 
752  requirePathnameExists("Icon Directory", Config.icons.directory);
753 
755  requirePathnameExists("Error Directory", Config.errorDirectory);
756 
757 #if USE_HTTP_VIOLATIONS
758 
759  {
760  const RefreshPattern *R;
761 
762  for (R = Config.Refresh; R; R = R->next) {
763  if (!R->flags.override_expire)
764  continue;
765 
766  debugs(22, DBG_IMPORTANT, "WARNING: use of 'override-expire' in 'refresh_pattern' violates HTTP");
767 
768  break;
769  }
770 
771  for (R = Config.Refresh; R; R = R->next) {
772  if (!R->flags.override_lastmod)
773  continue;
774 
775  debugs(22, DBG_IMPORTANT, "WARNING: use of 'override-lastmod' in 'refresh_pattern' violates HTTP");
776 
777  break;
778  }
779 
780  for (R = Config.Refresh; R; R = R->next) {
781  if (!R->flags.reload_into_ims)
782  continue;
783 
784  debugs(22, DBG_IMPORTANT, "WARNING: use of 'reload-into-ims' in 'refresh_pattern' violates HTTP");
785 
786  break;
787  }
788 
789  for (R = Config.Refresh; R; R = R->next) {
790  if (!R->flags.ignore_reload)
791  continue;
792 
793  debugs(22, DBG_IMPORTANT, "WARNING: use of 'ignore-reload' in 'refresh_pattern' violates HTTP");
794 
795  break;
796  }
797 
798  for (R = Config.Refresh; R; R = R->next) {
799  if (!R->flags.ignore_no_store)
800  continue;
801 
802  debugs(22, DBG_IMPORTANT, "WARNING: use of 'ignore-no-store' in 'refresh_pattern' violates HTTP");
803 
804  break;
805  }
806 
807  for (R = Config.Refresh; R; R = R->next) {
808  if (!R->flags.ignore_private)
809  continue;
810 
811  debugs(22, DBG_IMPORTANT, "WARNING: use of 'ignore-private' in 'refresh_pattern' violates HTTP");
812 
813  break;
814  }
815  }
816 #endif
817 #if !USE_HTTP_VIOLATIONS
818  Config.onoff.via = 1;
819 #else
820 
821  if (!Config.onoff.via)
822  debugs(22, DBG_IMPORTANT, "WARNING: HTTP requires the use of Via");
823 
824 #endif
825 
826  // we enable runtime PURGE checks if there is at least one PURGE method ACL
827  // TODO: replace with a dedicated "purge" ACL option?
829 
830  if (geteuid() == 0) {
831  if (NULL != Config.effectiveUser) {
832 
833  struct passwd *pwd = getpwnam(Config.effectiveUser);
834 
835  if (NULL == pwd) {
836  /*
837  * Andres Kroonmaa <andre@online.ee>:
838  * Some getpwnam() implementations (Solaris?) require
839  * an available FD < 256 for opening a FILE* to the
840  * passwd file.
841  * DW:
842  * This should be safe at startup, but might still fail
843  * during reconfigure.
844  */
845  fatalf("getpwnam failed to find userid for effective user '%s'",
847  return;
848  }
849 
850  Config2.effectiveUserID = pwd->pw_uid;
851 
852  Config2.effectiveGroupID = pwd->pw_gid;
853 
854 #if HAVE_PUTENV
855  if (pwd->pw_dir && *pwd->pw_dir) {
856  // putenv() leaks by design; avoid leaks when nothing changes
857  static SBuf lastDir;
858  if (lastDir.isEmpty() || lastDir.cmp(pwd->pw_dir) != 0) {
859  lastDir = pwd->pw_dir;
860  int len = strlen(pwd->pw_dir) + 6;
861  char *env_str = (char *)xcalloc(len, 1);
862  snprintf(env_str, len, "HOME=%s", pwd->pw_dir);
863  putenv(env_str);
864  }
865  }
866 #endif
867  }
868  } else {
869  Config2.effectiveUserID = geteuid();
870  Config2.effectiveGroupID = getegid();
871  }
872 
873  if (NULL != Config.effectiveGroup) {
874 
875  struct group *grp = getgrnam(Config.effectiveGroup);
876 
877  if (NULL == grp) {
878  fatalf("getgrnam failed to find groupid for effective group '%s'",
880  return;
881  }
882 
883  Config2.effectiveGroupID = grp->gr_gid;
884  }
885 
886 #if USE_OPENSSL
889 #endif
890 
891  if (Security::ProxyOutgoingConfig.encryptTransport) {
892  debugs(3, DBG_IMPORTANT, "Initializing https:// proxy context");
895 #if USE_OPENSSL
896  fatal("ERROR: Could not initialize https:// proxy context");
897 #else
898  debugs(3, DBG_IMPORTANT, "ERROR: proxying https:// currently still requires --with-openssl");
899 #endif
900  }
901 #if USE_OPENSSL
903 #endif
904  }
905 
906  for (CachePeer *p = Config.peers; p != NULL; p = p->next) {
907 
908  // default value for ssldomain= is the peer host/IP
909  if (p->secure.sslDomain.isEmpty())
910  p->secure.sslDomain = p->host;
911 
912  if (p->secure.encryptTransport) {
913  debugs(3, DBG_IMPORTANT, "Initializing cache_peer " << p->name << " TLS context");
914  p->sslContext = p->secure.createClientContext(true);
915  if (!p->sslContext) {
916  debugs(3, DBG_CRITICAL, "ERROR: Could not initialize cache_peer " << p->name << " TLS context");
917  self_destruct();
918  return;
919  }
920  }
921  }
922 
923  for (AnyP::PortCfgPointer s = HttpPortList; s != NULL; s = s->next) {
924  if (!s->secure.encryptTransport)
925  continue;
926  debugs(3, DBG_IMPORTANT, "Initializing " << AnyP::UriScheme(s->transport.protocol) << "_port " << s->s << " TLS contexts");
927  s->secure.initServerContexts(*s);
928  }
929 
930  // prevent infinite fetch loops in the request parser
931  // due to buffer full but not enough data received to finish parse
933  fatalf("Client request buffer of %u bytes cannot hold a request with %u bytes of headers." \
934  " Change client_request_buffer_max or request_header_max_size limits.",
936  }
937 
938  /*
939  * Disable client side request pipelining if client_persistent_connections OFF.
940  * Waste of resources queueing any pipelined requests when the first will close the connection.
941  */
943  debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: pipeline_prefetch " << Config.pipeline_max_prefetch <<
944  " requires client_persistent_connections ON. Forced pipeline_prefetch 0.");
946  }
947 
948 #if USE_AUTH
949  /*
950  * disable client side request pipelining. There is a race with
951  * Negotiate and NTLM when the client sends a second request on an
952  * connection before the authenticate challenge is sent. With
953  * pipelining OFF, the client may fail to authenticate, but squid's
954  * state will be preserved.
955  */
956  if (Config.pipeline_max_prefetch > 0) {
957  Auth::SchemeConfig *nego = Auth::SchemeConfig::Find("Negotiate");
959  if ((nego && nego->active()) || (ntlm && ntlm->active())) {
960  debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: pipeline_prefetch breaks NTLM and Negotiate authentication. Forced pipeline_prefetch 0.");
962  }
963  }
964 
965  for (auto &authSchemes : Auth::TheConfig.schemeLists) {
966  authSchemes.expand();
967  if (authSchemes.authConfigs.empty()) {
968  debugs(3, DBG_CRITICAL, "auth_schemes: at least one scheme name is required; got: " << authSchemes.rawSchemes);
969  self_destruct();
970  }
971  }
972 #endif
973 }
974 
981 void
982 parse_obsolete(const char *name)
983 {
984  // Directives which have been radically changed rather than removed
985  if (!strcmp(name, "url_rewrite_concurrency")) {
986  int cval;
987  parse_int(&cval);
988  debugs(3, DBG_CRITICAL, "WARNING: url_rewrite_concurrency upgrade overriding url_rewrite_children settings.");
990  }
991 
992  if (!strcmp(name, "log_access")) {
993  self_destruct();
994  return;
995  }
996 
997  if (!strcmp(name, "log_icap")) {
998  self_destruct();
999  return;
1000  }
1001 
1002  if (!strcmp(name, "ignore_ims_on_miss")) {
1003  // the replacement directive cache_revalidate_on_miss has opposite meanings for ON/OFF value
1004  // than the 2.7 directive. We need to parse and invert the configured value.
1005  int temp = 0;
1006  parse_onoff(&temp);
1008  }
1009 
1010  if (!strncmp(name, "sslproxy_", 9)) {
1011  // the replacement directive tls_outgoing_options uses options instead of whole-line input
1012  SBuf tmp;
1013  if (!strcmp(name, "sslproxy_cafile"))
1014  tmp.append("cafile=");
1015  else if (!strcmp(name, "sslproxy_capath"))
1016  tmp.append("capath=");
1017  else if (!strcmp(name, "sslproxy_cipher"))
1018  tmp.append("cipher=");
1019  else if (!strcmp(name, "sslproxy_client_certificate"))
1020  tmp.append("cert=");
1021  else if (!strcmp(name, "sslproxy_client_key"))
1022  tmp.append("key=");
1023  else if (!strcmp(name, "sslproxy_flags"))
1024  tmp.append("flags=");
1025  else if (!strcmp(name, "sslproxy_options"))
1026  tmp.append("options=");
1027  else if (!strcmp(name, "sslproxy_version"))
1028  tmp.append("version=");
1029  else {
1030  debugs(3, DBG_CRITICAL, "ERROR: unknown directive: " << name);
1031  self_destruct();
1032  return;
1033  }
1034 
1035  // add the value as unquoted-string because the old values did not support whitespace
1036  const char *token = ConfigParser::NextQuotedOrToEol();
1037  tmp.append(token, strlen(token));
1039  }
1040 }
1041 
1042 template <class MinimalUnit>
1043 static const char *
1045 {
1046  const auto minUnit = MinimalUnit(1);
1047  if(minUnit == std::chrono::nanoseconds(1))
1048  return T_NANOSECOND_STR;
1049  else if (minUnit == std::chrono::microseconds(1))
1050  return T_MICROSECOND_STR;
1051  else if (minUnit == std::chrono::milliseconds(1))
1052  return T_MILLISECOND_STR;
1053  else {
1054  assert(minUnit >= std::chrono::seconds(1));
1055  return T_SECOND_STR;
1056  }
1057 }
1058 
1064 template <class MinimalUnit>
1065 static bool
1066 parseTimeUnit(const char *unitName, std::chrono::nanoseconds &ns)
1067 {
1068  if (!unitName)
1069  throw TexcHere("missing time unit");
1070 
1071  if (!strncasecmp(unitName, T_NANOSECOND_STR, strlen(T_NANOSECOND_STR)))
1072  ns = std::chrono::nanoseconds(1);
1073  else if (!strncasecmp(unitName, T_MICROSECOND_STR, strlen(T_MICROSECOND_STR)))
1074  ns = std::chrono::microseconds(1);
1075  else if (!strncasecmp(unitName, T_MILLISECOND_STR, strlen(T_MILLISECOND_STR)))
1076  ns = std::chrono::milliseconds(1);
1077  else if (!strncasecmp(unitName, T_SECOND_STR, strlen(T_SECOND_STR)))
1078  ns = std::chrono::seconds(1);
1079  else if (!strncasecmp(unitName, T_MINUTE_STR, strlen(T_MINUTE_STR)))
1080  ns = std::chrono::minutes(1);
1081  else if (!strncasecmp(unitName, T_HOUR_STR, strlen(T_HOUR_STR)))
1082  ns = std::chrono::hours(1);
1083  else if (!strncasecmp(unitName, T_DAY_STR, strlen(T_DAY_STR)))
1084  ns = std::chrono::hours(24);
1085  else if (!strncasecmp(unitName, T_WEEK_STR, strlen(T_WEEK_STR)))
1086  ns = std::chrono::hours(24 * 7);
1087  else if (!strncasecmp(unitName, T_FORTNIGHT_STR, strlen(T_FORTNIGHT_STR)))
1088  ns = std::chrono::hours(24 * 14);
1089  else if (!strncasecmp(unitName, T_MONTH_STR, strlen(T_MONTH_STR)))
1090  ns = std::chrono::hours(24 * 30);
1091  else if (!strncasecmp(unitName, T_YEAR_STR, strlen(T_YEAR_STR)))
1092  ns = std::chrono::hours(static_cast<std::chrono::hours::rep>(HoursPerYear));
1093  else if (!strncasecmp(unitName, T_DECADE_STR, strlen(T_DECADE_STR)))
1094  ns = std::chrono::hours(static_cast<std::chrono::hours::rep>(HoursPerYear * 10));
1095  else
1096  return false;
1097 
1098  if (ns < MinimalUnit(1)) {
1099  throw TexcHere(ToSBuf("time unit '", unitName, "' is too small to be used in this context, the minimal unit is ",
1100  TimeUnitToString<MinimalUnit>()));
1101  }
1102 
1103  return true;
1104 }
1105 
1106 static std::chrono::nanoseconds
1107 ToNanoSeconds(const double value, const std::chrono::nanoseconds &unit)
1108 {
1109  if (value < 0.0)
1110  throw TexcHere("time must have a positive value");
1111 
1112  if (value > (static_cast<double>(std::chrono::nanoseconds::max().count()) / unit.count())) {
1113  const auto maxYears = std::chrono::duration_cast<std::chrono::hours>(std::chrono::nanoseconds::max()).count()/HoursPerYear;
1114  throw TexcHere(ToSBuf("time values cannot exceed ", maxYears, " years"));
1115  }
1116 
1117  return std::chrono::duration_cast<std::chrono::nanoseconds>(unit * value);
1118 }
1119 
1120 template <class TimeUnit>
1121 static TimeUnit
1122 FromNanoseconds(const std::chrono::nanoseconds &ns, const double parsedValue)
1123 {
1124  const auto result = std::chrono::duration_cast<TimeUnit>(ns);
1125  if (!result.count()) {
1126  throw TexcHere(ToSBuf("time value '", parsedValue,
1127  "' is too small to be used in this context, the minimal value is 1 ",
1128  TimeUnitToString<TimeUnit>()));
1129  }
1130  return result;
1131 }
1132 
1135 template <class TimeUnit>
1136 static TimeUnit
1138 {
1139  const auto valueToken = ConfigParser::NextToken();
1140  if (!valueToken)
1141  throw TexcHere("cannot read a time value");
1142 
1143  const auto parsedValue = xatof(valueToken);
1144 
1145  if (parsedValue == 0)
1146  return TimeUnit::zero();
1147 
1148  std::chrono::nanoseconds parsedUnitDuration;
1149 
1150  const auto token = ConfigParser::PeekAtToken();
1151 
1152  if (!parseTimeUnit<TimeUnit>(token, parsedUnitDuration))
1153  throw TexcHere(ToSBuf("unknown time unit '", token, "'"));
1154 
1155  (void)ConfigParser::NextToken();
1156 
1157  const auto nanoseconds = ToNanoSeconds(parsedValue, parsedUnitDuration);
1158 
1159  // validate precisions (time-units-small only)
1160  if (TimeUnit(1) <= std::chrono::microseconds(1)) {
1161  if (0 < nanoseconds.count() && nanoseconds.count() < 3) {
1163  "Squid time measurement precision is likely to be far worse than " <<
1164  "the nanosecond-level precision implied by the configured value: " << parsedValue << ' ' << token);
1165  }
1166  }
1167 
1168  return FromNanoseconds<TimeUnit>(nanoseconds, parsedValue);
1169 }
1170 
1171 static void
1172 parseBytesLine64(int64_t * bptr, const char *units)
1173 {
1174  char *token;
1175  double d;
1176  int64_t m;
1177  int64_t u;
1178 
1179  if ((u = parseBytesUnits(units)) == 0) {
1180  self_destruct();
1181  return;
1182  }
1183 
1184  if ((token = ConfigParser::NextToken()) == NULL) {
1185  self_destruct();
1186  return;
1187  }
1188 
1189  if (strcmp(token, "none") == 0 || strcmp(token, "-1") == 0) {
1190  *bptr = -1;
1191  return;
1192  }
1193 
1194  d = xatof(token);
1195 
1196  m = u; /* default to 'units' if none specified */
1197 
1198  if (0.0 == d)
1199  (void) 0;
1200  else if ((token = ConfigParser::NextToken()) == NULL)
1201  debugs(3, DBG_CRITICAL, "WARNING: No units on '" <<
1202  config_input_line << "', assuming " <<
1203  d << " " << units );
1204  else if ((m = parseBytesUnits(token)) == 0) {
1205  self_destruct();
1206  return;
1207  }
1208 
1209  *bptr = static_cast<int64_t>(m * d / u);
1210 
1211  if (static_cast<double>(*bptr) * 2 != (m * d / u) * 2) {
1212  debugs(3, DBG_CRITICAL, "ERROR: Invalid value '" <<
1213  d << " " << token << ": integer overflow (int64_t).");
1214  self_destruct();
1215  }
1216 }
1217 
1218 static void
1219 parseBytesLine(size_t * bptr, const char *units)
1220 {
1221  char *token;
1222  double d;
1223  int m;
1224  int u;
1225 
1226  if ((u = parseBytesUnits(units)) == 0) {
1227  self_destruct();
1228  return;
1229  }
1230 
1231  if ((token = ConfigParser::NextToken()) == NULL) {
1232  self_destruct();
1233  return;
1234  }
1235 
1236  if (strcmp(token, "none") == 0 || strcmp(token, "-1") == 0) {
1237  *bptr = static_cast<size_t>(-1);
1238  return;
1239  }
1240 
1241  d = xatof(token);
1242 
1243  m = u; /* default to 'units' if none specified */
1244 
1245  if (0.0 == d)
1246  (void) 0;
1247  else if ((token = ConfigParser::NextToken()) == NULL)
1248  debugs(3, DBG_CRITICAL, "WARNING: No units on '" <<
1249  config_input_line << "', assuming " <<
1250  d << " " << units );
1251  else if ((m = parseBytesUnits(token)) == 0) {
1252  self_destruct();
1253  return;
1254  }
1255 
1256  *bptr = static_cast<size_t>(m * d / u);
1257 
1258  if (static_cast<double>(*bptr) * 2 != (m * d / u) * 2) {
1259  debugs(3, DBG_CRITICAL, "ERROR: Invalid value '" <<
1260  d << " " << token << ": integer overflow (size_t).");
1261  self_destruct();
1262  }
1263 }
1264 
1265 static void
1266 parseBytesLineSigned(ssize_t * bptr, const char *units)
1267 {
1268  char *token;
1269  double d;
1270  int m;
1271  int u;
1272 
1273  if ((u = parseBytesUnits(units)) == 0) {
1274  self_destruct();
1275  return;
1276  }
1277 
1278  if ((token = ConfigParser::NextToken()) == NULL) {
1279  self_destruct();
1280  return;
1281  }
1282 
1283  if (strcmp(token, "none") == 0 || token[0] == '-' /* -N */) {
1284  *bptr = -1;
1285  return;
1286  }
1287 
1288  d = xatof(token);
1289 
1290  m = u; /* default to 'units' if none specified */
1291 
1292  if (0.0 == d)
1293  (void) 0;
1294  else if ((token = ConfigParser::NextToken()) == NULL)
1295  debugs(3, DBG_CRITICAL, "WARNING: No units on '" <<
1296  config_input_line << "', assuming " <<
1297  d << " " << units );
1298  else if ((m = parseBytesUnits(token)) == 0) {
1299  self_destruct();
1300  return;
1301  }
1302 
1303  *bptr = static_cast<ssize_t>(m * d / u);
1304 
1305  if (static_cast<double>(*bptr) * 2 != (m * d / u) * 2) {
1306  debugs(3, DBG_CRITICAL, "ERROR: Invalid value '" <<
1307  d << " " << token << ": integer overflow (ssize_t).");
1308  self_destruct();
1309  }
1310 }
1311 
1317 void
1318 parseBytesOptionValue(size_t * bptr, const char *units, char const * value)
1319 {
1320  int u;
1321  if ((u = parseBytesUnits(units)) == 0) {
1322  self_destruct();
1323  return;
1324  }
1325 
1326  // Find number from string beginning.
1327  char const * number_begin = value;
1328  char const * number_end = value;
1329 
1330  while ((*number_end >= '0' && *number_end <= '9')) {
1331  ++number_end;
1332  }
1333 
1334  String number;
1335  number.assign(number_begin, number_end - number_begin);
1336 
1337  int d = xatoi(number.termedBuf());
1338  int m;
1339  if ((m = parseBytesUnits(number_end)) == 0) {
1340  self_destruct();
1341  return;
1342  }
1343 
1344  *bptr = static_cast<size_t>(m * d / u);
1345  if (static_cast<double>(*bptr) * 2 != (m * d / u) * 2)
1346  self_destruct();
1347 }
1348 
1349 static size_t
1350 parseBytesUnits(const char *unit)
1351 {
1352  if (!strncasecmp(unit, B_BYTES_STR, strlen(B_BYTES_STR)))
1353  return 1;
1354 
1355  if (!strncasecmp(unit, B_KBYTES_STR, strlen(B_KBYTES_STR)))
1356  return 1 << 10;
1357 
1358  if (!strncasecmp(unit, B_MBYTES_STR, strlen(B_MBYTES_STR)))
1359  return 1 << 20;
1360 
1361  if (!strncasecmp(unit, B_GBYTES_STR, strlen(B_GBYTES_STR)))
1362  return 1 << 30;
1363 
1364  debugs(3, DBG_CRITICAL, "WARNING: Unknown bytes unit '" << unit << "'");
1365 
1366  return 0;
1367 }
1368 
1369 static void
1371 {
1372  while (char *token = ConfigParser::NextQuotedToken())
1373  list->push_back(SBuf(token));
1374 }
1375 
1376 // just dump a list, no directive name
1377 static void
1378 dump_SBufList(StoreEntry * entry, const SBufList &words)
1379 {
1380  for (const auto &i : words) {
1381  entry->append(i.rawContent(), i.length());
1382  entry->append(" ",1);
1383  }
1384  entry->append("\n",1);
1385 }
1386 
1387 // dump a SBufList type directive with name
1388 static void
1389 dump_SBufList(StoreEntry * entry, const char *name, SBufList &list)
1390 {
1391  if (!list.empty()) {
1392  entry->append(name, strlen(name));
1393  entry->append(" ", 1);
1394  dump_SBufList(entry, list);
1395  }
1396 }
1397 
1398 static void
1400 {
1401  if (list)
1402  list->clear();
1403 }
1404 
1405 static void
1406 dump_acl(StoreEntry * entry, const char *name, ACL * ae)
1407 {
1408  while (ae != NULL) {
1409  debugs(3, 3, "dump_acl: " << name << " " << ae->name);
1410  storeAppendPrintf(entry, "%s %s %s ",
1411  name,
1412  ae->name,
1413  ae->typeString());
1414  SBufList tail;
1415  tail.splice(tail.end(), ae->dumpOptions());
1416  tail.splice(tail.end(), ae->dump()); // ACL parameters
1417  dump_SBufList(entry, tail);
1418  ae = ae->next;
1419  }
1420 }
1421 
1422 static void
1424 {
1426 }
1427 
1428 static void
1430 {
1431  aclDestroyAcls(ae);
1432 }
1433 
1434 void
1436 {
1437  dump_SBufList(entry, head->dump());
1438 }
1439 
1440 void
1441 dump_acl_access(StoreEntry * entry, const char *name, acl_access * head)
1442 {
1443  if (head)
1444  dump_SBufList(entry, head->treeDump(name, &Acl::AllowOrDeny));
1445 }
1446 
1447 static void
1449 {
1451 }
1452 
1453 static void
1455 {
1457 }
1458 
1459 static void
1460 dump_address(StoreEntry * entry, const char *name, Ip::Address &addr)
1461 {
1462  char buf[MAX_IPSTRLEN];
1463  storeAppendPrintf(entry, "%s %s\n", name, addr.toStr(buf,MAX_IPSTRLEN) );
1464 }
1465 
1466 static void
1468 {
1469  char *token = ConfigParser::NextToken();
1470 
1471  if (!token) {
1472  self_destruct();
1473  return;
1474  }
1475 
1476  if (!strcmp(token,"any_addr"))
1477  addr->setAnyAddr();
1478  else if ( (!strcmp(token,"no_addr")) || (!strcmp(token,"full_mask")) )
1479  addr->setNoAddr();
1480  else if ( (*addr = token) ) // try parse numeric/IPA
1481  (void) 0;
1482  else if (addr->GetHostByName(token)) // do not use ipcache
1483  (void) 0;
1484  else { // not an IP and not a hostname
1485  debugs(3, DBG_CRITICAL, "FATAL: invalid IP address or domain name '" << token << "'");
1486  self_destruct();
1487  }
1488 }
1489 
1490 static void
1492 {
1493  addr->setEmpty();
1494 }
1495 
1496 static void
1497 dump_acl_address(StoreEntry * entry, const char *name, Acl::Address * head)
1498 {
1499  char buf[MAX_IPSTRLEN];
1500 
1501  for (Acl::Address *l = head; l; l = l->next) {
1502  if (!l->addr.isAnyAddr())
1503  storeAppendPrintf(entry, "%s %s", name, l->addr.toStr(buf,MAX_IPSTRLEN));
1504  else
1505  storeAppendPrintf(entry, "%s autoselect", name);
1506 
1507  dump_acl_list(entry, l->aclList);
1508 
1509  storeAppendPrintf(entry, "\n");
1510  }
1511 }
1512 
1513 static void
1515 {
1516  Acl::Address *l = new Acl::Address;
1517  parse_address(&l->addr);
1519 
1520  Acl::Address **tail = head;
1521  while (*tail)
1522  tail = &(*tail)->next;
1523 
1524  *tail = l;
1525 }
1526 
1527 static void
1529 {
1530  delete *head;
1531  *head = NULL;
1532 }
1533 
1534 static void
1535 dump_acl_tos(StoreEntry * entry, const char *name, acl_tos * head)
1536 {
1537  acl_tos *l;
1538 
1539  for (l = head; l; l = l->next) {
1540  if (l->tos > 0)
1541  storeAppendPrintf(entry, "%s 0x%02X", name, l->tos);
1542  else
1543  storeAppendPrintf(entry, "%s none", name);
1544 
1545  dump_acl_list(entry, l->aclList);
1546 
1547  storeAppendPrintf(entry, "\n");
1548  }
1549 }
1550 
1551 static void
1553 {
1554  unsigned int tos; /* Initially uint for strtoui. Casted to tos_t before return */
1555  char *token = ConfigParser::NextToken();
1556 
1557  if (!token) {
1558  self_destruct();
1559  return;
1560  }
1561 
1562  if (!xstrtoui(token, NULL, &tos, 0, std::numeric_limits<tos_t>::max())) {
1563  self_destruct();
1564  return;
1565  }
1566 
1567  const unsigned int chTos = tos & 0xFC;
1568  if (chTos != tos) {
1569  debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: Tos value '" << tos << "' adjusted to '" << chTos << "'");
1570  tos = chTos;
1571  }
1572 
1573  acl_tos *l = new acl_tos;
1574 
1575  l->tos = (tos_t)tos;
1576 
1577  aclParseAclList(LegacyParser, &l->aclList, token);
1578 
1579  acl_tos **tail = head; /* sane name below */
1580  while (*tail)
1581  tail = &(*tail)->next;
1582 
1583  *tail = l;
1584 }
1585 
1586 static void
1588 {
1589  delete *head;
1590  *head = NULL;
1591 }
1592 
1593 #if SO_MARK && USE_LIBCAP
1594 
1595 static void
1596 dump_acl_nfmark(StoreEntry * entry, const char *name, acl_nfmark * head)
1597 {
1598  for (acl_nfmark *l = head; l; l = l->next) {
1599  storeAppendPrintf(entry, "%s %s", name, ToSBuf(l->markConfig).c_str());
1600 
1601  dump_acl_list(entry, l->aclList);
1602 
1603  storeAppendPrintf(entry, "\n");
1604  }
1605 }
1606 
1607 static void
1608 parse_acl_nfmark(acl_nfmark ** head)
1609 {
1610  SBuf token(ConfigParser::NextToken());
1611  const auto mc = Ip::NfMarkConfig::Parse(token);
1612 
1613  // Packet marking directives should not allow to use masks.
1614  const auto pkt_dirs = {"mark_client_packet", "clientside_mark", "tcp_outgoing_mark"};
1615  if (mc.hasMask() && std::find(pkt_dirs.begin(), pkt_dirs.end(), cfg_directive) != pkt_dirs.end())
1616  throw TexcHere(ToSBuf("'", cfg_directive, "' does not support masked marks"));
1617 
1618  acl_nfmark *l = new acl_nfmark;
1619  l->markConfig = mc;
1620 
1621  aclParseAclList(LegacyParser, &l->aclList, token.c_str());
1622 
1623  acl_nfmark **tail = head; /* sane name below */
1624  while (*tail)
1625  tail = &(*tail)->next;
1626 
1627  *tail = l;
1628 }
1629 
1630 static void
1631 free_acl_nfmark(acl_nfmark ** head)
1632 {
1633  delete *head;
1634  *head = NULL;
1635 }
1636 #endif /* SO_MARK */
1637 
1638 static void
1639 dump_acl_b_size_t(StoreEntry * entry, const char *name, AclSizeLimit * head)
1640 {
1641  for (AclSizeLimit *l = head; l; l = l->next) {
1642  if (l->size != -1)
1643  storeAppendPrintf(entry, "%s %d %s\n", name, (int) l->size, B_BYTES_STR);
1644  else
1645  storeAppendPrintf(entry, "%s none", name);
1646 
1647  dump_acl_list(entry, l->aclList);
1648 
1649  storeAppendPrintf(entry, "\n");
1650  }
1651 }
1652 
1653 static void
1655 {
1656  AclSizeLimit *l = new AclSizeLimit;
1657 
1658  parse_b_int64_t(&l->size);
1659 
1661 
1662  AclSizeLimit **tail = head; /* sane name below */
1663  while (*tail)
1664  tail = &(*tail)->next;
1665 
1666  *tail = l;
1667 }
1668 
1669 static void
1671 {
1672  delete *head;
1673  *head = NULL;
1674 }
1675 
1676 #if USE_DELAY_POOLS
1677 
1678 #include "DelayConfig.h"
1679 #include "DelayPools.h"
1680 /* do nothing - free_delay_pool_count is the magic free function.
1681  * this is why delay_pool_count isn't just marked TYPE: u_short
1682  */
1683 #define free_delay_pool_class(X)
1684 #define free_delay_pool_access(X)
1685 #define free_delay_pool_rates(X)
1686 #define dump_delay_pool_class(X, Y, Z)
1687 #define dump_delay_pool_access(X, Y, Z)
1688 #define dump_delay_pool_rates(X, Y, Z)
1689 
1690 static void
1692 {
1693  cfg->freePoolCount();
1694 }
1695 
1696 static void
1697 dump_delay_pool_count(StoreEntry * entry, const char *name, DelayConfig &cfg)
1698 {
1699  cfg.dumpPoolCount (entry, name);
1700 }
1701 
1702 static void
1704 {
1705  cfg->parsePoolCount();
1706 }
1707 
1708 static void
1710 {
1711  cfg->parsePoolClass();
1712 }
1713 
1714 static void
1716 {
1717  cfg->parsePoolRates();
1718 }
1719 
1720 static void
1722 {
1724 }
1725 
1726 #endif
1727 
1728 #if USE_DELAY_POOLS
1729 #include "ClientDelayConfig.h"
1730 /* do nothing - free_client_delay_pool_count is the magic free function.
1731  * this is why client_delay_pool_count isn't just marked TYPE: u_short
1732  */
1733 
1734 #define free_client_delay_pool_access(X)
1735 #define free_client_delay_pool_rates(X)
1736 #define dump_client_delay_pool_access(X, Y, Z)
1737 #define dump_client_delay_pool_rates(X, Y, Z)
1738 
1739 static void
1741 {
1742  cfg->freePools();
1743 }
1744 
1745 static void
1747 {
1748  cfg.dumpPoolCount (entry, name);
1749 }
1750 
1751 static void
1753 {
1754  cfg->parsePoolCount();
1755 }
1756 
1757 static void
1759 {
1760  cfg->parsePoolRates();
1761 }
1762 
1763 static void
1765 {
1767 }
1768 #endif
1769 
1770 #if USE_HTTP_VIOLATIONS
1771 static void
1772 dump_http_header_access(StoreEntry * entry, const char *name, const HeaderManglers *manglers)
1773 {
1774  if (manglers)
1775  manglers->dumpAccess(entry, name);
1776 }
1777 
1778 static void
1780 {
1781  char *t = NULL;
1782 
1783  if ((t = ConfigParser::NextToken()) == NULL) {
1784  debugs(3, DBG_CRITICAL, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
1785  debugs(3, DBG_CRITICAL, "parse_http_header_access: missing header name.");
1786  return;
1787  }
1788 
1789  if (!*pm)
1790  *pm = new HeaderManglers;
1791  HeaderManglers *manglers = *pm;
1792  headerMangler *mangler = manglers->track(t);
1793  assert(mangler);
1794 
1795  std::string directive = "http_header_access ";
1796  directive += t;
1797  aclParseAccessLine(directive.c_str(), LegacyParser, &mangler->access_list);
1798 }
1799 
1800 static void
1802 {
1803  // we delete the entire http_header_* mangler configuration at once
1804  if (const HeaderManglers *manglers = *pm) {
1805  delete manglers;
1806  *pm = NULL;
1807  }
1808 }
1809 
1810 static void
1811 dump_http_header_replace(StoreEntry * entry, const char *name, const HeaderManglers *manglers)
1812 {
1813  if (manglers)
1814  manglers->dumpReplacement(entry, name);
1815 }
1816 
1817 static void
1819 {
1820  char *t = NULL;
1821 
1822  if ((t = ConfigParser::NextToken()) == NULL) {
1823  debugs(3, DBG_CRITICAL, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
1824  debugs(3, DBG_CRITICAL, "parse_http_header_replace: missing header name.");
1825  return;
1826  }
1827 
1828  const char *value = ConfigParser::NextQuotedOrToEol();
1829 
1830  if (!*pm)
1831  *pm = new HeaderManglers;
1832  HeaderManglers *manglers = *pm;
1833  manglers->setReplacement(t, value);
1834 }
1835 
1836 #endif
1837 
1838 static void
1839 dump_cachedir(StoreEntry * entry, const char *name, const Store::DiskConfig &swap)
1840 {
1841  Store::Disks::Dump(swap, *entry, name);
1842 }
1843 
1844 static int
1846 {
1847  return s == NULL;
1848 }
1849 
1850 #if USE_AUTH
1851 static void
1853 {
1854  char *type_str = ConfigParser::NextToken();
1855  if (!type_str) {
1856  self_destruct();
1857  return;
1858  }
1859 
1860  char *param_str = ConfigParser::NextToken();
1861  if (!param_str) {
1862  self_destruct();
1863  return;
1864  }
1865 
1866  /* find a configuration for the scheme in the currently parsed configs... */
1867  Auth::SchemeConfig *schemeCfg = Auth::SchemeConfig::Find(type_str);
1868 
1869  if (schemeCfg == NULL) {
1870  /* Create a configuration based on the scheme info */
1871  Auth::Scheme::Pointer theScheme = Auth::Scheme::Find(type_str);
1872 
1873  if (theScheme == NULL) {
1874  debugs(3, DBG_CRITICAL, "Parsing Config File: Unknown authentication scheme '" << type_str << "'.");
1875  self_destruct();
1876  return;
1877  }
1878 
1879  config->push_back(theScheme->createConfig());
1880  schemeCfg = Auth::SchemeConfig::Find(type_str);
1881  if (schemeCfg == NULL) {
1882  debugs(3, DBG_CRITICAL, "Parsing Config File: Corruption configuring authentication scheme '" << type_str << "'.");
1883  self_destruct();
1884  return;
1885  }
1886  }
1887 
1888  schemeCfg->parse(schemeCfg, config->size(), param_str);
1889 }
1890 
1891 static void
1893 {
1894  /* Wipe the Auth globals and Detach/Destruct component config + state. */
1895  cfg->clear();
1896 
1897  /* on reconfigure initialize new auth schemes for the new config. */
1898  if (reconfiguring) {
1899  Auth::Init();
1900  }
1901 }
1902 
1903 static void
1904 dump_authparam(StoreEntry * entry, const char *name, Auth::ConfigVector cfg)
1905 {
1906  for (auto *scheme : cfg)
1907  scheme->dump(entry, name, scheme);
1908 }
1909 
1910 static void
1912 {
1913  const char *tok = ConfigParser::NextQuotedToken();
1914  if (!tok) {
1915  debugs(29, DBG_CRITICAL, "FATAL: auth_schemes missing the parameter");
1916  self_destruct();
1917  return;
1918  }
1920  const auto action = Acl::Answer(ACCESS_ALLOWED, Auth::TheConfig.schemeLists.size() - 1);
1921  ParseAclWithAction(authSchemes, action, "auth_schemes");
1922 }
1923 
1924 static void
1926 {
1927  Auth::TheConfig.schemeLists.clear();
1928  free_acl_access(authSchemes);
1929 }
1930 
1931 static void
1932 dump_AuthSchemes(StoreEntry *entry, const char *name, acl_access *authSchemes)
1933 {
1934  if (authSchemes)
1935  dump_SBufList(entry, authSchemes->treeDump(name, [](const Acl::Answer &action) {
1936  return Auth::TheConfig.schemeLists.at(action.kind).rawSchemes;
1937  }));
1938 }
1939 
1940 #endif /* USE_AUTH */
1941 
1942 static void
1943 ParseAclWithAction(acl_access **access, const Acl::Answer &action, const char *desc, ACL *acl)
1944 {
1945  assert(access);
1946  SBuf name;
1947  if (!*access) {
1948  *access = new Acl::Tree;
1949  name.Printf("(%s rules)", desc);
1950  (*access)->context(name.c_str(), config_input_line);
1951  }
1952  Acl::AndNode *rule = new Acl::AndNode;
1953  name.Printf("(%s rule)", desc);
1954  rule->context(name.c_str(), config_input_line);
1955  acl ? rule->add(acl) : rule->lineParse();
1956  (*access)->add(rule, action);
1957 }
1958 
1959 static void
1961 {
1962  assert(swap);
1963  Store::Disks::Parse(*swap);
1964 }
1965 
1966 static const char *
1968 {
1969  const char * result;
1970 
1971  switch (type) {
1972 
1973  case PEER_PARENT:
1974  result = "parent";
1975  break;
1976 
1977  case PEER_SIBLING:
1978  result = "sibling";
1979  break;
1980 
1981  case PEER_MULTICAST:
1982  result = "multicast";
1983  break;
1984 
1985  default:
1986  result = "unknown";
1987  break;
1988  }
1989 
1990  return result;
1991 }
1992 
1993 static void
1994 dump_peer(StoreEntry * entry, const char *name, CachePeer * p)
1995 {
1997  LOCAL_ARRAY(char, xname, 128);
1998 
1999  while (p != NULL) {
2000  storeAppendPrintf(entry, "%s %s %s %d %d name=%s",
2001  name,
2002  p->host,
2003  neighborTypeStr(p),
2004  p->http_port,
2005  p->icp.port,
2006  p->name);
2007  dump_peer_options(entry, p);
2008 
2009  if (p->access) {
2010  snprintf(xname, 128, "cache_peer_access %s", p->name);
2011  dump_acl_access(entry, xname, p->access);
2012  }
2013 
2014  for (t = p->typelist; t; t = t->next) {
2015  storeAppendPrintf(entry, "neighbor_type_domain %s %s %s\n",
2016  p->host,
2017  peer_type_str(t->type),
2018  t->domain);
2019  }
2020 
2021  p = p->next;
2022  }
2023 }
2024 
2029 static bool
2030 isUnsignedNumeric(const char *str, size_t len)
2031 {
2032  if (len < 1) return false;
2033 
2034  for (; len >0 && *str; ++str, --len) {
2035  if (! isdigit(*str))
2036  return false;
2037  }
2038  return true;
2039 }
2040 
2045 static unsigned short
2046 GetService(const char *proto)
2047 {
2048  struct servent *port = NULL;
2050  char *token = ConfigParser::NextToken();
2051  if (token == NULL) {
2052  self_destruct();
2053  return 0; /* NEVER REACHED */
2054  }
2056  if ( !isUnsignedNumeric(token, strlen(token)) )
2057  port = getservbyname(token, proto);
2058  if (port != NULL) {
2059  return ntohs((unsigned short)port->s_port);
2060  }
2062  return xatos(token);
2063 }
2064 
2069 inline unsigned short
2071 {
2072  return GetService("tcp");
2073 }
2074 
2079 inline unsigned short
2081 {
2082  return GetService("udp");
2083 }
2084 
2085 static void
2087 {
2088  char *host_str = ConfigParser::NextToken();
2089  if (!host_str) {
2090  self_destruct();
2091  return;
2092  }
2093 
2094  char *token = ConfigParser::NextToken();
2095  if (!token) {
2096  self_destruct();
2097  return;
2098  }
2099 
2100  CachePeer *p = new CachePeer;
2101  p->host = xstrdup(host_str);
2102  Tolower(p->host);
2103  p->name = xstrdup(host_str);
2104  p->type = parseNeighborType(token);
2105 
2106  if (p->type == PEER_MULTICAST) {
2107  p->options.no_digest = true;
2108  p->options.no_netdb_exchange = true;
2109  }
2110 
2111  p->http_port = GetTcpService();
2112 
2113  if (!p->http_port) {
2114  delete p;
2115  self_destruct();
2116  return;
2117  }
2118 
2119  p->icp.port = GetUdpService();
2120 
2121  while ((token = ConfigParser::NextToken())) {
2122  if (!strcmp(token, "proxy-only")) {
2123  p->options.proxy_only = true;
2124  } else if (!strcmp(token, "no-query")) {
2125  p->options.no_query = true;
2126  } else if (!strcmp(token, "background-ping")) {
2127  p->options.background_ping = true;
2128  } else if (!strcmp(token, "no-digest")) {
2129  p->options.no_digest = true;
2130  } else if (!strcmp(token, "no-tproxy")) {
2131  p->options.no_tproxy = true;
2132  } else if (!strcmp(token, "multicast-responder")) {
2133  p->options.mcast_responder = true;
2134 #if PEER_MULTICAST_SIBLINGS
2135  } else if (!strcmp(token, "multicast-siblings")) {
2136  p->options.mcast_siblings = true;
2137 #endif
2138  } else if (!strncmp(token, "weight=", 7)) {
2139  p->weight = xatoi(token + 7);
2140  } else if (!strncmp(token, "basetime=", 9)) {
2141  p->basetime = xatoi(token + 9);
2142  } else if (!strcmp(token, "closest-only")) {
2143  p->options.closest_only = true;
2144  } else if (!strncmp(token, "ttl=", 4)) {
2145  p->mcast.ttl = xatoi(token + 4);
2146 
2147  if (p->mcast.ttl < 0)
2148  p->mcast.ttl = 0;
2149 
2150  if (p->mcast.ttl > 128)
2151  p->mcast.ttl = 128;
2152  } else if (!strcmp(token, "default")) {
2153  p->options.default_parent = true;
2154  } else if (!strcmp(token, "round-robin")) {
2155  p->options.roundrobin = true;
2156  } else if (!strcmp(token, "weighted-round-robin")) {
2157  p->options.weighted_roundrobin = true;
2158 #if USE_HTCP
2159  } else if (!strcmp(token, "htcp")) {
2160  p->options.htcp = true;
2161  } else if (!strncmp(token, "htcp=", 5) || !strncmp(token, "htcp-", 5)) {
2162  /* Note: The htcp- form is deprecated, replaced by htcp= */
2163  p->options.htcp = true;
2164  char *tmp = xstrdup(token+5);
2165  char *mode, *nextmode;
2166  for (mode = nextmode = tmp; mode; mode = nextmode) {
2167  nextmode = strchr(mode, ',');
2168  if (nextmode) {
2169  *nextmode = '\0';
2170  ++nextmode;
2171  }
2172  if (!strcmp(mode, "no-clr")) {
2173  if (p->options.htcp_only_clr)
2174  fatalf("parse_peer: can't set htcp-no-clr and htcp-only-clr simultaneously");
2175  p->options.htcp_no_clr = true;
2176  } else if (!strcmp(mode, "no-purge-clr")) {
2177  p->options.htcp_no_purge_clr = true;
2178  } else if (!strcmp(mode, "only-clr")) {
2179  if (p->options.htcp_no_clr)
2180  fatalf("parse_peer: can't set htcp no-clr and only-clr simultaneously");
2181  p->options.htcp_only_clr = true;
2182  } else if (!strcmp(mode, "forward-clr")) {
2183  p->options.htcp_forward_clr = true;
2184  } else if (!strcmp(mode, "oldsquid")) {
2185  p->options.htcp_oldsquid = true;
2186  } else {
2187  fatalf("invalid HTCP mode '%s'", mode);
2188  }
2189  }
2190  safe_free(tmp);
2191 #endif
2192  } else if (!strcmp(token, "no-netdb-exchange")) {
2193  p->options.no_netdb_exchange = true;
2194 
2195  } else if (!strcmp(token, "carp")) {
2196  if (p->type != PEER_PARENT)
2197  fatalf("parse_peer: non-parent carp peer %s/%d\n", p->host, p->http_port);
2198 
2199  p->options.carp = true;
2200  } else if (!strncmp(token, "carp-key=", 9)) {
2201  if (p->options.carp != true)
2202  fatalf("parse_peer: carp-key specified on non-carp peer %s/%d\n", p->host, p->http_port);
2203  p->options.carp_key.set = true;
2204  char *nextkey=token+strlen("carp-key="), *key=nextkey;
2205  for (; key; key = nextkey) {
2206  nextkey=strchr(key,',');
2207  if (nextkey) ++nextkey; // skip the comma, any
2208  if (0==strncmp(key,"scheme",6)) {
2209  p->options.carp_key.scheme = true;
2210  } else if (0==strncmp(key,"host",4)) {
2211  p->options.carp_key.host = true;
2212  } else if (0==strncmp(key,"port",4)) {
2213  p->options.carp_key.port = true;
2214  } else if (0==strncmp(key,"path",4)) {
2215  p->options.carp_key.path = true;
2216  } else if (0==strncmp(key,"params",6)) {
2217  p->options.carp_key.params = true;
2218  } else {
2219  fatalf("invalid carp-key '%s'",key);
2220  }
2221  }
2222  } else if (!strcmp(token, "userhash")) {
2223 #if USE_AUTH
2224  if (p->type != PEER_PARENT)
2225  fatalf("parse_peer: non-parent userhash peer %s/%d\n", p->host, p->http_port);
2226 
2227  p->options.userhash = true;
2228 #else
2229  fatalf("parse_peer: userhash requires authentication. peer %s/%d\n", p->host, p->http_port);
2230 #endif
2231  } else if (!strcmp(token, "sourcehash")) {
2232  if (p->type != PEER_PARENT)
2233  fatalf("parse_peer: non-parent sourcehash peer %s/%d\n", p->host, p->http_port);
2234 
2235  p->options.sourcehash = true;
2236 
2237  } else if (!strcmp(token, "no-delay")) {
2238 #if USE_DELAY_POOLS
2239  p->options.no_delay = true;
2240 #else
2241  debugs(0, DBG_CRITICAL, "WARNING: cache_peer option 'no-delay' requires --enable-delay-pools");
2242 #endif
2243  } else if (!strncmp(token, "login=", 6)) {
2244  p->login = xstrdup(token + 6);
2245  rfc1738_unescape(p->login);
2246  } else if (!strcmp(token, "auth-no-keytab")) {
2247  p->options.auth_no_keytab = 1;
2248  } else if (!strncmp(token, "connect-timeout=", 16)) {
2249  p->connect_timeout_raw = xatoi(token + 16);
2250  } else if (!strncmp(token, "connect-fail-limit=", 19)) {
2251  p->connect_fail_limit = xatoi(token + 19);
2252 #if USE_CACHE_DIGESTS
2253  } else if (!strncmp(token, "digest-url=", 11)) {
2254  p->digest_url = xstrdup(token + 11);
2255 #endif
2256 
2257  } else if (!strcmp(token, "allow-miss")) {
2258  p->options.allow_miss = true;
2259  } else if (!strncmp(token, "max-conn=", 9)) {
2260  p->max_conn = xatoi(token + 9);
2261  } else if (!strncmp(token, "standby=", 8)) {
2262  p->standby.limit = xatoi(token + 8);
2263  } else if (!strcmp(token, "originserver")) {
2264  p->options.originserver = true;
2265  } else if (!strncmp(token, "name=", 5)) {
2266  safe_free(p->name);
2267 
2268  if (token[5])
2269  p->name = xstrdup(token + 5);
2270  } else if (!strncmp(token, "forceddomain=", 13)) {
2271  safe_free(p->domain);
2272  if (token[13])
2273  p->domain = xstrdup(token + 13);
2274 
2275  } else if (strncmp(token, "ssl", 3) == 0) {
2276 #if !USE_OPENSSL
2277  debugs(0, DBG_CRITICAL, "WARNING: cache_peer option '" << token << "' requires --with-openssl");
2278 #else
2279  p->secure.parse(token+3);
2280 #endif
2281  } else if (strncmp(token, "tls-", 4) == 0) {
2282  p->secure.parse(token+4);
2283  } else if (strncmp(token, "tls", 3) == 0) {
2284  p->secure.parse(token+3);
2285  } else if (strcmp(token, "front-end-https") == 0) {
2286  p->front_end_https = 1;
2287  } else if (strcmp(token, "front-end-https=on") == 0) {
2288  p->front_end_https = 1;
2289  } else if (strcmp(token, "front-end-https=auto") == 0) {
2290  p->front_end_https = 2;
2291  } else if (strcmp(token, "connection-auth=off") == 0) {
2292  p->connection_auth = 0;
2293  } else if (strcmp(token, "connection-auth") == 0) {
2294  p->connection_auth = 1;
2295  } else if (strcmp(token, "connection-auth=on") == 0) {
2296  p->connection_auth = 1;
2297  } else if (strcmp(token, "connection-auth=auto") == 0) {
2298  p->connection_auth = 2;
2299  } else if (token[0] == '#') {
2300  // start of a text comment. stop reading this line.
2301  break;
2302  } else {
2303  debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: Ignoring unknown cache_peer option '" << token << "'");
2304  }
2305  }
2306 
2307  if (peerFindByName(p->name))
2308  fatalf("ERROR: cache_peer %s specified twice\n", p->name);
2309 
2310  if (p->max_conn > 0 && p->max_conn < p->standby.limit)
2311  fatalf("ERROR: cache_peer %s max-conn=%d is lower than its standby=%d\n", p->host, p->max_conn, p->standby.limit);
2312 
2313  if (p->weight < 1)
2314  p->weight = 1;
2315 
2316  if (p->connect_fail_limit < 1)
2317  p->connect_fail_limit = 10;
2318 
2319 #if USE_CACHE_DIGESTS
2320  if (!p->options.no_digest)
2321  peerDigestCreate(p);
2322 #endif
2323 
2324  if (p->secure.encryptTransport)
2325  p->secure.parseOptions();
2326 
2327  p->index = ++Config.npeers;
2328 
2329  while (*head != NULL)
2330  head = &(*head)->next;
2331 
2332  *head = p;
2333 
2334  peerClearRRStart();
2335 }
2336 
2337 static void
2339 {
2340  delete *P;
2341  *P = NULL;
2342  Config.npeers = 0;
2343 }
2344 
2345 static void
2346 dump_cachemgrpasswd(StoreEntry * entry, const char *name, Mgr::ActionPasswordList * list)
2347 {
2348  while (list) {
2349  if (strcmp(list->passwd, "none") && strcmp(list->passwd, "disable"))
2350  storeAppendPrintf(entry, "%s XXXXXXXXXX", name);
2351  else
2352  storeAppendPrintf(entry, "%s %s", name, list->passwd);
2353 
2354  for (auto w : list->actions)
2355  entry->appendf(" " SQUIDSBUFPH, SQUIDSBUFPRINT(w));
2356 
2357  storeAppendPrintf(entry, "\n");
2358  list = list->next;
2359  }
2360 }
2361 
2362 static void
2364 {
2365  char *passwd = nullptr;
2366  parse_string(&passwd);
2367 
2369  p->passwd = passwd;
2370 
2371  while (char *token = ConfigParser::NextQuotedToken())
2372  p->actions.push_back(SBuf(token));
2373 
2375  for (P = head; *P; P = &(*P)->next) {
2376  /*
2377  * See if any of the actions from this line already have a
2378  * password from previous lines. The password checking
2379  * routines in cache_manager.c take the the password from
2380  * the first Mgr::ActionPasswordList that contains the
2381  * requested action. Thus, we should warn users who might
2382  * think they can have two passwords for the same action.
2383  */
2384  for (const auto &w : (*P)->actions) {
2385  for (const auto &u : p->actions) {
2386  if (w != u)
2387  continue;
2388 
2389  debugs(0, DBG_PARSE_NOTE(1), "ERROR: action '" << u << "' (line " << config_lineno << ") already has a password");
2390  }
2391  }
2392  }
2393 
2394  *P = p;
2395 }
2396 
2397 static void
2399 {
2400  delete *head;
2401  *head = nullptr;
2402 }
2403 
2404 static void
2405 dump_denyinfo(StoreEntry * entry, const char *name, AclDenyInfoList * var)
2406 {
2407  while (var != NULL) {
2408  storeAppendPrintf(entry, "%s %s", name, var->err_page_name);
2409 
2410  for (const auto &aclName: var->acl_list)
2411  storeAppendPrintf(entry, " " SQUIDSBUFPH, SQUIDSBUFPRINT(aclName));
2412 
2413  storeAppendPrintf(entry, "\n");
2414 
2415  var = var->next;
2416  }
2417 }
2418 
2419 static void
2421 {
2422  aclParseDenyInfoLine(var);
2423 }
2424 
2425 void
2427 {
2428  delete *list;
2429  *list = nullptr;
2430 }
2431 
2432 static void
2434 {
2435  char *host = ConfigParser::NextToken();
2436  if (!host) {
2437  self_destruct();
2438  return;
2439  }
2440 
2441  CachePeer *p = peerFindByName(host);
2442  if (!p) {
2443  debugs(15, DBG_CRITICAL, "ERROR: " << cfg_filename << ", line " << config_lineno << ": No cache_peer '" << host << "'");
2444  return;
2445  }
2446 
2447  std::string directive = "peer_access ";
2448  directive += host;
2449  aclParseAccessLine(directive.c_str(), LegacyParser, &p->access);
2450 }
2451 
2452 static void
2454 {
2455  char *host = ConfigParser::NextToken();
2456  if (!host) {
2457  self_destruct();
2458  return;
2459  }
2460 
2461  char *type = ConfigParser::NextToken();
2462  if (!type) {
2463  self_destruct();
2464  return;
2465  }
2466 
2467  char *domain = nullptr;
2468  while ((domain = ConfigParser::NextToken())) {
2469  CachePeer *p = peerFindByName(host);
2470  if (!p) {
2471  debugs(15, DBG_CRITICAL, "" << cfg_filename << ", line " << config_lineno << ": No cache_peer '" << host << "'");
2472  return;
2473  }
2474 
2475  auto *l = static_cast<NeighborTypeDomainList *>(xcalloc(1, sizeof(NeighborTypeDomainList)));
2476  l->type = parseNeighborType(type);
2477  l->domain = xstrdup(domain);
2478 
2479  NeighborTypeDomainList **L = nullptr;
2480  for (L = &(p->typelist); *L; L = &((*L)->next));
2481  *L = l;
2482  }
2483 }
2484 
2485 static void
2486 dump_int(StoreEntry * entry, const char *name, int var)
2487 {
2488  storeAppendPrintf(entry, "%s %d\n", name, var);
2489 }
2490 
2491 void
2492 parse_int(int *var)
2493 {
2494  int i;
2495  i = GetInteger();
2496  *var = i;
2497 }
2498 
2499 static void
2500 free_int(int *var)
2501 {
2502  *var = 0;
2503 }
2504 
2505 static void
2506 dump_int64_t(StoreEntry * entry, const char *name, int64_t var)
2507 {
2508  storeAppendPrintf(entry, "%s %" PRId64 "\n", name, var);
2509 }
2510 
2511 void
2512 parse_int64_t(int64_t *var)
2513 {
2514  int64_t i;
2515  i = GetInteger64();
2516  *var = i;
2517 }
2518 
2519 static void
2520 free_int64_t(int64_t *var)
2521 {
2522  *var = 0;
2523 }
2524 
2525 static void
2526 dump_onoff(StoreEntry * entry, const char *name, int var)
2527 {
2528  storeAppendPrintf(entry, "%s %s\n", name, var ? "on" : "off");
2529 }
2530 
2531 void
2532 parse_onoff(int *var)
2533 {
2534  char *token = ConfigParser::NextToken();
2535  if (!token) {
2536  self_destruct();
2537  return;
2538  }
2539 
2540  if (!strcmp(token, "on")) {
2541  *var = 1;
2542  } else if (!strcmp(token, "enable")) {
2543  debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: 'enable' is deprecated. Please update to use 'on'.");
2544  *var = 1;
2545  } else if (!strcmp(token, "off")) {
2546  *var = 0;
2547  } else if (!strcmp(token, "disable")) {
2548  debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: 'disable' is deprecated. Please update to use 'off'.");
2549  *var = 0;
2550  } else {
2551  debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: Invalid option: Boolean options can only be 'on' or 'off'.");
2552  self_destruct();
2553  }
2554 }
2555 
2556 #define free_onoff free_int
2557 
2558 static void
2559 dump_tristate(StoreEntry * entry, const char *name, int var)
2560 {
2561  const char *state;
2562 
2563  if (var > 0)
2564  state = "on";
2565  else if (var < 0)
2566  state = "warn";
2567  else
2568  state = "off";
2569 
2570  storeAppendPrintf(entry, "%s %s\n", name, state);
2571 }
2572 
2573 static void
2575 {
2576  char *token = ConfigParser::NextToken();
2577  if (!token) {
2578  self_destruct();
2579  return;
2580  }
2581 
2582  if (!strcmp(token, "on")) {
2583  *var = 1;
2584  } else if (!strcmp(token, "enable")) {
2585  debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: 'enable' is deprecated. Please update to use value 'on'.");
2586  *var = 1;
2587  } else if (!strcmp(token, "warn")) {
2588  *var = -1;
2589  } else if (!strcmp(token, "off")) {
2590  *var = 0;
2591  } else if (!strcmp(token, "disable")) {
2592  debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: 'disable' is deprecated. Please update to use value 'off'.");
2593  *var = 0;
2594  } else {
2595  debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "ERROR: Invalid option: Tristate options can only be 'on', 'off', or 'warn'.");
2596  self_destruct();
2597  }
2598 }
2599 
2600 #define free_tristate free_int
2601 
2602 void
2604 {
2605  char *token = ConfigParser::PeekAtToken();
2606  if (!token) {
2607  self_destruct();
2608  return;
2609  }
2610 
2611  if (!strcmp(token, "on")) {
2612  debugs(0, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: 'pipeline_prefetch on' is deprecated. Please update to use 1 (or a higher number).");
2613  *var = 1;
2614  //pop the token
2615  (void)ConfigParser::NextToken();
2616  } else if (!strcmp(token, "off")) {
2617  debugs(0, DBG_PARSE_NOTE(2), "WARNING: 'pipeline_prefetch off' is deprecated. Please update to use '0'.");
2618  *var = 0;
2619  //pop the token
2620  (void)ConfigParser::NextToken();
2621  } else
2622  parse_int(var);
2623 }
2624 
2625 #define free_pipelinePrefetch free_int
2626 #define dump_pipelinePrefetch dump_int
2627 
2628 static void
2629 dump_refreshpattern(StoreEntry * entry, const char *name, RefreshPattern * head)
2630 {
2631  while (head != NULL) {
2632  storeAppendPrintf(entry, "%s%s %s %d %d%% %d",
2633  name,
2634  head->pattern.flags&REG_ICASE ? " -i" : null_string,
2635  head->pattern.c_str(),
2636  (int) head->min / 60,
2637  (int) (100.0 * head->pct + 0.5),
2638  (int) head->max / 60);
2639 
2640  if (head->max_stale >= 0)
2641  storeAppendPrintf(entry, " max-stale=%d", head->max_stale);
2642 
2643  if (head->flags.refresh_ims)
2644  storeAppendPrintf(entry, " refresh-ims");
2645 
2646  if (head->flags.store_stale)
2647  storeAppendPrintf(entry, " store-stale");
2648 
2649 #if USE_HTTP_VIOLATIONS
2650 
2651  if (head->flags.override_expire)
2652  storeAppendPrintf(entry, " override-expire");
2653 
2654  if (head->flags.override_lastmod)
2655  storeAppendPrintf(entry, " override-lastmod");
2656 
2657  if (head->flags.reload_into_ims)
2658  storeAppendPrintf(entry, " reload-into-ims");
2659 
2660  if (head->flags.ignore_reload)
2661  storeAppendPrintf(entry, " ignore-reload");
2662 
2663  if (head->flags.ignore_no_store)
2664  storeAppendPrintf(entry, " ignore-no-store");
2665 
2666  if (head->flags.ignore_private)
2667  storeAppendPrintf(entry, " ignore-private");
2668 #endif
2669 
2670  storeAppendPrintf(entry, "\n");
2671 
2672  head = head->next;
2673  }
2674 }
2675 
2676 static void
2678 {
2679  char *token;
2680  char *pattern;
2681  time_t min = 0;
2682  double pct = 0.0;
2683  time_t max = 0;
2684  int refresh_ims = 0;
2685  int store_stale = 0;
2686  int max_stale = -1;
2687 
2688 #if USE_HTTP_VIOLATIONS
2689 
2690  int override_expire = 0;
2691  int override_lastmod = 0;
2692  int reload_into_ims = 0;
2693  int ignore_reload = 0;
2694  int ignore_no_store = 0;
2695  int ignore_private = 0;
2696 #endif
2697 
2698  int i;
2699  RefreshPattern *t;
2700  regex_t comp;
2701  int errcode;
2702  int flags = REG_EXTENDED | REG_NOSUB;
2703 
2704  if ((token = ConfigParser::RegexPattern()) != NULL) {
2705 
2706  if (strcmp(token, "-i") == 0) {
2707  flags |= REG_ICASE;
2708  token = ConfigParser::RegexPattern();
2709  } else if (strcmp(token, "+i") == 0) {
2710  flags &= ~REG_ICASE;
2711  token = ConfigParser::RegexPattern();
2712  }
2713 
2714  }
2715 
2716  if (token == NULL) {
2717  debugs(3, DBG_CRITICAL, "FATAL: refresh_pattern missing the regex pattern parameter");
2718  self_destruct();
2719  return;
2720  }
2721 
2722  pattern = xstrdup(token);
2723 
2724  i = GetInteger(); /* token: min */
2725 
2726  /* catch negative and insanely huge values close to 32-bit wrap */
2727  if (i < 0) {
2728  debugs(3, DBG_IMPORTANT, "WARNING: refresh_pattern minimum age negative. Cropped back to zero.");
2729  i = 0;
2730  }
2731  if (i > 60*24*365) {
2732  debugs(3, DBG_IMPORTANT, "WARNING: refresh_pattern minimum age too high. Cropped back to 1 year.");
2733  i = 60*24*365;
2734  }
2735 
2736  min = (time_t) (i * 60); /* convert minutes to seconds */
2737 
2738  pct = GetPercentage(false); /* token: pct . with no limit on size */
2739 
2740  i = GetInteger(); /* token: max */
2741 
2742  /* catch negative and insanely huge values close to 32-bit wrap */
2743  if (i < 0) {
2744  debugs(3, DBG_IMPORTANT, "WARNING: refresh_pattern maximum age negative. Cropped back to zero.");
2745  i = 0;
2746  }
2747  if (i > 60*24*365) {
2748  debugs(3, DBG_IMPORTANT, "WARNING: refresh_pattern maximum age too high. Cropped back to 1 year.");
2749  i = 60*24*365;
2750  }
2751 
2752  max = (time_t) (i * 60); /* convert minutes to seconds */
2753 
2754  /* Options */
2755  while ((token = ConfigParser::NextToken()) != NULL) {
2756  if (!strcmp(token, "refresh-ims")) {
2757  refresh_ims = 1;
2758  } else if (!strcmp(token, "store-stale")) {
2759  store_stale = 1;
2760  } else if (!strncmp(token, "max-stale=", 10)) {
2761  max_stale = xatoi(token + 10);
2762 
2763 #if USE_HTTP_VIOLATIONS
2764 
2765  } else if (!strcmp(token, "override-expire"))
2766  override_expire = 1;
2767  else if (!strcmp(token, "override-lastmod"))
2768  override_lastmod = 1;
2769  else if (!strcmp(token, "ignore-no-store"))
2770  ignore_no_store = 1;
2771  else if (!strcmp(token, "ignore-private"))
2772  ignore_private = 1;
2773  else if (!strcmp(token, "reload-into-ims")) {
2774  reload_into_ims = 1;
2776  /* tell client_side.c that this is used */
2777  } else if (!strcmp(token, "ignore-reload")) {
2778  ignore_reload = 1;
2780  /* tell client_side.c that this is used */
2781 #endif
2782 
2783  } else if (!strcmp(token, "ignore-no-cache") ||
2784  !strcmp(token, "ignore-must-revalidate") ||
2785  !strcmp(token, "ignore-auth")
2786  ) {
2787  debugs(22, DBG_PARSE_NOTE(2), "UPGRADE: refresh_pattern option '" << token << "' is obsolete. Remove it.");
2788  } else
2789  debugs(22, DBG_CRITICAL, "refreshAddToList: Unknown option '" << pattern << "': " << token);
2790  }
2791 
2792  if ((errcode = regcomp(&comp, pattern, flags)) != 0) {
2793  char errbuf[256];
2794  regerror(errcode, &comp, errbuf, sizeof errbuf);
2795  debugs(22, DBG_CRITICAL, "" << cfg_filename << " line " << config_lineno << ": " << config_input_line);
2796  debugs(22, DBG_CRITICAL, "refreshAddToList: Invalid regular expression '" << pattern << "': " << errbuf);
2797  xfree(pattern);
2798  return;
2799  }
2800 
2801  pct = pct < 0.0 ? 0.0 : pct;
2802  max = max < 0 ? 0 : max;
2803  t = new RefreshPattern(pattern, flags);
2804  t->pattern.regex = comp;
2805  t->min = min;
2806  t->pct = pct;
2807  t->max = max;
2808 
2809  if (refresh_ims)
2810  t->flags.refresh_ims = true;
2811 
2812  if (store_stale)
2813  t->flags.store_stale = true;
2814 
2815  t->max_stale = max_stale;
2816 
2817 #if USE_HTTP_VIOLATIONS
2818 
2819  if (override_expire)
2820  t->flags.override_expire = true;
2821 
2822  if (override_lastmod)
2823  t->flags.override_lastmod = true;
2824 
2825  if (reload_into_ims)
2826  t->flags.reload_into_ims = true;
2827 
2828  if (ignore_reload)
2829  t->flags.ignore_reload = true;
2830 
2831  if (ignore_no_store)
2832  t->flags.ignore_no_store = true;
2833 
2834  if (ignore_private)
2835  t->flags.ignore_private = true;
2836 #endif
2837 
2838  t->next = NULL;
2839 
2840  while (*head)
2841  head = &(*head)->next;
2842 
2843  *head = t;
2844 
2845  xfree(pattern);
2846 }
2847 
2848 static void
2850 {
2851  delete *head;
2852  *head = nullptr;
2853 
2854 #if USE_HTTP_VIOLATIONS
2856 
2857 #endif
2858 }
2859 
2860 static void
2861 dump_string(StoreEntry * entry, const char *name, char *var)
2862 {
2863  if (var != NULL)
2864  storeAppendPrintf(entry, "%s %s\n", name, var);
2865 }
2866 
2867 static void
2868 parse_string(char **var)
2869 {
2870  safe_free(*var);
2871 
2872  char *token = ConfigParser::NextToken();
2873  if (!token) {
2874  self_destruct();
2875  return;
2876  }
2877 
2878  *var = xstrdup(token);
2879 }
2880 
2881 static void
2882 free_string(char **var)
2883 {
2884  safe_free(*var);
2885 }
2886 
2887 void
2888 parse_eol(char *volatile *var)
2889 {
2890  if (!var) {
2891  self_destruct();
2892  return;
2893  }
2894 
2895  unsigned char *token = (unsigned char *) ConfigParser::NextQuotedOrToEol();
2896  safe_free(*var);
2897 
2898  if (!token) {
2899  self_destruct();
2900  return;
2901  }
2902 
2903  while (*token && xisspace(*token))
2904  ++token;
2905 
2906  if (!*token) {
2907  self_destruct();
2908  return;
2909  }
2910 
2911  *var = xstrdup((char *) token);
2912 }
2913 
2914 #define dump_eol dump_string
2915 #define free_eol free_string
2916 
2917 static void
2919 {
2920  safe_free(*var);
2921 
2922  char *token = ConfigParser::NextQuotedToken();
2923  if (!token) {
2924  self_destruct();
2925  return;
2926  }
2927 
2928  *var = xstrdup(token);
2929 }
2930 
2931 #define dump_TokenOrQuotedString dump_string
2932 #define free_TokenOrQuotedString free_string
2933 
2934 static void
2935 dump_time_t(StoreEntry * entry, const char *name, time_t var)
2936 {
2937  storeAppendPrintf(entry, "%s %d seconds\n", name, (int) var);
2938 }
2939 
2940 void
2941 parse_time_t(time_t * var)
2942 {
2943  const auto maxTime = std::numeric_limits<time_t>::max();
2944  const auto seconds = parseTimeLine<std::chrono::seconds>();
2945  if (maxTime < seconds.count())
2946  throw TexcHere(ToSBuf("directive supports time values up to ", maxTime, " but is given ", seconds.count(), " seconds"));
2947  *var = static_cast<time_t>(seconds.count());
2948 }
2949 
2950 static void
2951 free_time_t(time_t * var)
2952 {
2953  *var = 0;
2954 }
2955 
2956 static void
2957 dump_time_msec(StoreEntry * entry, const char *name, time_msec_t var)
2958 {
2959  if (var % 1000)
2960  storeAppendPrintf(entry, "%s %" PRId64 " milliseconds\n", name, var);
2961  else
2962  storeAppendPrintf(entry, "%s %d seconds\n", name, (int)(var/1000) );
2963 }
2964 
2965 void
2967 {
2968  *var = parseTimeLine<std::chrono::milliseconds>().count();
2969 }
2970 
2971 static void
2973 {
2974  *var = 0;
2975 }
2976 
2977 static void
2978 dump_time_nanoseconds(StoreEntry *entry, const char *name, const std::chrono::nanoseconds &var)
2979 {
2980  // std::chrono::nanoseconds::rep is unknown a priori so we cast to (and print) the largest supported integer
2981  storeAppendPrintf(entry, "%s %jd nanoseconds\n", name, static_cast<intmax_t>(var.count()));
2982 }
2983 
2984 static void
2985 parse_time_nanoseconds(std::chrono::nanoseconds *var)
2986 {
2987  *var = parseTimeLine<std::chrono::nanoseconds>();
2988 }
2989 
2990 static void
2991 free_time_nanoseconds(std::chrono::nanoseconds *var)
2992 {
2993  *var = std::chrono::nanoseconds::zero();
2994 }
2995 
2996 #if UNUSED_CODE
2997 static void
2998 dump_size_t(StoreEntry * entry, const char *name, size_t var)
2999 {
3000  storeAppendPrintf(entry, "%s %d\n", name, (int) var);
3001 }
3002 #endif
3003 
3004 static void
3005 dump_b_size_t(StoreEntry * entry, const char *name, size_t var)
3006 {
3007  storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_BYTES_STR);
3008 }
3009 
3010 static void
3011 dump_b_ssize_t(StoreEntry * entry, const char *name, ssize_t var)
3012 {
3013  storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_BYTES_STR);
3014 }
3015 
3016 #if UNUSED_CODE
3017 static void
3018 dump_kb_size_t(StoreEntry * entry, const char *name, size_t var)
3019 {
3020  storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_KBYTES_STR);
3021 }
3022 #endif
3023 
3024 static void
3025 dump_b_int64_t(StoreEntry * entry, const char *name, int64_t var)
3026 {
3027  storeAppendPrintf(entry, "%s %" PRId64 " %s\n", name, var, B_BYTES_STR);
3028 }
3029 
3030 static void
3031 dump_kb_int64_t(StoreEntry * entry, const char *name, int64_t var)
3032 {
3033  storeAppendPrintf(entry, "%s %" PRId64 " %s\n", name, var, B_KBYTES_STR);
3034 }
3035 
3036 #if UNUSED_CODE
3037 static void
3038 parse_size_t(size_t * var)
3039 {
3040  int i;
3041  i = GetInteger();
3042  *var = (size_t) i;
3043 }
3044 #endif
3045 
3046 static void
3047 parse_b_size_t(size_t * var)
3048 {
3050 }
3051 
3052 static void
3053 parse_b_ssize_t(ssize_t * var)
3054 {
3056 }
3057 
3058 #if UNUSED_CODE
3059 static void
3060 parse_kb_size_t(size_t * var)
3061 {
3063 }
3064 #endif
3065 
3066 static void
3067 parse_b_int64_t(int64_t * var)
3068 {
3070 }
3071 
3072 static void
3073 parse_kb_int64_t(int64_t * var)
3074 {
3076 }
3077 
3078 static void
3079 free_size_t(size_t * var)
3080 {
3081  *var = 0;
3082 }
3083 
3084 static void
3085 free_ssize_t(ssize_t * var)
3086 {
3087  *var = 0;
3088 }
3089 
3090 static void
3091 free_b_int64_t(int64_t * var)
3092 {
3093  *var = 0;
3094 }
3095 
3096 #define free_b_size_t free_size_t
3097 #define free_b_ssize_t free_ssize_t
3098 #define free_kb_size_t free_size_t
3099 #define free_mb_size_t free_size_t
3100 #define free_gb_size_t free_size_t
3101 #define free_kb_int64_t free_b_int64_t
3102 
3103 static void
3104 dump_u_short(StoreEntry * entry, const char *name, unsigned short var)
3105 {
3106  storeAppendPrintf(entry, "%s %d\n", name, var);
3107 }
3108 
3109 static void
3110 free_u_short(unsigned short * u)
3111 {
3112  *u = 0;
3113 }
3114 
3115 static void
3116 parse_u_short(unsigned short * var)
3117 {
3119 }
3120 
3121 void
3122 ConfigParser::ParseUShort(unsigned short *var)
3123 {
3124  *var = GetShort();
3125 }
3126 
3127 void
3129 {
3130  int i = GetInteger();
3131 
3132  if (0 == i)
3133  *var = false;
3134  else if (1 == i)
3135  *var = true;
3136  else
3137  self_destruct();
3138 }
3139 
3140 static void
3141 dump_wordlist(StoreEntry * entry, const char *name, wordlist * list)
3142 {
3143  while (list != NULL) {
3144  storeAppendPrintf(entry, "%s %s\n", name, list->key);
3145  list = list->next;
3146  }
3147 }
3148 
3149 void
3151 {
3152  parse_wordlist(list);
3153 }
3154 
3155 void
3157 {
3158  char *token;
3159  while ((token = ConfigParser::NextQuotedToken()))
3160  wordlistAdd(list, token);
3161 }
3162 
3163 #if 0 /* now unused */
3164 static int
3165 check_null_wordlist(wordlist * w)
3166 {
3167  return w == NULL;
3168 }
3169 #endif
3170 
3171 static int
3173 {
3174  return a == NULL;
3175 }
3176 
3177 #define free_wordlist wordlistDestroy
3178 
3179 #define free_uri_whitespace free_int
3180 
3181 static void
3183 {
3184  char *token = ConfigParser::NextToken();
3185  if (!token) {
3186  self_destruct();
3187  return;
3188  }
3189 
3190  if (!strcmp(token, "strip"))
3191  *var = URI_WHITESPACE_STRIP;
3192  else if (!strcmp(token, "deny"))
3193  *var = URI_WHITESPACE_DENY;
3194  else if (!strcmp(token, "allow"))
3195  *var = URI_WHITESPACE_ALLOW;
3196  else if (!strcmp(token, "encode"))
3197  *var = URI_WHITESPACE_ENCODE;
3198  else if (!strcmp(token, "chop"))
3199  *var = URI_WHITESPACE_CHOP;
3200  else {
3201  debugs(0, DBG_PARSE_NOTE(2), "ERROR: Invalid option '" << token << "': 'uri_whitespace' accepts 'strip', 'deny', 'allow', 'encode', and 'chop'.");
3202  self_destruct();
3203  }
3204 }
3205 
3206 static void
3207 dump_uri_whitespace(StoreEntry * entry, const char *name, int var)
3208 {
3209  const char *s;
3210 
3211  if (var == URI_WHITESPACE_ALLOW)
3212  s = "allow";
3213  else if (var == URI_WHITESPACE_ENCODE)
3214  s = "encode";
3215  else if (var == URI_WHITESPACE_CHOP)
3216  s = "chop";
3217  else if (var == URI_WHITESPACE_DENY)
3218  s = "deny";
3219  else
3220  s = "strip";
3221 
3222  storeAppendPrintf(entry, "%s %s\n", name, s);
3223 }
3224 
3225 static void
3227 {
3228  if (!*settings)
3229  return;
3230 
3231  free_string(&(*settings)->type);
3232 
3233  free_wordlist(&(*settings)->args);
3234 
3235  delete *settings;
3236 
3237  *settings = NULL;
3238 }
3239 
3240 static void
3242 {
3243  if (*settings)
3244  free_removalpolicy(settings);
3245 
3246  *settings = new RemovalPolicySettings;
3247 
3248  parse_string(&(*settings)->type);
3249 
3250  parse_wordlist(&(*settings)->args);
3251 }
3252 
3253 static void
3254 dump_removalpolicy(StoreEntry * entry, const char *name, RemovalPolicySettings * settings)
3255 {
3256  wordlist *args;
3257  storeAppendPrintf(entry, "%s %s", name, settings->type);
3258  args = settings->args;
3259 
3260  while (args) {
3261  storeAppendPrintf(entry, " %s", args->key);
3262  args = args->next;
3263  }
3264 
3265  storeAppendPrintf(entry, "\n");
3266 }
3267 
3268 inline void
3270 {}
3271 
3272 static void
3274 {
3275  int value = 0;
3276  parse_onoff(&value);
3277  option->configure(value > 0);
3278 }
3279 
3280 static void
3281 dump_YesNoNone(StoreEntry * entry, const char *name, YesNoNone &option)
3282 {
3283  if (option.configured())
3284  dump_onoff(entry, name, option ? 1 : 0);
3285 }
3286 
3287 static void
3289 {}
3290 
3291 static void
3293 {
3294  char *token = ConfigParser::NextToken();
3295  if (!token) {
3296  self_destruct();
3297  return;
3298  }
3299 
3300  if (strcmp(token, "always") == 0) {
3303  } else if (strcmp(token, "disk") == 0) {
3306  } else if (strncmp(token, "net", 3) == 0) {
3309  } else if (strcmp(token, "never") == 0) {
3312  } else {
3313  debugs(0, DBG_PARSE_NOTE(2), "ERROR: Invalid option '" << token << "': 'memory_cache_mode' accepts 'always', 'disk', 'network', and 'never'.");
3314  self_destruct();
3315  }
3316 }
3317 
3318 static void
3319 dump_memcachemode(StoreEntry * entry, const char *name, SquidConfig &)
3320 {
3321  storeAppendPrintf(entry, "%s ", name);
3323  storeAppendPrintf(entry, "always");
3325  storeAppendPrintf(entry, "disk");
3327  storeAppendPrintf(entry, "network");
3329  storeAppendPrintf(entry, "none");
3330  storeAppendPrintf(entry, "\n");
3331 }
3332 
3333 #include "cf_parser.cci"
3334 
3335 peer_t
3336 parseNeighborType(const char *s)
3337 {
3338  if (!strcmp(s, "parent"))
3339  return PEER_PARENT;
3340 
3341  if (!strcmp(s, "neighbor"))
3342  return PEER_SIBLING;
3343 
3344  if (!strcmp(s, "neighbour"))
3345  return PEER_SIBLING;
3346 
3347  if (!strcmp(s, "sibling"))
3348  return PEER_SIBLING;
3349 
3350  if (!strcmp(s, "multicast"))
3351  return PEER_MULTICAST;
3352 
3353  debugs(15, DBG_CRITICAL, "WARNING: Unknown neighbor type: " << s);
3354 
3355  return PEER_SIBLING;
3356 }
3357 
3358 #if USE_WCCPv2
3359 static void
3361 {
3362  char *token;
3363  Ip::Address_list *s;
3364  Ip::Address ipa;
3365 
3366  while ((token = ConfigParser::NextToken())) {
3367  if (GetHostWithPort(token, &ipa)) {
3368 
3369  while (*head)
3370  head = &(*head)->next;
3371 
3372  s = static_cast<Ip::Address_list *>(xcalloc(1, sizeof(*s)));
3373  s->s = ipa;
3374 
3375  *head = s;
3376  } else {
3377  self_destruct();
3378  return;
3379  }
3380  }
3381 }
3382 
3383 static void
3384 dump_IpAddress_list(StoreEntry * e, const char *n, const Ip::Address_list * s)
3385 {
3386  char ntoabuf[MAX_IPSTRLEN];
3387 
3388  while (s) {
3389  storeAppendPrintf(e, "%s %s\n",
3390  n,
3391  s->s.toStr(ntoabuf,MAX_IPSTRLEN));
3392  s = s->next;
3393  }
3394 }
3395 
3396 static void
3398 {
3399  if (*head) delete *head;
3400  *head = NULL;
3401 }
3402 
3403 #if CURRENTLY_UNUSED
3404 /* This code was previously used by http_port. Left as it really should
3405  * be used by icp_port and htcp_port
3406  */
3407 static int
3408 check_null_IpAddress_list(const Ip::Address_list * s)
3409 {
3410  return NULL == s;
3411 }
3412 
3413 #endif /* CURRENTLY_UNUSED */
3414 #endif /* USE_WCCPv2 */
3415 
3416 static void
3418 {
3419  char *host = NULL;
3420  unsigned short port = 0;
3421  char *t = NULL;
3422  char *junk = NULL;
3423 
3424  s->disable_pmtu_discovery = DISABLE_PMTU_OFF;
3425  s->name = xstrdup(token);
3426  s->connection_auth_disabled = false;
3427 
3428  const SBuf &portType = AnyP::UriScheme(s->transport.protocol).image();
3429 
3430  if (*token == '[') {
3431  /* [ipv6]:port */
3432  host = token + 1;
3433  t = strchr(host, ']');
3434  if (!t) {
3435  debugs(3, DBG_CRITICAL, "FATAL: " << portType << "_port: missing ']' on IPv6 address: " << token);
3436  self_destruct();
3437  return;
3438  }
3439  *t = '\0';
3440  ++t;
3441  if (*t != ':') {
3442  debugs(3, DBG_CRITICAL, "FATAL: " << portType << "_port: missing Port in: " << token);
3443  self_destruct();
3444  return;
3445  }
3446  if (!Ip::EnableIpv6) {
3447  debugs(3, DBG_CRITICAL, "FATAL: " << portType << "_port: IPv6 is not available.");
3448  self_destruct();
3449  return;
3450  }
3451  port = xatos(t + 1);
3452  } else if ((t = strchr(token, ':'))) {
3453  /* host:port */
3454  /* ipv4:port */
3455  host = token;
3456  *t = '\0';
3457  port = xatos(t + 1);
3458 
3459  } else if (strtol(token, &junk, 10) && !*junk) {
3460  port = xatos(token);
3461  debugs(3, 3, portType << "_port: found Listen on Port: " << port);
3462  } else {
3463  debugs(3, DBG_CRITICAL, "FATAL: " << portType << "_port: missing Port: " << token);
3464  self_destruct();
3465  return;
3466  }
3467 
3468  if (port == 0 && host != NULL) {
3469  debugs(3, DBG_CRITICAL, "FATAL: " << portType << "_port: Port cannot be 0: " << token);
3470  self_destruct();
3471  return;
3472  }
3473 
3474  if (NULL == host) {
3475  s->s.setAnyAddr();
3476  s->s.port(port);
3477  if (!Ip::EnableIpv6)
3478  s->s.setIPv4();
3479  debugs(3, 3, portType << "_port: found Listen on wildcard address: *:" << s->s.port());
3480  } else if ( (s->s = host) ) { /* check/parse numeric IPA */
3481  s->s.port(port);
3482  if (!Ip::EnableIpv6)
3483  s->s.setIPv4();
3484  debugs(3, 3, portType << "_port: Listen on Host/IP: " << host << " --> " << s->s);
3485  } else if ( s->s.GetHostByName(host) ) { /* check/parse for FQDN */
3486  /* do not use ipcache */
3487  s->defaultsite = xstrdup(host);
3488  s->s.port(port);
3489  if (!Ip::EnableIpv6)
3490  s->s.setIPv4();
3491  debugs(3, 3, portType << "_port: found Listen as Host " << s->defaultsite << " on IP: " << s->s);
3492  } else {
3493  debugs(3, DBG_CRITICAL, "FATAL: " << portType << "_port: failed to resolve Host/IP: " << host);
3494  self_destruct();
3495  }
3496 }
3497 
3501 static AnyP::ProtocolVersion
3503 {
3504  // HTTP/1.0 not supported because we are version 1.1 which contains a superset of 1.0
3505  // and RFC 2616 requires us to upgrade 1.0 to 1.1
3506  if (value.cmp("HTTP") == 0 || value.cmp("HTTP/1.1") == 0)
3507  return Http::ProtocolVersion(1,1);
3508 
3509  if (value.cmp("HTTPS") == 0 || value.cmp("HTTPS/1.1") == 0)
3511 
3512  if (value.cmp("FTP") == 0)
3513  return Ftp::ProtocolVersion();
3514 
3515  fatalf("%s directive does not support protocol=" SQUIDSBUFPH "\n", cfg_directive, SQUIDSBUFPRINT(value));
3516  return AnyP::ProtocolVersion(); // not reached
3517 }
3518 
3519 static void
3521 {
3522  /* modes first */
3523 
3524  if (strcmp(token, "accel") == 0) {
3525  if (s->flags.isIntercepted()) {
3526  debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": Accelerator mode requires its own port. It cannot be shared with other modes.");
3527  self_destruct();
3528  return;
3529  }
3530  s->flags.accelSurrogate = true;
3531  s->vhost = true;
3532  } else if (strcmp(token, "transparent") == 0 || strcmp(token, "intercept") == 0) {
3533  if (s->flags.accelSurrogate || s->flags.tproxyIntercept) {
3534  debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": Intercept mode requires its own interception port. It cannot be shared with other modes.");
3535  self_destruct();
3536  return;
3537  }
3538  s->flags.natIntercept = true;
3540  /* Log information regarding the port modes under interception. */
3541  debugs(3, DBG_IMPORTANT, "Starting Authentication on port " << s->s);
3542  debugs(3, DBG_IMPORTANT, "Disabling Authentication on port " << s->s << " (interception enabled)");
3543  } else if (strcmp(token, "tproxy") == 0) {
3544  if (s->flags.natIntercept || s->flags.accelSurrogate) {
3545  debugs(3,DBG_CRITICAL, "FATAL: " << cfg_directive << ": TPROXY option requires its own interception port. It cannot be shared with other modes.");
3546  self_destruct();
3547  return;
3548  }
3549  s->flags.tproxyIntercept = true;
3551  /* Log information regarding the port modes under transparency. */
3552  debugs(3, DBG_IMPORTANT, "Disabling Authentication on port " << s->s << " (TPROXY enabled)");
3553 
3554  if (s->flags.proxySurrogate) {
3555  debugs(3, DBG_IMPORTANT, "Disabling TPROXY Spoofing on port " << s->s << " (require-proxy-header enabled)");
3556  }
3557 
3558  if (!Ip::Interceptor.ProbeForTproxy(s->s)) {
3559  debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": TPROXY support in the system does not work.");
3560  self_destruct();
3561  return;
3562  }
3563 
3564  } else if (strcmp(token, "require-proxy-header") == 0) {
3565  s->flags.proxySurrogate = true;
3566  if (s->flags.tproxyIntercept) {
3567  // receiving is still permitted, so we do not unset the TPROXY flag
3568  // spoofing access control override takes care of the spoof disable later
3569  debugs(3, DBG_IMPORTANT, "Disabling TPROXY Spoofing on port " << s->s << " (require-proxy-header enabled)");
3570  }
3571 
3572  } else if (strncmp(token, "defaultsite=", 12) == 0) {
3573  if (!s->flags.accelSurrogate) {
3574  debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": defaultsite option requires Acceleration mode flag.");
3575  self_destruct();
3576  return;
3577  }
3578  safe_free(s->defaultsite);
3579  s->defaultsite = xstrdup(token + 12);
3580  } else if (strcmp(token, "vhost") == 0) {
3581  if (!s->flags.accelSurrogate) {
3582  debugs(3, DBG_CRITICAL, "WARNING: " << cfg_directive << ": vhost option is deprecated. Use 'accel' mode flag instead.");
3583  }
3584  s->flags.accelSurrogate = true;
3585  s->vhost = true;
3586  } else if (strcmp(token, "no-vhost") == 0) {
3587  if (!s->flags.accelSurrogate) {
3588  debugs(3, DBG_IMPORTANT, "ERROR: " << cfg_directive << ": no-vhost option requires Acceleration mode flag.");
3589  }
3590  s->vhost = false;
3591  } else if (strcmp(token, "vport") == 0) {
3592  if (!s->flags.accelSurrogate) {
3593  debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": vport option requires Acceleration mode flag.");
3594  self_destruct();
3595  return;
3596  }
3597  s->vport = -1;
3598  } else if (strncmp(token, "vport=", 6) == 0) {
3599  if (!s->flags.accelSurrogate) {
3600  debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": vport option requires Acceleration mode flag.");
3601  self_destruct();
3602  return;
3603  }
3604  s->vport = xatos(token + 6);
3605  } else if (strncmp(token, "protocol=", 9) == 0) {
3606  if (!s->flags.accelSurrogate) {
3607  debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": protocol option requires Acceleration mode flag.");
3608  self_destruct();
3609  return;
3610  }
3611  s->transport = parsePortProtocol(ToUpper(SBuf(token + 9)));
3612  } else if (strcmp(token, "allow-direct") == 0) {
3613  if (!s->flags.accelSurrogate) {
3614  debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": allow-direct option requires Acceleration mode flag.");
3615  self_destruct();
3616  return;
3617  }
3618  s->allow_direct = true;
3619  } else if (strcmp(token, "act-as-origin") == 0) {
3620  if (!s->flags.accelSurrogate) {
3621  debugs(3, DBG_IMPORTANT, "ERROR: " << cfg_directive << ": act-as-origin option requires Acceleration mode flag.");
3622  } else
3623  s->actAsOrigin = true;
3624  } else if (strcmp(token, "ignore-cc") == 0) {
3625 #if !USE_HTTP_VIOLATIONS
3626  if (!s->flags.accelSurrogate) {
3627  debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": ignore-cc option requires Acceleration mode flag.");
3628  self_destruct();
3629  return;
3630  }
3631 #endif
3632  s->ignore_cc = true;
3633  } else if (strncmp(token, "name=", 5) == 0) {
3634  safe_free(s->name);
3635  s->name = xstrdup(token + 5);
3636  } else if (strcmp(token, "no-connection-auth") == 0) {
3637  s->connection_auth_disabled = true;
3638  } else if (strcmp(token, "connection-auth=off") == 0) {
3639  s->connection_auth_disabled = true;
3640  } else if (strcmp(token, "connection-auth") == 0) {
3641  s->connection_auth_disabled = false;
3642  } else if (strcmp(token, "connection-auth=on") == 0) {
3643  s->connection_auth_disabled = false;
3644  } else if (strncmp(token, "disable-pmtu-discovery=", 23) == 0) {
3645  if (!strcmp(token + 23, "off"))
3646  s->disable_pmtu_discovery = DISABLE_PMTU_OFF;
3647  else if (!strcmp(token + 23, "transparent"))
3648  s->disable_pmtu_discovery = DISABLE_PMTU_TRANSPARENT;
3649  else if (!strcmp(token + 23, "always"))
3650  s->disable_pmtu_discovery = DISABLE_PMTU_ALWAYS;
3651  else {
3652  self_destruct();
3653  return;
3654  }
3655  } else if (strcmp(token, "ipv4") == 0) {
3656  if ( !s->s.setIPv4() ) {
3657  debugs(3, DBG_CRITICAL, "FATAL: " << cfg_directive << ": IPv6 addresses cannot be used as IPv4-Only. " << s->s );
3658  self_destruct();
3659  return;
3660  }
3661  } else if (strcmp(token, "tcpkeepalive") == 0) {
3662  s->tcp_keepalive.enabled = true;
3663  } else if (strncmp(token, "tcpkeepalive=", 13) == 0) {
3664  char *t = token + 13;
3665  s->tcp_keepalive.enabled = true;
3666  s->tcp_keepalive.idle = xatoui(t,',');
3667  t = strchr(t, ',');
3668  if (t) {
3669  ++t;
3670  s->tcp_keepalive.interval = xatoui(t,',');
3671  t = strchr(t, ',');
3672  }
3673  if (t) {
3674  ++t;
3675  s->tcp_keepalive.timeout = xatoui(t);
3676  }
3677 #if USE_OPENSSL
3678  } else if (strcmp(token, "sslBump") == 0) {
3679  debugs(3, DBG_PARSE_NOTE(1), "WARNING: '" << token << "' is deprecated " <<
3680  "in " << cfg_directive << ". Use 'ssl-bump' instead.");
3681  s->flags.tunnelSslBumping = true;
3682  } else if (strcmp(token, "ssl-bump") == 0) {
3683  s->flags.tunnelSslBumping = true;
3684  } else if (strncmp(token, "cert=", 5) == 0) {
3685  s->secure.parse(token);
3686  } else if (strncmp(token, "key=", 4) == 0) {
3687  s->secure.parse(token);
3688  } else if (strncmp(token, "version=", 8) == 0) {
3689  debugs(3, DBG_PARSE_NOTE(1), "UPGRADE WARNING: '" << token << "' is deprecated " <<
3690  "in " << cfg_directive << ". Use 'options=' instead.");
3691  s->secure.parse(token);
3692  } else if (strncmp(token, "options=", 8) == 0) {
3693  s->secure.parse(token);
3694  } else if (strncmp(token, "cipher=", 7) == 0) {
3695  s->secure.parse(token);
3696  } else if (strncmp(token, "clientca=", 9) == 0) {
3697  s->secure.parse(token);
3698  } else if (strncmp(token, "cafile=", 7) == 0) {
3699  debugs(3, DBG_PARSE_NOTE(1), "UPGRADE WARNING: '" << token << "' is deprecated " <<
3700  "in " << cfg_directive << ". Use 'tls-cafile=' instead.");
3701  s->secure.parse(token);
3702  } else if (strncmp(token, "capath=", 7) == 0) {
3703  s->secure.parse(token);
3704  } else if (strncmp(token, "crlfile=", 8) == 0) {
3705  s->secure.parse(token);
3706  } else if (strncmp(token, "dhparams=", 9) == 0) {
3707  debugs(3, DBG_PARSE_NOTE(DBG_IMPORTANT), "WARNING: '" << token << "' is deprecated " <<
3708  "in " << cfg_directive << ". Use 'tls-dh=' instead.");
3709  s->secure.parse(token);
3710  } else if (strncmp(token, "sslflags=", 9) == 0) {
3711  // NP: deprecation warnings output by secure.parse() when relevant
3712  s->secure.parse(token+3);
3713  } else if (strncmp(token, "sslcontext=", 11) == 0) {
3714  // NP: deprecation warnings output by secure.parse() when relevant
3715  s->secure.parse(token+3);
3716  } else if (strncmp(token, "generate-host-certificates", 26) == 0) {
3717  s->secure.parse(token);
3718 #endif
3719  } else if (strncmp(token, "dynamic_cert_mem_cache_size=", 28) == 0) {
3720  s->secure.parse(token);
3721  } else if (strncmp(token, "tls-", 4) == 0) {
3722  s->secure.parse(token+4);
3723  } else if (strcmp(token, "ftp-track-dirs") == 0) {
3724  s->ftp_track_dirs = true;
3725  } else if (strcmp(token, "worker-queues") == 0) {
3726 #if !defined(SO_REUSEADDR)
3727 #error missing system #include that #defines SO_* constants
3728 #endif
3729 #if !defined(SO_REUSEPORT)
3730  throw TexcHere(ToSBuf(cfg_directive, ' ', token, " option requires building Squid where SO_REUSEPORT is supported by the TCP stack"));
3731 #endif
3732  s->workerQueues = true;
3733  } else {
3734  debugs(3, DBG_CRITICAL, "FATAL: Unknown " << cfg_directive << " option '" << token << "'.");
3735  self_destruct();
3736  }
3737 }
3738 
3739 void
3740 add_http_port(char *portspec)
3741 {
3743  s->transport = parsePortProtocol(SBuf("HTTP"));
3744  parsePortSpecification(s, portspec);
3745  // we may need to merge better if the above returns a list with clones
3746  assert(s->next == NULL);
3747  s->next = HttpPortList;
3748  HttpPortList = s;
3749 }
3750 
3751 static void
3752 parsePortCfg(AnyP::PortCfgPointer *head, const char *optionName)
3753 {
3754  SBuf protoName;
3755  if (strcmp(optionName, "http_port") == 0 ||
3756  strcmp(optionName, "ascii_port") == 0)
3757  protoName = "HTTP";
3758  else if (strcmp(optionName, "https_port") == 0)
3759  protoName = "HTTPS";
3760  else if (strcmp(optionName, "ftp_port") == 0)
3761  protoName = "FTP";
3762  if (protoName.isEmpty()) {
3763  self_destruct();
3764  return;
3765  }
3766 
3767  char *token = ConfigParser::NextToken();
3768 
3769  if (!token) {
3770  self_destruct();
3771  return;
3772  }
3773 
3775  s->transport = parsePortProtocol(protoName); // default; protocol=... overwrites
3776  parsePortSpecification(s, token);
3777 
3778  /* parse options ... */
3779  while ((token = ConfigParser::NextToken())) {
3780  parse_port_option(s, token);
3781  }
3782 
3783  s->secure.syncCaFiles();
3784 
3785  if (s->transport.protocol == AnyP::PROTO_HTTPS) {
3786  s->secure.encryptTransport = true;
3787 #if USE_OPENSSL
3788  /* ssl-bump on https_port configuration requires either tproxy or intercept, and vice versa */
3789  const bool hijacked = s->flags.isIntercepted();
3790  if (s->flags.tunnelSslBumping && !hijacked) {
3791  debugs(3, DBG_CRITICAL, "FATAL: ssl-bump on https_port requires tproxy/intercept which is missing.");
3792  self_destruct();
3793  return;
3794  }
3795  if (hijacked && !s->flags.tunnelSslBumping) {
3796  debugs(3, DBG_CRITICAL, "FATAL: tproxy/intercept on https_port requires ssl-bump which is missing.");
3797  self_destruct();
3798  return;
3799  }
3800 #endif
3801  if (s->flags.proxySurrogate) {
3802  debugs(3,DBG_CRITICAL, "FATAL: https_port: require-proxy-header option is not supported on HTTPS ports.");
3803  self_destruct();
3804  return;
3805  }
3806  } else if (protoName.cmp("FTP") == 0) {
3807  /* ftp_port does not support ssl-bump */
3808  if (s->flags.tunnelSslBumping) {
3809  debugs(3, DBG_CRITICAL, "FATAL: ssl-bump is not supported for ftp_port.");
3810  self_destruct();
3811  return;
3812  }
3813  if (s->flags.proxySurrogate) {
3814  // Passive FTP data channel does not work without deep protocol inspection in the frontend.
3815  debugs(3,DBG_CRITICAL, "FATAL: require-proxy-header option is not supported on ftp_port.");
3816  self_destruct();
3817  return;
3818  }
3819  }
3820 
3821  if (s->secure.encryptTransport) {
3822  if (s->secure.certs.empty()) {
3823  debugs(3, DBG_CRITICAL, "FATAL: " << AnyP::UriScheme(s->transport.protocol) << "_port requires a cert= parameter");
3824  self_destruct();
3825  return;
3826  }
3827  s->secure.parseOptions();
3828  }
3829 
3830  // *_port line should now be fully valid so we can clone it if necessary
3831  if (Ip::EnableIpv6&IPV6_SPECIAL_SPLITSTACK && s->s.isAnyAddr()) {
3832  // clone the port options from *s to *(s->next)
3833  s->next = s->clone();
3834  s->next->s.setIPv4();
3835  debugs(3, 3, AnyP::UriScheme(s->transport.protocol).image() << "_port: clone wildcard address for split-stack: " << s->s << " and " << s->next->s);
3836  }
3837 
3838  while (*head != NULL)
3839  head = &((*head)->next);
3840 
3841  *head = s;
3842 }
3843 
3844 static void
3846 {
3847  char buf[MAX_IPSTRLEN];
3848 
3849  storeAppendPrintf(e, "%s %s",
3850  n,
3851  s->s.toUrl(buf,MAX_IPSTRLEN));
3852 
3853  // MODES and specific sub-options.
3854  if (s->flags.natIntercept)
3855  storeAppendPrintf(e, " intercept");
3856 
3857  else if (s->flags.tproxyIntercept)
3858  storeAppendPrintf(e, " tproxy");
3859 
3860  else if (s->flags.proxySurrogate)
3861  storeAppendPrintf(e, " require-proxy-header");
3862 
3863  else if (s->flags.accelSurrogate) {
3864  storeAppendPrintf(e, " accel");
3865 
3866  if (s->vhost)
3867  storeAppendPrintf(e, " vhost");
3868 
3869  if (s->vport < 0)
3870  storeAppendPrintf(e, " vport");
3871  else if (s->vport > 0)
3872  storeAppendPrintf(e, " vport=%d", s->vport);
3873 
3874  if (s->defaultsite)
3875  storeAppendPrintf(e, " defaultsite=%s", s->defaultsite);
3876 
3877  // TODO: compare against prefix of 'n' instead of assuming http_port
3878  if (s->transport.protocol != AnyP::PROTO_HTTP)
3879  storeAppendPrintf(e, " protocol=%s", AnyP::ProtocolType_str[s->transport.protocol]);
3880 
3881  if (s->allow_direct)
3882  storeAppendPrintf(e, " allow-direct");
3883 
3884  if (s->ignore_cc)
3885  storeAppendPrintf(e, " ignore-cc");
3886 
3887  }
3888 
3889  // Generic independent options
3890 
3891  if (s->name)
3892  storeAppendPrintf(e, " name=%s", s->name);
3893 
3894 #if USE_HTTP_VIOLATIONS
3895  if (!s->flags.accelSurrogate && s->ignore_cc)
3896  storeAppendPrintf(e, " ignore-cc");
3897 #endif
3898 
3899  if (s->connection_auth_disabled)
3900  storeAppendPrintf(e, " connection-auth=off");
3901  else
3902  storeAppendPrintf(e, " connection-auth=on");
3903 
3904  if (s->disable_pmtu_discovery != DISABLE_PMTU_OFF) {
3905  const char *pmtu;
3906 
3907  if (s->disable_pmtu_discovery == DISABLE_PMTU_ALWAYS)
3908  pmtu = "always";
3909  else
3910  pmtu = "transparent";
3911 
3912  storeAppendPrintf(e, " disable-pmtu-discovery=%s", pmtu);
3913  }
3914 
3915  if (s->s.isAnyAddr() && !s->s.isIPv6())
3916  storeAppendPrintf(e, " ipv4");
3917 
3918  if (s->tcp_keepalive.enabled) {
3919  if (s->tcp_keepalive.idle || s->tcp_keepalive.interval || s->tcp_keepalive.timeout) {
3920  storeAppendPrintf(e, " tcpkeepalive=%d,%d,%d", s->tcp_keepalive.idle, s->tcp_keepalive.interval, s->tcp_keepalive.timeout);
3921  } else {
3922  storeAppendPrintf(e, " tcpkeepalive");
3923  }
3924  }
3925 
3926 #if USE_OPENSSL
3927  if (s->flags.tunnelSslBumping)
3928  storeAppendPrintf(e, " ssl-bump");
3929 #endif
3930 
3931  s->secure.dumpCfg(e, "tls-");
3932 }
3933 
3934 static void
3935 dump_PortCfg(StoreEntry * e, const char *n, const AnyP::PortCfgPointer &s)
3936 {
3937  for (AnyP::PortCfgPointer p = s; p != NULL; p = p->next) {
3938  dump_generic_port(e, n, p);
3939  storeAppendPrintf(e, "\n");
3940  }
3941 }
3942 
3943 void
3945 {
3946  free_all();
3947  Config.ssl_client.sslContext.reset();
3948 #if USE_OPENSSL
3950 #endif
3951 }
3952 
3953 void
3954 requirePathnameExists(const char *name, const char *path)
3955 {
3956 
3957  struct stat sb;
3958  char pathbuf[BUFSIZ];
3959  assert(path != NULL);
3960 
3961  if (Config.chroot_dir && (geteuid() == 0)) {
3962  snprintf(pathbuf, BUFSIZ, "%s/%s", Config.chroot_dir, path);
3963  path = pathbuf;
3964  }
3965 
3966  if (stat(path, &sb) < 0) {
3967  int xerrno = errno;
3968  debugs(0, DBG_CRITICAL, (opt_parse_cfg_only?"FATAL: ":"ERROR: ") << name << " " << path << ": " << xstrerr(xerrno));
3969  // keep going to find more issues if we are only checking the config file with "-k parse"
3970  if (opt_parse_cfg_only)
3971  return;
3972  // this is fatal if it is found during startup or reconfigure
3973  if (opt_send_signal == -1 || opt_send_signal == SIGHUP)
3974  fatalf("%s %s: %s", name, path, xstrerr(xerrno));
3975  }
3976 }
3977 
3978 #include "AccessLogEntry.h"
3979 
4000 static void
4002 {
4003  const char *filename = ConfigParser::NextToken();
4004  if (!filename) {
4005  self_destruct();
4006  return;
4007  }
4008 
4009  CustomLog *cl = (CustomLog *)xcalloc(1, sizeof(*cl));
4010 
4011  cl->filename = xstrdup(filename);
4012  // default buffer size and fatal settings
4013  cl->bufferSize = 8*MAX_URL;
4014  cl->fatal = true;
4015 
4016  if (strcmp(filename, "none") == 0) {
4018  aclParseAclList(LegacyParser, &cl->aclList, filename);
4019  while (*logs)
4020  logs = &(*logs)->next;
4021  *logs = cl;
4022  return;
4023  }
4024 
4026  cl->rotateCount = -1; // default: use global logfile_rotate setting.
4027 
4028  const char *token = ConfigParser::PeekAtToken();
4029  if (!token) { // style #1
4030  // no options to deal with
4031  } else if (!strchr(token, '=')) { // style #3
4032  // if logformat name is recognized,
4033  // pop the previewed token; Else it must be an ACL name
4034  if (setLogformat(cl, token, false))
4035  (void)ConfigParser::NextToken();
4036  } else { // style #4
4037  do {
4038  if (strncasecmp(token, "on-error=", 9) == 0) {
4039  if (strncasecmp(token+9, "die", 3) == 0) {
4040  cl->fatal = true;
4041  } else if (strncasecmp(token+9, "drop", 4) == 0) {
4042  cl->fatal = false;
4043  } else {
4044  debugs(3, DBG_CRITICAL, "Unknown value for on-error '" <<
4045  token << "' expected 'drop' or 'die'");
4046  xfree(cl->filename);
4047  xfree(cl);
4048  self_destruct();
4049  return;
4050  }
4051  } else if (strncasecmp(token, "buffer-size=", 12) == 0) {
4052  parseBytesOptionValue(&cl->bufferSize, B_BYTES_STR, token+12);
4053  } else if (strncasecmp(token, "rotate=", 7) == 0) {
4054  cl->rotateCount = xatoi(token + 7);
4055  } else if (strncasecmp(token, "logformat=", 10) == 0) {
4056  setLogformat(cl, token+10, true);
4057  } else if (!strchr(token, '=')) {
4058  // Do not pop the token; it must be an ACL name
4059  break; // done with name=value options, now to ACLs
4060  } else {
4061  debugs(3, DBG_CRITICAL, "Unknown access_log option " << token);
4062  xfree(cl->filename);
4063  xfree(cl);
4064  self_destruct();
4065  return;
4066  }
4067  // Pop the token, it was a valid "name=value" option
4068  (void)ConfigParser::NextToken();
4069  // Get next with preview ConfigParser::NextToken call.
4070  } while ((token = ConfigParser::PeekAtToken()) != NULL);
4071  }
4072 
4073  // set format if it has not been specified explicitly
4074  if (cl->type == Log::Format::CLF_UNKNOWN)
4075  setLogformat(cl, "squid", true);
4076 
4078 
4079  while (*logs)
4080  logs = &(*logs)->next;
4081 
4082  *logs = cl;
4083 }
4084 
4087 static bool
4088 setLogformat(CustomLog *cl, const char *logdef_name, const bool dieWhenMissing)
4089 {
4090  assert(cl);
4091  assert(logdef_name);
4092 
4093  debugs(3, 9, "possible " << cl->filename << " logformat: " << logdef_name);
4094 
4095  if (cl->type != Log::Format::CLF_UNKNOWN) {
4096  debugs(3, DBG_CRITICAL, "FATAL: Second logformat name in one access_log: " <<
4097  logdef_name << " " << cl->type << " ? " << Log::Format::CLF_NONE);
4098  self_destruct();
4099  return false;
4100  }
4101 
4102  /* look for the definition pointer corresponding to this name */
4104 
4105  while (lf != NULL) {
4106  debugs(3, 9, "Comparing against '" << lf->name << "'");
4107 
4108  if (strcmp(lf->name, logdef_name) == 0)
4109  break;
4110 
4111  lf = lf->next;
4112  }
4113 
4114  if (lf != NULL) {
4116  cl->logFormat = lf;
4117  } else if (strcmp(logdef_name, "auto") == 0) {
4118  debugs(0, DBG_CRITICAL, "WARNING: Log format 'auto' no longer exists. Using 'squid' instead.");
4120  } else if (strcmp(logdef_name, "squid") == 0) {
4122  } else if (strcmp(logdef_name, "common") == 0) {
4124  } else if (strcmp(logdef_name, "combined") == 0) {
4126 #if ICAP_CLIENT
4127  } else if (strcmp(logdef_name, "icap_squid") == 0) {
4129 #endif
4130  } else if (strcmp(logdef_name, "useragent") == 0) {
4132  } else if (strcmp(logdef_name, "referrer") == 0) {
4134  } else if (dieWhenMissing) {
4135  debugs(3, DBG_CRITICAL, "FATAL: Log format '" << logdef_name << "' is not defined");
4136  self_destruct();
4137  return false;
4138  } else {
4139  return false;
4140  }
4141 
4142  return true;
4143 }
4144 
4145 static int
4146 check_null_access_log(CustomLog *customlog_definitions)
4147 {
4148  return customlog_definitions == NULL;
4149 }
4150 
4151 static void
4152 dump_access_log(StoreEntry * entry, const char *name, CustomLog * logs)
4153 {
4154  CustomLog *log;
4155 
4156  for (log = logs; log; log = log->next) {
4157  storeAppendPrintf(entry, "%s ", name);
4158 
4159  switch (log->type) {
4160 
4162  storeAppendPrintf(entry, "%s logformat=%s", log->filename, log->logFormat->name);
4163  break;
4164 
4165  case Log::Format::CLF_NONE:
4166  storeAppendPrintf(entry, "logformat=none");
4167  break;
4168 
4170  // this is the default, no need to add to the dump
4171  //storeAppendPrintf(entry, "%s logformat=squid", log->filename);
4172  break;
4173 
4175  storeAppendPrintf(entry, "%s logformat=combined", log->filename);
4176  break;
4177 
4179  storeAppendPrintf(entry, "%s logformat=common", log->filename);
4180  break;
4181 
4182 #if ICAP_CLIENT
4184  storeAppendPrintf(entry, "%s logformat=icap_squid", log->filename);
4185  break;
4186 #endif
4188  storeAppendPrintf(entry, "%s logformat=useragent", log->filename);
4189  break;
4190 
4192  storeAppendPrintf(entry, "%s logformat=referrer", log->filename);
4193  break;
4194 
4196  break;
4197  }
4198 
4199  // default is on-error=die
4200  if (!log->fatal)
4201  storeAppendPrintf(entry, " on-error=drop");
4202 
4203  // default: 64KB
4204  if (log->bufferSize != 64*1024)
4205  storeAppendPrintf(entry, " buffer-size=%" PRIuSIZE, log->bufferSize);
4206 
4207  if (log->rotateCount >= 0)
4208  storeAppendPrintf(entry, " rotate=%d", log->rotateCount);
4209 
4210  if (log->aclList)
4211  dump_acl_list(entry, log->aclList);
4212 
4213  storeAppendPrintf(entry, "\n");
4214  }
4215 }
4216 
4217 static void
4219 {
4220  while (*definitions) {
4221  CustomLog *log = *definitions;
4222  *definitions = log->next;
4223 
4224  log->logFormat = NULL;
4225  log->type = Log::Format::CLF_UNKNOWN;
4226 
4227  if (log->aclList)
4228  aclDestroyAclList(&log->aclList);
4229 
4230  safe_free(log->filename);
4231 
4232  xfree(log);
4233  }
4234 }
4235 
4236 #if HAVE_CPU_AFFINITY /* until somebody else needs this general code */
4237 static bool
4239 parseNamedIntList(const char *data, const String &name, std::vector<int> &list)
4240 {
4241  if (data && (strncmp(data, name.rawBuf(), name.size()) == 0)) {
4242  data += name.size();
4243  if (*data == '=') {
4244  while (true) {
4245  ++data;
4246  int value = 0;
4247  if (!StringToInt(data, value, &data, 10))
4248  break;
4249  list.push_back(value);
4250  if (*data == '\0' || *data != ',')
4251  break;
4252  }
4253  }
4254  }
4255  return data && *data == '\0';
4256 }
4257 #endif
4258 
4259 static void
4260 parse_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap)
4261 {
4262 #if !HAVE_CPU_AFFINITY
4263  debugs(3, DBG_CRITICAL, "FATAL: Squid built with no CPU affinity " <<
4264  "support, do not set 'cpu_affinity_map'");
4265  self_destruct();
4266 
4267 #else /* HAVE_CPU_AFFINITY */
4268  if (!*cpuAffinityMap)
4269  *cpuAffinityMap = new CpuAffinityMap;
4270 
4271  const char *const pToken = ConfigParser::NextToken();
4272  const char *const cToken = ConfigParser::NextToken();
4273  std::vector<int> processes, cores;
4274  if (!parseNamedIntList(pToken, "process_numbers", processes)) {
4275  debugs(3, DBG_CRITICAL, "FATAL: bad 'process_numbers' parameter " <<
4276  "in 'cpu_affinity_map'");
4277  self_destruct();
4278  } else if (!parseNamedIntList(cToken, "cores", cores)) {
4279  debugs(3, DBG_CRITICAL, "FATAL: bad 'cores' parameter in " <<
4280  "'cpu_affinity_map'");
4281  self_destruct();
4282  } else if (!(*cpuAffinityMap)->add(processes, cores)) {
4283  debugs(3, DBG_CRITICAL, "FATAL: bad 'cpu_affinity_map'; " <<
4284  "process_numbers and cores lists differ in length or " <<
4285  "contain numbers <= 0");
4286  self_destruct();
4287  }
4288 #endif
4289 }
4290 
4291 static void
4292 dump_CpuAffinityMap(StoreEntry *const entry, const char *const name, const CpuAffinityMap *const cpuAffinityMap)
4293 {
4294  if (cpuAffinityMap) {
4295  storeAppendPrintf(entry, "%s process_numbers=", name);
4296  for (size_t i = 0; i < cpuAffinityMap->processes().size(); ++i) {
4297  storeAppendPrintf(entry, "%s%i", (i ? "," : ""),
4298  cpuAffinityMap->processes()[i]);
4299  }
4300  storeAppendPrintf(entry, " cores=");
4301  for (size_t i = 0; i < cpuAffinityMap->cores().size(); ++i) {
4302  storeAppendPrintf(entry, "%s%i", (i ? "," : ""),
4303  cpuAffinityMap->cores()[i]);
4304  }
4305  storeAppendPrintf(entry, "\n");
4306  }
4307 }
4308 
4309 static void
4310 free_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap)
4311 {
4312  delete *cpuAffinityMap;
4313  *cpuAffinityMap = NULL;
4314 }
4315 
4316 #if USE_ADAPTATION
4317 
4318 static void
4320 {
4322 }
4323 
4324 static void
4326 {
4328 }
4329 
4330 static void
4332 {
4334 }
4335 #endif /* USE_ADAPTATION */
4336 
4337 #if ICAP_CLIENT
4338 
4339 static void
4341 {
4342  cfg->parseService();
4343 }
4344 
4345 static void
4347 {
4348  cfg->freeService();
4349 }
4350 
4351 static void
4352 dump_icap_service_type(StoreEntry * entry, const char *name, const Adaptation::Icap::Config &cfg)
4353 {
4354  cfg.dumpService(entry, name);
4355 }
4356 
4357 static void
4359 {
4360  debugs(93, DBG_CRITICAL, "WARNING: 'icap_class' is deprecated. " <<
4361  "Use 'adaptation_service_set' instead");
4363 }
4364 
4365 static void
4367 {
4368  debugs(93, DBG_CRITICAL, "WARNING: 'icap_access' is deprecated. " <<
4369  "Use 'adaptation_access' instead");
4371 }
4372 
4373 #endif
4374 
4375 #if USE_ECAP
4376 
4377 static void
4379 {
4380  cfg->parseService();
4381 }
4382 
4383 static void
4385 {
4386  cfg->freeService();
4387 }
4388 
4389 static void
4390 dump_ecap_service_type(StoreEntry * entry, const char *name, const Adaptation::Ecap::Config &cfg)
4391 {
4392  cfg.dumpService(entry, name);
4393 }
4394 
4395 #endif /* USE_ECAP */
4396 
4397 #if ICAP_CLIENT
4399 {
4400  char *token;
4402 
4403  if ((token = ConfigParser::NextToken()) == NULL)
4404  return;
4405 
4406  if (strcmp(token,"in") != 0) {
4407  debugs(3, DBG_CRITICAL, "expecting 'in' on'" << config_input_line << "'");
4408  self_destruct();
4409  return;
4410  }
4411 
4413 }
4414 
4415 static void dump_icap_service_failure_limit(StoreEntry *entry, const char *name, const Adaptation::Icap::Config &cfg)
4416 {
4417  storeAppendPrintf(entry, "%s %d", name, cfg.service_failure_limit);
4418  if (cfg.oldest_service_failure > 0) {
4419  storeAppendPrintf(entry, " in %d seconds", (int)cfg.oldest_service_failure);
4420  }
4421  storeAppendPrintf(entry, "\n");
4422 }
4423 
4425 {
4426  cfg->oldest_service_failure = 0;
4427  cfg->service_failure_limit = 0;
4428 }
4429 #endif
4430 
4431 #if USE_OPENSSL
4433 {
4434  char *al;
4436  if ((al = ConfigParser::NextToken()) == NULL) {
4437  xfree(ca);
4438  self_destruct();
4439  return;
4440  }
4441 
4442  const char *param;
4443  if ( char *s = strchr(al, '{')) {
4444  *s = '\0'; // terminate the al string
4445  ++s;
4446  param = s;
4447  s = strchr(s, '}');
4448  if (!s) {
4449  xfree(ca);
4450  self_destruct();
4451  return;
4452  }
4453  *s = '\0';
4454  } else
4455  param = NULL;
4456 
4457  if (strcmp(al, Ssl::CertAdaptAlgorithmStr[Ssl::algSetValidAfter]) == 0) {
4458  ca->alg = Ssl::algSetValidAfter;
4459  ca->param = xstrdup("on");
4460  } else if (strcmp(al, Ssl::CertAdaptAlgorithmStr[Ssl::algSetValidBefore]) == 0) {
4462  ca->param = xstrdup("on");
4463  } else if (strcmp(al, Ssl::CertAdaptAlgorithmStr[Ssl::algSetCommonName]) == 0) {
4464  ca->alg = Ssl::algSetCommonName;
4465  if (param) {
4466  if (strlen(param) > 64) {
4467  debugs(3, DBG_CRITICAL, "FATAL: sslproxy_cert_adapt: setCommonName{" <<param << "} : using common name longer than 64 bytes is not supported");
4468  xfree(ca);
4469  self_destruct();
4470  return;
4471  }
4472  ca->param = xstrdup(param);
4473  }
4474  } else {
4475  debugs(3, DBG_CRITICAL, "FATAL: sslproxy_cert_adapt: unknown cert adaptation algorithm: " << al);
4476  xfree(ca);
4477  self_destruct();
4478  return;
4479  }
4480 
4482 
4483  while (*cert_adapt)
4484  cert_adapt = &(*cert_adapt)->next;
4485 
4486  *cert_adapt = ca;
4487 }
4488 
4489 static void dump_sslproxy_cert_adapt(StoreEntry *entry, const char *name, sslproxy_cert_adapt *cert_adapt)
4490 {
4491  for (sslproxy_cert_adapt *ca = cert_adapt; ca != NULL; ca = ca->next) {
4492  storeAppendPrintf(entry, "%s ", name);
4493  storeAppendPrintf(entry, "%s{%s} ", Ssl::sslCertAdaptAlgoritm(ca->alg), ca->param);
4494  if (ca->aclList)
4495  dump_acl_list(entry, ca->aclList);
4496  storeAppendPrintf(entry, "\n");
4497  }
4498 }
4499 
4501 {
4502  while (*cert_adapt) {
4503  sslproxy_cert_adapt *ca = *cert_adapt;
4504  *cert_adapt = ca->next;
4505  safe_free(ca->param);
4506 
4507  if (ca->aclList)
4508  aclDestroyAclList(&ca->aclList);
4509 
4510  safe_free(ca);
4511  }
4512 }
4513 
4515 {
4516  char *al;
4518  if ((al = ConfigParser::NextToken()) == NULL) {
4519  xfree(cs);
4520  self_destruct();
4521  return;
4522  }
4523 
4524  if (strcmp(al, Ssl::CertSignAlgorithmStr[Ssl::algSignTrusted]) == 0)
4525  cs->alg = Ssl::algSignTrusted;
4526  else if (strcmp(al, Ssl::CertSignAlgorithmStr[Ssl::algSignUntrusted]) == 0)
4527  cs->alg = Ssl::algSignUntrusted;
4528  else if (strcmp(al, Ssl::CertSignAlgorithmStr[Ssl::algSignSelf]) == 0)
4529  cs->alg = Ssl::algSignSelf;
4530  else {
4531  debugs(3, DBG_CRITICAL, "FATAL: sslproxy_cert_sign: unknown cert signing algorithm: " << al);
4532  xfree(cs);
4533  self_destruct();
4534  return;
4535  }
4536 
4538 
4539  while (*cert_sign)
4540  cert_sign = &(*cert_sign)->next;
4541 
4542  *cert_sign = cs;
4543 }
4544 
4545 static void dump_sslproxy_cert_sign(StoreEntry *entry, const char *name, sslproxy_cert_sign *cert_sign)
4546 {
4547  sslproxy_cert_sign *cs;
4548  for (cs = cert_sign; cs != NULL; cs = cs->next) {
4549  storeAppendPrintf(entry, "%s ", name);
4550  storeAppendPrintf(entry, "%s ", Ssl::certSignAlgorithm(cs->alg));
4551  if (cs->aclList)
4552  dump_acl_list(entry, cs->aclList);
4553  storeAppendPrintf(entry, "\n");
4554  }
4555 }
4556 
4558 {
4559  while (*cert_sign) {
4560  sslproxy_cert_sign *cs = *cert_sign;
4561  *cert_sign = cs->next;
4562 
4563  if (cs->aclList)
4564  aclDestroyAclList(&cs->aclList);
4565 
4566  safe_free(cs);
4567  }
4568 }
4569 
4571 {
4572 public:
4574  /* RegisteredRunner API */
4575  virtual void finalizeConfig();
4576 };
4577 
4579 
4581 
4582 void
4584 {
4587  static char buf[1024];
4589  strcpy(buf, "ssl_bump deny all");
4590  debugs(3, DBG_CRITICAL, "WARNING: auto-converting deprecated implicit "
4591  "\"ssl_bump deny all\" to \"ssl_bump none all\". New ssl_bump configurations "
4592  "must not use implicit rules. Update your ssl_bump rules.");
4593  } else {
4594  strcpy(buf, "ssl_bump allow all");
4595  debugs(3, DBG_CRITICAL, "SECURITY NOTICE: auto-converting deprecated implicit "
4596  "\"ssl_bump allow all\" to \"ssl_bump client-first all\" which is usually "
4597  "inferior to the newer server-first bumping mode. New ssl_bump"
4598  " configurations must not use implicit rules. Update your ssl_bump rules.");
4599  }
4600  parse_line(buf);
4601  }
4602 }
4603 
4604 static void parse_sslproxy_ssl_bump(acl_access **ssl_bump)
4605 {
4606  typedef const char *BumpCfgStyle;
4607  BumpCfgStyle bcsNone = NULL;
4608  BumpCfgStyle bcsNew = "new client/server-first/none";
4609  BumpCfgStyle bcsOld = "deprecated allow/deny";
4610  static BumpCfgStyle bumpCfgStyleLast = bcsNone;
4611  BumpCfgStyle bumpCfgStyleNow = bcsNone;
4612  char *bm;
4613  if ((bm = ConfigParser::NextToken()) == NULL) {
4614  self_destruct();
4615  return;
4616  }
4617 
4618  // if this is the first rule processed
4619  if (*ssl_bump == NULL) {
4620  bumpCfgStyleLast = bcsNone;
4622  }
4623 
4625 
4626  if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpClientFirst]) == 0) {
4628  bumpCfgStyleNow = bcsNew;
4629  } else if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpServerFirst]) == 0) {
4631  bumpCfgStyleNow = bcsNew;
4632  } else if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpPeek]) == 0) {
4633  action.kind = Ssl::bumpPeek;
4634  bumpCfgStyleNow = bcsNew;
4635  } else if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpStare]) == 0) {
4636  action.kind = Ssl::bumpStare;
4637  bumpCfgStyleNow = bcsNew;
4638  } else if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpSplice]) == 0) {
4639  action.kind = Ssl::bumpSplice;
4640  bumpCfgStyleNow = bcsNew;
4641  } else if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpBump]) == 0) {
4642  action.kind = Ssl::bumpBump;
4643  bumpCfgStyleNow = bcsNew;
4644  } else if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpTerminate]) == 0) {
4645  action.kind = Ssl::bumpTerminate;
4646  bumpCfgStyleNow = bcsNew;
4647  } else if (strcmp(bm, Ssl::BumpModeStr[Ssl::bumpNone]) == 0) {
4648  action.kind = Ssl::bumpNone;
4649  bumpCfgStyleNow = bcsNew;
4650  } else if (strcmp(bm, "allow") == 0) {
4651  debugs(3, DBG_CRITICAL, "SECURITY NOTICE: auto-converting deprecated "
4652  "\"ssl_bump allow <acl>\" to \"ssl_bump client-first <acl>\" which "
4653  "is usually inferior to the newer server-first "
4654  "bumping mode. Update your ssl_bump rules.");
4656  bumpCfgStyleNow = bcsOld;
4658  } else if (strcmp(bm, "deny") == 0) {
4659  debugs(3, DBG_CRITICAL, "WARNING: auto-converting deprecated "
4660  "\"ssl_bump deny <acl>\" to \"ssl_bump none <acl>\". Update "
4661  "your ssl_bump rules.");
4662  action.kind = Ssl::bumpNone;
4663  bumpCfgStyleNow = bcsOld;
4665  } else {
4666  debugs(3, DBG_CRITICAL, "FATAL: unknown ssl_bump mode: " << bm);
4667  self_destruct();
4668  return;
4669  }
4670 
4671  if (bumpCfgStyleLast != bcsNone && bumpCfgStyleNow != bumpCfgStyleLast) {
4672  debugs(3, DBG_CRITICAL, "FATAL: do not mix " << bumpCfgStyleNow << " actions with " <<
4673  bumpCfgStyleLast << " actions. Update your ssl_bump rules.");
4674  self_destruct();
4675  return;
4676  }
4677 
4678  bumpCfgStyleLast = bumpCfgStyleNow;
4679 
4680  // empty rule OK
4681  ParseAclWithAction(ssl_bump, action, "ssl_bump");
4682 }
4683 
4684 static void dump_sslproxy_ssl_bump(StoreEntry *entry, const char *name, acl_access *ssl_bump)
4685 {
4686  if (ssl_bump)
4687  dump_SBufList(entry, ssl_bump->treeDump(name, [](const Acl::Answer &action) {
4688  return Ssl::BumpModeStr.at(action.kind);
4689  }));
4690 }
4691 
4692 static void free_sslproxy_ssl_bump(acl_access **ssl_bump)
4693 {
4694  free_acl_access(ssl_bump);
4695 }
4696 
4697 #endif
4698 
4699 static void dump_HeaderWithAclList(StoreEntry * entry, const char *name, HeaderWithAclList *headers)
4700 {
4701  if (!headers)
4702  return;
4703 
4704  for (HeaderWithAclList::iterator hwa = headers->begin(); hwa != headers->end(); ++hwa) {
4705  storeAppendPrintf(entry, "%s %s %s", name, hwa->fieldName.c_str(), hwa->fieldValue.c_str());
4706  if (hwa->aclList)
4707  dump_acl_list(entry, hwa->aclList);
4708  storeAppendPrintf(entry, "\n");
4709  }
4710 }
4711 
4713 {
4714  char *fn;
4715  if (!*headers) {
4716  *headers = new HeaderWithAclList;
4717  }
4718  if ((fn = ConfigParser::NextToken()) == NULL) {
4719  self_destruct();
4720  return;
4721  }
4722  HeaderWithAcl hwa;
4723  hwa.fieldName = fn;
4725  if (hwa.fieldId == Http::HdrType::BAD_HDR)
4727 
4728  Format::Format *nlf = new ::Format::Format("hdrWithAcl");
4732  hwa.fieldValue = buf.termedBuf();
4734  if (hwa.quoted) {
4735  if (!nlf->parse(hwa.fieldValue.c_str())) {
4736  self_destruct();
4737  return;
4738  }
4739  hwa.valueFormat = nlf;
4740  } else
4741  delete nlf;
4742  aclParseAclList(LegacyParser, &hwa.aclList, (hwa.fieldName + ':' + hwa.fieldValue).c_str());
4743  (*headers)->push_back(hwa);
4744 }
4745 
4747 {
4748  if (!(*header))
4749  return;
4750 
4751  for (HeaderWithAclList::iterator hwa = (*header)->begin(); hwa != (*header)->end(); ++hwa) {
4752  if (hwa->aclList)
4753  aclDestroyAclList(&hwa->aclList);
4754 
4755  if (hwa->valueFormat) {
4756  delete hwa->valueFormat;
4757  hwa->valueFormat = NULL;
4758  }
4759  }
4760  delete *header;
4761  *header = NULL;
4762 }
4763 
4764 static void parse_note(Notes *notes)
4765 {
4766  assert(notes);
4767  notes->parse(LegacyParser);
4768 }
4769 
4770 static void dump_note(StoreEntry *entry, const char *name, Notes &notes)
4771 {
4772  notes.dump(entry, name);
4773 }
4774 
4775 static void free_note(Notes *notes)
4776 {
4777  notes->clean();
4778 }
4779 
4780 static bool FtpEspvDeprecated = false;
4781 static void parse_ftp_epsv(acl_access **ftp_epsv)
4782 {
4783  Acl::Answer ftpEpsvDeprecatedAction;
4784  bool ftpEpsvIsDeprecatedRule = false;
4785 
4786  char *t = ConfigParser::PeekAtToken();
4787  if (!t) {
4788  self_destruct();
4789  return;
4790  }
4791 
4792  if (!strcmp(t, "off")) {
4793  (void)ConfigParser::NextToken();
4794  ftpEpsvIsDeprecatedRule = true;
4795  ftpEpsvDeprecatedAction = Acl::Answer(ACCESS_DENIED);
4796  } else if (!strcmp(t, "on")) {
4797  (void)ConfigParser::NextToken();
4798  ftpEpsvIsDeprecatedRule = true;
4799  ftpEpsvDeprecatedAction = Acl::Answer(ACCESS_ALLOWED);
4800  }
4801 
4802  // Check for mixing "ftp_epsv on|off" and "ftp_epsv allow|deny .." rules:
4803  // 1) if this line is "ftp_epsv allow|deny ..." and already exist rules of "ftp_epsv on|off"
4804  // 2) if this line is "ftp_epsv on|off" and already exist rules of "ftp_epsv allow|deny ..."
4805  // then abort
4806  if ((!ftpEpsvIsDeprecatedRule && FtpEspvDeprecated) ||
4807  (ftpEpsvIsDeprecatedRule && !FtpEspvDeprecated && *ftp_epsv != NULL)) {
4808  debugs(3, DBG_CRITICAL, "FATAL: do not mix \"ftp_epsv on|off\" cfg lines with \"ftp_epsv allow|deny ...\" cfg lines. Update your ftp_epsv rules.");
4809  self_destruct();
4810  return;
4811  }
4812 
4813  if (ftpEpsvIsDeprecatedRule) {
4814  // overwrite previous ftp_epsv lines
4815  delete *ftp_epsv;
4816  *ftp_epsv = nullptr;
4817 
4818  if (ftpEpsvDeprecatedAction == Acl::Answer(ACCESS_DENIED)) {
4819  if (ACL *a = ACL::FindByName("all"))
4820  ParseAclWithAction(ftp_epsv, ftpEpsvDeprecatedAction, "ftp_epsv", a);
4821  else {
4822  self_destruct();
4823  return;
4824  }
4825  }
4826  FtpEspvDeprecated = true;
4827  } else {
4829  }
4830 }
4831 
4832 static void dump_ftp_epsv(StoreEntry *entry, const char *name, acl_access *ftp_epsv)
4833 {
4834  if (ftp_epsv)
4835  dump_SBufList(entry, ftp_epsv->treeDump(name, Acl::AllowOrDeny));
4836 }
4837 
4838 static void free_ftp_epsv(acl_access **ftp_epsv)
4839 {
4840  free_acl_access(ftp_epsv);
4841  FtpEspvDeprecated = false;
4842 }
4843 
4846 static std::chrono::seconds
4848 {
4849  const auto timeValueToken = ConfigParser::NextToken();
4850  if (!timeValueToken)
4851  throw TexcHere("cannot read a time value");
4852 
4853  using Seconds = std::chrono::seconds;
4854 
4855  const auto parsedTimeValue = xatof(timeValueToken);
4856 
4857  if (parsedTimeValue == 0)
4858  return std::chrono::seconds::zero();
4859 
4860  std::chrono::nanoseconds parsedUnitDuration;
4861 
4862  const auto unitToken = ConfigParser::PeekAtToken();
4863  if (parseTimeUnit<Seconds>(unitToken, parsedUnitDuration))
4864  (void)ConfigParser::NextToken();
4865  else {
4866  const auto defaultParsed = parseTimeUnit<Seconds>(T_SECOND_STR, parsedUnitDuration);
4867  assert(defaultParsed);
4869  ": WARNING: missing time unit, using deprecated default '" << T_SECOND_STR << "'");
4870  }
4871 
4872  const auto nanoseconds = ToNanoSeconds(parsedTimeValue, parsedUnitDuration);
4873 
4874  return FromNanoseconds<Seconds>(nanoseconds, parsedTimeValue);
4875 }
4876 
4877 static void
4879 {
4880  // TODO: do not allow optional timeunit (as the documentation prescribes)
4881  // and use parseTimeLine() instead.
4883 
4884  char *key, *value;
4885  while(ConfigParser::NextKvPair(key, value)) {
4886  if (strcasecmp(key, "on_timeout") == 0) {
4887  if (strcasecmp(value, "bypass") == 0)
4888  config->action = toutActBypass;
4889  else if (strcasecmp(value, "fail") == 0)
4890  config->action = toutActFail;
4891  else if (strcasecmp(value, "retry") == 0)
4892  config->action = toutActRetry;
4893  else if (strcasecmp(value, "use_configured_response") == 0) {
4895  } else {
4896  debugs(3, DBG_CRITICAL, "FATAL: unsupported \"on_timeout\" action: " << value);
4897  self_destruct();
4898  return;
4899  }
4900  } else if (strcasecmp(key, "response") == 0) {
4901  config->response = xstrdup(value);
4902  } else {
4903  debugs(3, DBG_CRITICAL, "FATAL: unsupported option " << key);
4904  self_destruct();
4905  return;
4906  }
4907  }
4908 
4909  if (config->action == toutActUseConfiguredResponse && !config->response) {
4910  debugs(3, DBG_CRITICAL, "FATAL: Expected 'response=' option after 'on_timeout=use_configured_response' option");
4911  self_destruct();
4912  }
4913 
4914  if (config->action != toutActUseConfiguredResponse && config->response) {
4915  debugs(3, DBG_CRITICAL, "FATAL: 'response=' option is valid only when used with the 'on_timeout=use_configured_response' option");
4916  self_destruct();
4917  }
4918 }
4919 
4920 static void
4922 {
4923  const char *onTimedOutActions[] = {"bypass", "fail", "retry", "use_configured_response"};
4924  assert(config.action >= 0 && config.action <= toutActUseConfiguredResponse);
4925 
4926  dump_time_t(entry, name, Config.Timeout.urlRewrite);
4927  storeAppendPrintf(entry, " on_timeout=%s", onTimedOutActions[config.action]);
4928 
4929  if (config.response)
4930  storeAppendPrintf(entry, " response=\"%s\"", config.response);
4931 
4932  storeAppendPrintf(entry, "\n");
4933 }
4934 
4935 static void
4937 {
4939  config->action = 0;
4940  safe_free(config->response);
4941 }
4942 
4943 static void
4945 {
4946  int val = 0;
4947  parse_onoff(&val);
4948 
4949  // If quoted values is set to on then enable new strict mode parsing
4950  if (val) {
4952  ConfigParser::StrictMode = true;
4953  } else {
4955  ConfigParser::StrictMode = false;
4956  }
4957 }
4958 
4959 static void
4960 dump_configuration_includes_quoted_values(StoreEntry *const entry, const char *const name, bool)
4961 {
4962  int val = ConfigParser::RecognizeQuotedValues ? 1 : 0;
4963  dump_onoff(entry, name, val);
4964 }
4965 
4966 static void
4968 {
4970  ConfigParser::StrictMode = false;
4971 }
4972 
4973 static void
4975 {
4976  char *tm;
4977  if ((tm = ConfigParser::NextToken()) == NULL) {
4978  self_destruct();
4979  return;
4980  }
4981 
4983  if (strcmp(tm, "tunnel") == 0)
4984  action.kind = 1;
4985  else if (strcmp(tm, "respond") == 0)
4986  action.kind = 2;
4987  else {
4988  debugs(3, DBG_CRITICAL, "FATAL: unknown on_unsupported_protocol mode: " << tm);
4989  self_destruct();
4990  return;
4991  }
4992 
4993  // empty rule OK
4994  ParseAclWithAction(access, action, "on_unsupported_protocol");
4995 }
4996 
4997 static void
4998 dump_on_unsupported_protocol(StoreEntry *entry, const char *name, acl_access *access)
4999 {
5000  static const std::vector<const char *> onErrorTunnelMode = {
5001  "none",
5002  "tunnel",
5003  "respond"
5004  };
5005  if (access) {
5006  SBufList lines = access->treeDump(name, [](const Acl::Answer &action) {
5007  return onErrorTunnelMode.at(action.kind);
5008  });
5009  dump_SBufList(entry, lines);
5010  }
5011 }
5012 
5013 static void
5015 {
5016  free_acl_access(access);
5017 }
5018 
5019 static void
5021 {
5022  assert(protoGuardsPtr);
5023  auto &protoGuards = *protoGuardsPtr;
5024  if (!protoGuards)
5025  protoGuards = new HttpUpgradeProtocolAccess();
5026  protoGuards->configureGuard(LegacyParser);
5027 }
5028 
5029 static void
5031 {
5032  if (!protoGuards)
5033  return;
5034 
5035  const SBuf name(rawName);
5036  protoGuards->forEach([entry,&name](const SBuf &proto, const acl_access *acls) {
5037  SBufList line;
5038  line.push_back(name);
5039  line.push_back(proto);
5040  const auto acld = acls->treeDump("", &Acl::AllowOrDeny);
5041  line.insert(line.end(), acld.begin(), acld.end());
5042  dump_SBufList(entry, line);
5043  });
5044 }
5045 
5046 static void
5048 {
5049  assert(protoGuardsPtr);
5050  auto &protoGuards = *protoGuardsPtr;
5051  delete protoGuards;
5052  protoGuards = nullptr;
5053 }
5054 
char * errorDirectory
Definition: SquidConfig.h:433
static peer_t parseNeighborType(const char *s)
Definition: cache_cf.cc:3336
acl_access * access_list
static void parse_http_header_access(HeaderManglers **manglers)
Definition: cache_cf.cc:1779
bool proxy_only
Definition: CachePeer.h:82
static void dump_wordlist(StoreEntry *entry, const char *name, wordlist *list)
Definition: cache_cf.cc:3141
void fatal(const char *message)
Definition: fatal.cc:28
const char * xstrerr(int error)
Definition: xstrerror.cc:83
bool no_query
Definition: CachePeer.h:83
#define URI_WHITESPACE_ENCODE
Definition: defines.h:196
@ bumpPeek
Definition: support.h:126
static void parse_adaptation_access_type()
Definition: cache_cf.cc:4331
static void dump_access_log(StoreEntry *entry, const char *name, CustomLog *definitions)
Definition: cache_cf.cc:4152
void parse_int(int *var)
Definition: cache_cf.cc:2492
static const char * FindStatement(const char *line, const char *statement)
Definition: cache_cf.cc:367
static void parsePortSpecification(const AnyP::PortCfgPointer &s, char *token)
Definition: cache_cf.cc:3417
static void dump_icap_service_type(StoreEntry *, const char *, const Adaptation::Icap::Config &)
Definition: cache_cf.cc:4352
bool htcp_no_clr
Definition: CachePeer.h:94
time_t period
Definition: SquidConfig.h:232
static void dump_time_msec(StoreEntry *entry, const char *name, time_msec_t var)
Definition: cache_cf.cc:2957
int connection_auth
0 - off, 1 - on, 2 - auto
Definition: CachePeer.h:195
@ PEER_MULTICAST
Definition: enums.h:31
virtual bool active() const =0
static void ParseAccess(ConfigParser &parser)
Definition: Config.cc:276
void * xcalloc(size_t n, size_t sz)
Definition: xalloc.cc:72
void wordlistDestroy(wordlist **list)
destroy a wordlist
Definition: wordlist.cc:16
bool background_ping
Definition: CachePeer.h:84
static std::chrono::nanoseconds ToNanoSeconds(const double value, const std::chrono::nanoseconds &unit)
Definition: cache_cf.cc:1107
static SBuf CurrentLocation()
static void parse_TokenOrQuotedString(char **var)
Definition: cache_cf.cc:2918
CachePeer * peerFindByName(const char *name)
Definition: neighbors.cc:1124
int opt_send_signal
void appendf(const char *fmt,...) PRINTF_FORMAT_ARG2
Append operation with printf-style arguments.
Definition: Packable.h:61
RunnerRegistrationEntry(sslBumpCfgRr)
#define BUFSIZ
Definition: defines.h:20
ACLList * aclList
Definition: QosConfig.h:37
static const char * peer_type_str(const peer_t type)
Definition: cache_cf.cc:1967
const char * uniqueHostname(void)
Definition: tools.cc:492
static void free_int(int *var)
Definition: cache_cf.cc:2500
static size_t parseBytesUnits(const char *unit)
Definition: cache_cf.cc:1350
static char * NextQuotedToken()
static void parse_icap_service_type(Adaptation::Icap::Config *)
Definition: cache_cf.cc:4340
static void parse_u_short(unsigned short *var)
Definition: cache_cf.cc:3116
CustomLog * icaplogs
Definition: SquidConfig.h:185
#define xmalloc
static void free_acl_tos(acl_tos **head)
Definition: cache_cf.cc:1587
@ CLF_COMMON
Definition: Formats.h:29
struct CachePeer::@31 options
struct squidaio_request_t * next
Definition: aiops.cc:51
acl_access * access
Definition: CachePeer.h:79
#define URI_WHITESPACE_STRIP
Definition: defines.h:194
bool xstrtoui(const char *s, char **end, unsigned int *value, unsigned int min, unsigned int max)
Definition: xstrto.cc:86
static void dump_tristate(StoreEntry *entry, const char *name, int var)
Definition: cache_cf.cc:2559
static void parse_http_upgrade_request_protocols(HttpUpgradeProtocolAccess **protoGuards)
Definition: cache_cf.cc:5020
void parsePoolClass()
Definition: DelayConfig.cc:31
static void dump_time_nanoseconds(StoreEntry *entry, const char *name, const std::chrono::nanoseconds &var)
Definition: cache_cf.cc:2978
static void free_CpuAffinityMap(CpuAffinityMap **const cpuAffinityMap)
Definition: cache_cf.cc:4310
char * unlinkd
Definition: SquidConfig.h:201
void peerDigestCreate(CachePeer *p)
Definition: peer_digest.cc:130
static void parse_ecap_service_type(Adaptation::Ecap::Config *)
Definition: cache_cf.cc:4378
static void parse_delay_pool_class(DelayConfig *cfg)
Definition: cache_cf.cc:1709
#define URI_WHITESPACE_CHOP
Definition: defines.h:197
void useSquidUntrusted(SSL_CTX *sslContext)
Definition: support.cc:1178
Security::ContextPointer createClientContext(bool setOptions)
generate a security client-context from these configured options
Definition: PeerOptions.cc:271
u_int index
Definition: CachePeer.h:38
static void dump_kb_int64_t(StoreEntry *entry, const char *name, int64_t var)
Definition: cache_cf.cc:3031
static int parseManyConfigFiles(char *files, int depth)
Definition: cache_cf.cc:290
static ConfigParser LegacyParser
Definition: cache_cf.cc:263
double GetPercentage(bool limit)
Definition: Parsing.cc:172
static int parse_line(char *)
AnyP::ProtocolVersion ProtocolVersion()
Protocol version to use in Http::Message structures wrapping FTP messages.
Definition: Elements.cc:24
static void free_removalpolicy(RemovalPolicySettings **settings)
Definition: cache_cf.cc:3226
Log::Format::log_type type
Definition: CustomLog.h:33
#define LOCAL_ARRAY(type, name, size)
Definition: squid.h:75
static const char *const T_HOUR_STR
Definition: cache_cf.cc:145
static void parse_kb_int64_t(int64_t *var)
Definition: cache_cf.cc:3073
AnyP::PortCfgPointer HttpPortList
list of Squid http(s)_port configured
Definition: PortCfg.cc:21
static int check_null_acl_access(acl_access *a)
Definition: cache_cf.cc:3172
static void parse_refreshpattern(RefreshPattern **)
Definition: cache_cf.cc:2677
static void parse_address(Ip::Address *addr)
Definition: cache_cf.cc:1467
int memory_cache_first
Definition: SquidConfig.h:341
static void parse_acl_tos(acl_tos **head)
Definition: cache_cf.cc:1552
peer_t type
Definition: CachePeer.h:41
SBuf TheKidName
current Squid process name (e.g., "squid-coord")
Definition: Kids.cc:19
void log(char *format,...)
bool isEmpty() const
Definition: SBuf.h:420
static void free_acl_access(acl_access **head)
Definition: cache_cf.cc:1454
virtual char const * typeString() const =0
static ACL * FindByName(const char *name)
Definition: Acl.cc:93
static void free_cachemgrpasswd(Mgr::ActionPasswordList **head)
Definition: cache_cf.cc:2398
char config_input_line[BUFSIZ]
representation of a class of Size-limit ACLs
Definition: AclSizeLimit.h:17
void dump(StoreEntry *entry, const char *name)
Dump the notes list to the given StoreEntry object.
Definition: Notes.cc:255
ACLList * aclList
Definition: QosConfig.h:51
int KidIdentifier
void aclParseAccessLine(const char *directive, ConfigParser &, acl_access **treep)
Definition: Gadgets.cc:137
std::list< HeaderWithAcl > HeaderWithAclList
static void EnableMacros()
Allow macros inside quoted strings.
Definition: ConfigParser.h:125
static int check_null_string(char *s)
Definition: cache_cf.cc:1845
#define O_TEXT
Definition: defines.h:201
std::list< SBuf > SBufList
Definition: forward.h:22
static void trim_trailing_ws(char *str)
Definition: cache_cf.cc:357
static void parse_acl_access(acl_access **head)
Definition: cache_cf.cc:1448
static void free_sslproxy_ssl_bump(acl_access **ssl_bump)
Definition: cache_cf.cc:4692
static void ParseBool(bool *var)
Definition: cache_cf.cc:3128
void storeAppendPrintf(StoreEntry *e, const char *fmt,...)
Definition: store.cc:880
static void dump_time_t(StoreEntry *entry, const char *name, time_t var)
Definition: cache_cf.cc:2935
static bool StrictMode
Definition: ConfigParser.h:141
const char * sslCertAdaptAlgoritm(int alg)
Definition: gadgets.h:200
ACLList * aclList
Definition: CustomLog.h:29
static void dump_ftp_epsv(StoreEntry *entry, const char *name, acl_access *ftp_epsv)
Definition: cache_cf.cc:4832
Note::Pointer parse(ConfigParser &parser)
Parses a notes line and returns a pointer to the parsed Note object.
Definition: Notes.cc:202
static void dump_http_upgrade_request_protocols(StoreEntry *entry, const char *name, HttpUpgradeProtocolAccess *protoGuards)
Definition: cache_cf.cc:5030
char * login
Definition: CachePeer.h:174
bool GetHostByName(const char *s)
Definition: Address.cc:372
Helper::ChildConfig storeIdChildren
Definition: SquidConfig.h:213
void StartTransparency()
Definition: Intercept.h:61
#define SQUID_UDP_SO_SNDBUF
Definition: squid.h:49
void clear()
Definition: SquidConfig.h:568
size_t udpMaxHitObjsz
Definition: SquidConfig.h:248
static bool LastTokenWasQuoted()
Definition: ConfigParser.h:92
const char * ProtocolType_str[]
static void parse_obsolete(const char *)
Definition: cache_cf.cc:982
Address_list * next
Definition: Address.h:371
@ CLF_COMBINED
Definition: Formats.h:28
Definition: SBuf.h:87
const char * certSignAlgorithm(int sg)
Definition: gadgets.h:163
BumpMode
Definition: support.h:126
static void dump_sslproxy_ssl_bump(StoreEntry *entry, const char *name, acl_access *ssl_bump)
Definition: cache_cf.cc:4684
char * name
Definition: Format.h:59
int const char int
Definition: stub_libmem.cc:75
static bool RecognizeQuotedValues
configuration_includes_quoted_values in squid.conf
Definition: ConfigParser.h:133
unsigned short xatos(const char *token)
Definition: Parsing.cc:108
static char * PeekAtToken()
time_t oldest_service_failure
Definition: Config.h:55
stores cpu_affinity_map configuration
static void dump_onoff(StoreEntry *entry, const char *name, int var)
Definition: cache_cf.cc:2526
static void free_size_t(size_t *var)
Definition: cache_cf.cc:3079
tos_t tos
Definition: QosConfig.h:38
static void parse_b_ssize_t(ssize_t *var)
Definition: