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