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