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