]> git.ipfire.org Git - thirdparty/squid.git/blame - src/cache_cf.cc
Document the 'carp' cache_peer option
[thirdparty/squid.git] / src / cache_cf.cc
CommitLineData
be335c22 1
30a4f2a8 2/*
3f38a55e 3 * $Id: cache_cf.cc,v 1.433 2003/02/21 19:53:01 hno Exp $
30a4f2a8 4 *
5 * DEBUG: section 3 Configuration File Parsing
6 * AUTHOR: Harvest Derived
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 9 * ----------------------------------------------------------
30a4f2a8 10 *
2b6662ba 11 * Squid is the result of efforts by numerous individuals from
12 * the Internet community; see the CONTRIBUTORS file for full
13 * details. Many organizations have provided support for Squid's
14 * development; see the SPONSORS file for full details. Squid is
15 * Copyrighted (C) 2001 by the Regents of the University of
16 * California; see the COPYRIGHT file for full details. Squid
17 * incorporates software developed and/or copyrighted by other
18 * sources; see the CREDITS file for full details.
30a4f2a8 19 *
20 * This program is free software; you can redistribute it and/or modify
21 * it under the terms of the GNU General Public License as published by
22 * the Free Software Foundation; either version 2 of the License, or
23 * (at your option) any later version.
24 *
25 * This program is distributed in the hope that it will be useful,
26 * but WITHOUT ANY WARRANTY; without even the implied warranty of
27 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
28 * GNU General Public License for more details.
29 *
30 * You should have received a copy of the GNU General Public License
31 * along with this program; if not, write to the Free Software
cbdec147 32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
e25c139f 33 *
30a4f2a8 34 */
cf5fd929 35
44a47c6e 36#include "squid.h"
e6ccf245 37#include "authenticate.h"
38#include "Store.h"
d3b3ab85 39#include "SwapDir.h"
b67e2c8c 40#include "Config.h"
8000a965 41#include "ACL.h"
1df370e3 42
43#if SQUID_SNMP
a97cfa48 44#include "snmp.h"
1df370e3 45#endif
090089c4 46
8813e606 47static const char *const T_SECOND_STR = "second";
48static const char *const T_MINUTE_STR = "minute";
49static const char *const T_HOUR_STR = "hour";
50static const char *const T_DAY_STR = "day";
51static const char *const T_WEEK_STR = "week";
52static const char *const T_FORTNIGHT_STR = "fortnight";
53static const char *const T_MONTH_STR = "month";
54static const char *const T_YEAR_STR = "year";
55static const char *const T_DECADE_STR = "decade";
aa0a0c7c 56
9906e724 57static const char *const B_BYTES_STR = "bytes";
58static const char *const B_KBYTES_STR = "KB";
59static const char *const B_MBYTES_STR = "MB";
60static const char *const B_GBYTES_STR = "GB";
61
4db43fab 62static const char *const list_sep = ", \t\n\r";
b0e7d2d5 63
14f13894 64static void parse_cachedir_option_readonly(SwapDir * sd, const char *option, const char *value, int reconfiguring);
d3b3ab85 65static void dump_cachedir_option_readonly(StoreEntry * e, const char *option, SwapDir const * sd);
14f13894 66static void parse_cachedir_option_maxsize(SwapDir * sd, const char *option, const char *value, int reconfiguring);
d3b3ab85 67static void dump_cachedir_option_maxsize(StoreEntry * e, const char *option, SwapDir const * sd);
b0e7d2d5 68static struct cache_dir_option common_cachedir_options[] =
69{
70 {"read-only", parse_cachedir_option_readonly, dump_cachedir_option_readonly},
71 {"max-size", parse_cachedir_option_maxsize, dump_cachedir_option_maxsize},
72 {NULL, NULL}
73};
74
97474590 75
cd748f27 76static void update_maxobjsize(void);
f5b8bbc4 77static void configDoConfigure(void);
78static void parse_refreshpattern(refresh_t **);
79static int parseTimeUnits(const char *unit);
80static void parseTimeLine(time_t * tptr, const char *units);
59715b38 81static void parse_ushort(u_short * var);
f5b8bbc4 82static void parse_string(char **);
f5b8bbc4 83static void default_all(void);
84static void defaults_if_none(void);
85static int parse_line(char *);
86static void parseBytesLine(size_t * bptr, const char *units);
87static size_t parseBytesUnits(const char *unit);
f5b8bbc4 88static void free_all(void);
94439e4e 89void requirePathnameExists(const char *name, const char *path);
ed7f5615 90static OBJH dump_config;
e6ccf245 91#ifdef HTTP_VIOLATIONS
6bccf575 92static void dump_http_header_access(StoreEntry * entry, const char *name, header_mangler header[]);
93static void parse_http_header_access(header_mangler header[]);
94static void free_http_header_access(header_mangler header[]);
95static void dump_http_header_replace(StoreEntry * entry, const char *name, header_mangler header[]);
96static void parse_http_header_replace(header_mangler * header);
97static void free_http_header_replace(header_mangler * header);
9e8b2f1c 98#endif
6bccf575 99static void parse_denyinfo(acl_deny_info_list ** var);
100static void dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var);
101static void free_denyinfo(acl_deny_info_list ** var);
3f38a55e 102#if CURRENTLY_UNUSED
7e3ce7b9 103static void parse_sockaddr_in_list(sockaddr_in_list **);
104static void dump_sockaddr_in_list(StoreEntry *, const char *, const sockaddr_in_list *);
105static void free_sockaddr_in_list(sockaddr_in_list **);
106static int check_null_sockaddr_in_list(const sockaddr_in_list *);
3f38a55e 107#endif /* CURRENTLY_UNUSED */
108static void parse_http_port_list(http_port_list **);
109static void dump_http_port_list(StoreEntry *, const char *, const http_port_list *);
110static void free_http_port_list(http_port_list **);
111#if UNUSED_CODE
112static int check_null_http_port_list(const http_port_list *);
52f772de 113#endif
d193a436 114#if USE_SSL
115static void parse_https_port_list(https_port_list **);
116static void dump_https_port_list(StoreEntry *, const char *, const https_port_list *);
117static void free_https_port_list(https_port_list **);
118#if 0
119static int check_null_https_port_list(const https_port_list *);
120#endif
121#endif /* USE_SSL */
270b86af 122
0e4e0e7d 123void
0673c0ba 124self_destruct(void)
090089c4 125{
137ee196 126 fatalf("Bungled %s line %d: %s",
b8de7ebe 127 cfg_filename, config_lineno, config_input_line);
090089c4 128}
129
8203a132 130void
131wordlistDestroy(wordlist ** list)
0ffd22bc 132{
133 wordlist *w = NULL;
79d39a72 134 while ((w = *list) != NULL) {
b5639035 135 *list = w->next;
0ffd22bc 136 safe_free(w->key);
db1cd23c 137 memFree(w, MEM_WORDLIST);
0ffd22bc 138 }
139 *list = NULL;
140}
141
858783c9 142const char *
fe4e214f 143wordlistAdd(wordlist ** list, const char *key)
090089c4 144{
c68e9c6b 145 while (*list)
146 list = &(*list)->next;
e6ccf245 147 *list = static_cast<wordlist *>(memAllocate(MEM_WORDLIST));
c68e9c6b 148 (*list)->key = xstrdup(key);
149 (*list)->next = NULL;
858783c9 150 return (*list)->key;
151}
152
153void
a4b8110e 154wordlistJoin(wordlist ** list, wordlist ** wl)
858783c9 155{
156 while (*list)
157 list = &(*list)->next;
158 *list = *wl;
159 *wl = NULL;
160}
161
162void
a4b8110e 163wordlistAddWl(wordlist ** list, wordlist * wl)
858783c9 164{
165 while (*list)
166 list = &(*list)->next;
a4b8110e 167 for (; wl; wl = wl->next, list = &(*list)->next) {
e6ccf245 168 *list = static_cast<wordlist *>(memAllocate(MEM_WORDLIST));
858783c9 169 (*list)->key = xstrdup(wl->key);
a4b8110e 170 (*list)->next = NULL;
858783c9 171 }
090089c4 172}
173
137ee196 174void
eeb423fb 175wordlistCat(const wordlist * w, MemBuf * mb)
5da06f20 176{
5da06f20 177 while (NULL != w) {
137ee196 178 memBufPrintf(mb, "%s\n", w->key);
5da06f20 179 w = w->next;
180 }
5da06f20 181}
182
6b8e7481 183wordlist *
184wordlistDup(const wordlist * w)
185{
186 wordlist *D = NULL;
187 while (NULL != w) {
188 wordlistAdd(&D, w->key);
189 w = w->next;
190 }
191 return D;
192}
193
8203a132 194void
195intlistDestroy(intlist ** list)
92a6f4b1 196{
197 intlist *w = NULL;
198 intlist *n = NULL;
92a6f4b1 199 for (w = *list; w; w = n) {
200 n = w->next;
db1cd23c 201 memFree(w, MEM_INTLIST);
92a6f4b1 202 }
203 *list = NULL;
204}
205
5db53b8f 206int
207intlistFind(intlist * list, int i)
208{
209 intlist *w = NULL;
210 for (w = list; w; w = w->next)
211 if (w->i == i)
212 return 1;
213 return 0;
214}
215
3c5557f9 216/*
5c20d6fa 217 * These functions is the same as atoi/l/f, except that they check for errors
3c5557f9 218 */
090089c4 219
5c20d6fa 220static long
221xatol(const char *token)
222{
223 char *end;
224 long ret = strtol(token, &end, 10);
225 if (ret == 0 && end == token)
226 self_destruct();
227 return ret;
228}
229
230static int
231xatoi(const char *token)
232{
233 return xatol(token);
234}
235
236static double
237xatof(const char *token)
238{
239 char *end;
240 double ret = strtod(token, &end);
241 if (ret == 0 && end == token)
242 self_destruct();
243 return ret;
244}
245
0e4e0e7d 246int
247GetInteger(void)
248{
249 char *token = strtok(NULL, w_space);
250 int i;
251 if (token == NULL)
252 self_destruct();
253 if (sscanf(token, "%d", &i) != 1)
254 self_destruct();
255 return i;
256}
090089c4 257
cd748f27 258static void
259update_maxobjsize(void)
260{
261 int i;
e8dbac8b 262 ssize_t ms = -1;
cd748f27 263
264 for (i = 0; i < Config.cacheSwap.n_configured; i++) {
d3b3ab85 265 assert (Config.cacheSwap.swapDirs[i]);
266 if (Config.cacheSwap.swapDirs[i]->max_objsize > ms)
267 ms = Config.cacheSwap.swapDirs[i]->max_objsize;
cd748f27 268 }
269 store_maxobjsize = ms;
270}
271
270b86af 272int
273parseConfigFile(const char *file_name)
2546fcb3 274{
270b86af 275 FILE *fp = NULL;
276 char *token = NULL;
72121e8b 277 char *tmp_line;
e13ee7ad 278 int err_count = 0;
1741cbad 279 int is_pipe = 0;
42bf7c64 280 configFreeMemory();
0153d498 281 default_all();
1741cbad 282 if (file_name[0] == '!' || file_name[0] == '|') {
283 fp = popen(file_name + 1, "r");
284 is_pipe = 1;
285 } else {
286 fp = fopen(file_name, "r");
287 }
288 if (fp == NULL)
137ee196 289 fatalf("Unable to open configuration file: %s: %s",
270b86af 290 file_name, xstrerror());
e24070c5 291#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
c4aefe96 292 setmode(fileno(fp), O_TEXT);
293#endif
270b86af 294 cfg_filename = file_name;
1741cbad 295 if (is_pipe)
296 cfg_filename = file_name + 1;
297 else if ((token = strrchr(cfg_filename, '/')))
270b86af 298 cfg_filename = token + 1;
299 memset(config_input_line, '\0', BUFSIZ);
300 config_lineno = 0;
301 while (fgets(config_input_line, BUFSIZ, fp)) {
302 config_lineno++;
303 if ((token = strchr(config_input_line, '\n')))
304 *token = '\0';
1741cbad 305 if (strncmp(config_input_line, "#line ", 6) == 0) {
306 static char new_file_name[1024];
307 static char *file;
308 static char new_lineno;
309 token = config_input_line + 6;
310 new_lineno = strtol(token, &file, 0) - 1;
311 if (file == token)
312 continue; /* Not a valid #line directive, may be a comment */
313 while (*file && isspace((unsigned char) *file))
314 file++;
315 if (*file) {
316 if (*file != '"')
317 continue; /* Not a valid #line directive, may be a comment */
318 xstrncpy(new_file_name, file + 1, sizeof(new_file_name));
319 if ((token = strchr(new_file_name, '"')))
320 *token = '\0';
321 cfg_filename = new_file_name;
322#if PROBABLY_NOT_WANTED_HERE
323 if ((token = strrchr(cfg_filename, '/')))
324 cfg_filename = token + 1;
325#endif
326 }
327 config_lineno = new_lineno;
328 }
270b86af 329 if (config_input_line[0] == '#')
330 continue;
331 if (config_input_line[0] == '\0')
332 continue;
333 debug(3, 5) ("Processing: '%s'\n", config_input_line);
72121e8b 334 tmp_line = xstrdup(config_input_line);
270b86af 335 if (!parse_line(tmp_line)) {
1741cbad 336 debug(3, 0) ("parseConfigFile: '%s' line %d unrecognized: '%s'\n",
337 cfg_filename,
270b86af 338 config_lineno,
339 config_input_line);
e13ee7ad 340 err_count++;
270b86af 341 }
72121e8b 342 safe_free(tmp_line);
270b86af 343 }
1741cbad 344 if (is_pipe) {
345 int ret = pclose(fp);
346 if (ret != 0)
347 fatalf("parseConfigFile: '%s' failed with exit code %d\n", file_name, ret);
348 } else {
349 fclose(fp);
350 }
f0b19334 351 defaults_if_none();
352 configDoConfigure();
22f3fd98 353 cachemgrRegister("config",
354 "Current Squid Configuration",
355 dump_config,
1da3b90b 356 1, 1);
e13ee7ad 357 return err_count;
f0b19334 358}
270b86af 359
f0b19334 360static void
361configDoConfigure(void)
362{
f0b19334 363 memset(&Config2, '\0', sizeof(SquidConfig2));
7021844c 364 /* init memory as early as possible */
365 memConfigure();
270b86af 366 /* Sanity checks */
a95856a0 367 if (Config.cacheSwap.swapDirs == NULL)
368 fatal("No cache_dir's specified in config file");
9fa8263f 369 /* calculate Config.Swap.maxSize */
f4e3fa54 370 storeDirConfigure();
82e2afd9 371 if (0 == Config.Swap.maxSize)
372 /* people might want a zero-sized cache on purpose */
373 (void) 0;
374 else if (Config.Swap.maxSize < (Config.memMaxSize >> 10))
92b5d5b7 375 debug(3, 0) ("WARNING cache_mem is larger than total disk cache space!\n");
84f42bac 376 if (Config.Announce.period > 0) {
377 Config.onoff.announce = 1;
378 } else if (Config.Announce.period < 1) {
f1dc9b30 379 Config.Announce.period = 86400 * 365; /* one year */
17a0a4ee 380 Config.onoff.announce = 0;
270b86af 381 }
6b53c392 382#if USE_DNSSERVERS
f0b19334 383 if (Config.dnsChildren < 1)
384 fatal("No dnsservers allocated");
efd900cb 385#endif
270b86af 386 if (Config.Program.redirect) {
387 if (Config.redirectChildren < 1) {
388 Config.redirectChildren = 0;
c6d5b87b 389 wordlistDestroy(&Config.Program.redirect);
270b86af 390 }
fea2e6e0 391 }
f1dc9b30 392 if (Config.appendDomain)
393 if (*Config.appendDomain != '.')
394 fatal("append_domain must begin with a '.'");
270b86af 395 if (Config.errHtmlText == NULL)
396 Config.errHtmlText = xstrdup(null_string);
397 storeConfigure();
52f772de 398 snprintf(ThisCache, sizeof(ThisCache), "%s (%s)",
98829f69 399 uniqueHostname(),
137ee196 400 full_appname_string);
38a6c74e 401 /*
402 * the extra space is for loop detection in client_side.c -- we search
403 * for substrings in the Via header.
404 */
52f772de 405 snprintf(ThisCache2, sizeof(ThisCache), " %s (%s)",
38a6c74e 406 uniqueHostname(),
38a6c74e 407 full_appname_string);
270b86af 408 if (!Config.udpMaxHitObjsz || Config.udpMaxHitObjsz > SQUID_UDP_SO_SNDBUF)
409 Config.udpMaxHitObjsz = SQUID_UDP_SO_SNDBUF;
410 if (Config.appendDomain)
411 Config.appendDomainLen = strlen(Config.appendDomain);
412 else
413 Config.appendDomainLen = 0;
f1dc9b30 414 safe_free(debug_options)
415 debug_options = xstrdup(Config.debugOptions);
22c653cd 416 if (Config.retry.timeout < 5)
417 fatal("minimum_retry_timeout must be at least 5 seconds");
418 if (Config.retry.maxtries > 10)
419 fatal("maximum_single_addr_tries cannot be larger than 10");
420 if (Config.retry.maxtries < 1) {
22c653cd 421 debug(3, 0) ("WARNING: resetting 'maximum_single_addr_tries to 1\n");
5210854d 422 Config.retry.maxtries = 1;
423 }
f0b19334 424 requirePathnameExists("MIME Config Table", Config.mimeTablePathname);
6b53c392 425#if USE_DNSSERVERS
f0b19334 426 requirePathnameExists("cache_dns_program", Config.Program.dnsserver);
efd900cb 427#endif
a3d0a19d 428#if USE_UNLINKD
f0b19334 429 requirePathnameExists("unlinkd_program", Config.Program.unlinkd);
a3d0a19d 430#endif
f0b19334 431 if (Config.Program.redirect)
c6d5b87b 432 requirePathnameExists("redirect_program", Config.Program.redirect->key);
f0b19334 433 requirePathnameExists("Icon Directory", Config.icons.directory);
434 requirePathnameExists("Error Directory", Config.errorDirectory);
9f60cfdf 435#if HTTP_VIOLATIONS
436 {
49c0f46d 437 const refresh_t *R;
438 for (R = Config.Refresh; R; R = R->next) {
439 if (!R->flags.override_expire)
440 continue;
441 debug(22, 1) ("WARNING: use of 'override-expire' in 'refresh_pattern' violates HTTP\n");
442 break;
443 }
444 for (R = Config.Refresh; R; R = R->next) {
445 if (!R->flags.override_lastmod)
446 continue;
447 debug(22, 1) ("WARNING: use of 'override-lastmod' in 'refresh_pattern' violates HTTP\n");
448 break;
449 }
9f60cfdf 450 }
c2f5c744 451#endif
452#if !HTTP_VIOLATIONS
453 Config.onoff.via = 1;
454#else
455 if (!Config.onoff.via)
456 debug(22, 1) ("WARNING: HTTP requires the use of Via\n");
9f60cfdf 457#endif
db1cd23c 458 if (Config.Wais.relayHost) {
29b8d8d6 459 if (Config.Wais._peer)
460 cbdataFree(Config.Wais._peer);
461 Config.Wais._peer = cbdataAlloc(peer);
462 Config.Wais._peer->host = xstrdup(Config.Wais.relayHost);
463 Config.Wais._peer->http_port = Config.Wais.relayPort;
db1cd23c 464 }
53cb32a9 465 if (aclPurgeMethodInUse(Config.accessList.http))
466 Config2.onoff.enable_purge = 1;
8749fa47 467 if (geteuid() == 0) {
468 if (NULL != Config.effectiveUser) {
2d72d4fd 469 struct passwd *pwd = getpwnam(Config.effectiveUser);
470 if (NULL == pwd)
471 /*
472 * Andres Kroonmaa <andre@online.ee>:
473 * Some getpwnam() implementations (Solaris?) require
474 * an available FD < 256 for opening a FILE* to the
475 * passwd file.
476 * DW:
477 * This should be safe at startup, but might still fail
478 * during reconfigure.
479 */
480 fatalf("getpwnam failed to find userid for effective user '%s'",
04bd8d25 481 Config.effectiveUser);
2d72d4fd 482 Config2.effectiveUserID = pwd->pw_uid;
963a4014 483 Config2.effectiveGroupID = pwd->pw_gid;
2d72d4fd 484 }
8749fa47 485 } else {
486 Config2.effectiveUserID = geteuid();
487 Config2.effectiveGroupID = getegid();
d20b1cd0 488 }
489 if (NULL != Config.effectiveGroup) {
490 struct group *grp = getgrnam(Config.effectiveGroup);
491 if (NULL == grp)
492 fatalf("getgrnam failed to find groupid for effective group '%s'",
04bd8d25 493 Config.effectiveGroup);
d20b1cd0 494 Config2.effectiveGroupID = grp->gr_gid;
495 }
56fe752e 496 urlExtMethodConfigure();
feb32c6e 497 if (0 == Config.onoff.client_db) {
498 acl *a;
499 for (a = Config.aclList; a; a = a->next) {
8000a965 500 if (ACL_MAXCONN != a->aclType())
feb32c6e 501 continue;
502 debug(22, 0) ("WARNING: 'maxconn' ACL (%s) won't work with client_db disabled\n", a->name);
503 }
504 }
a7ad6e4e 505#if USE_SSL
506 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);
507#endif
090089c4 508}
509
270b86af 510/* Parse a time specification from the config file. Store the
f1dc9b30 511 * result in 'tptr', after converting it to 'units' */
8203a132 512static void
a47b9029 513parseTimeLine(time_t * tptr, const char *units)
090089c4 514{
515 char *token;
270b86af 516 double d;
f1dc9b30 517 time_t m;
518 time_t u;
270b86af 519 if ((u = parseTimeUnits(units)) == 0)
3003c0f3 520 self_destruct();
270b86af 521 if ((token = strtok(NULL, w_space)) == NULL)
3003c0f3 522 self_destruct();
5c20d6fa 523 d = xatof(token);
270b86af 524 m = u; /* default to 'units' if none specified */
10738561 525 if (0 == d)
526 (void) 0;
527 else if ((token = strtok(NULL, w_space)) == NULL)
a47b9029 528 debug(3, 0) ("WARNING: No units on '%s', assuming %f %s\n",
529 config_input_line, d, units);
9e975e4e 530 else if ((m = parseTimeUnits(token)) == 0)
a47b9029 531 self_destruct();
e6ccf245 532 *tptr = static_cast<time_t> (m * d / u);
090089c4 533}
534
270b86af 535static int
536parseTimeUnits(const char *unit)
537{
538 if (!strncasecmp(unit, T_SECOND_STR, strlen(T_SECOND_STR)))
539 return 1;
540 if (!strncasecmp(unit, T_MINUTE_STR, strlen(T_MINUTE_STR)))
541 return 60;
542 if (!strncasecmp(unit, T_HOUR_STR, strlen(T_HOUR_STR)))
543 return 3600;
544 if (!strncasecmp(unit, T_DAY_STR, strlen(T_DAY_STR)))
545 return 86400;
546 if (!strncasecmp(unit, T_WEEK_STR, strlen(T_WEEK_STR)))
547 return 86400 * 7;
548 if (!strncasecmp(unit, T_FORTNIGHT_STR, strlen(T_FORTNIGHT_STR)))
549 return 86400 * 14;
550 if (!strncasecmp(unit, T_MONTH_STR, strlen(T_MONTH_STR)))
551 return 86400 * 30;
552 if (!strncasecmp(unit, T_YEAR_STR, strlen(T_YEAR_STR)))
e6ccf245 553 return static_cast<int>(86400 * 365.2522);
270b86af 554 if (!strncasecmp(unit, T_DECADE_STR, strlen(T_DECADE_STR)))
e6ccf245 555 return static_cast<int>(86400 * 365.2522 * 10);
270b86af 556 debug(3, 1) ("parseTimeUnits: unknown time unit '%s'\n", unit);
557 return 0;
558}
559
9906e724 560static void
9e975e4e 561parseBytesLine(size_t * bptr, const char *units)
9906e724 562{
563 char *token;
564 double d;
565 size_t m;
566 size_t u;
567 if ((u = parseBytesUnits(units)) == 0)
568 self_destruct();
569 if ((token = strtok(NULL, w_space)) == NULL)
570 self_destruct();
5c20d6fa 571 d = xatof(token);
9906e724 572 m = u; /* default to 'units' if none specified */
343f47a3 573 if (0.0 == d)
10738561 574 (void) 0;
4860dc1b 575 else if ((token = strtok(NULL, w_space)) == NULL)
9e975e4e 576 debug(3, 0) ("WARNING: No units on '%s', assuming %f %s\n",
577 config_input_line, d, units);
578 else if ((m = parseBytesUnits(token)) == 0)
579 self_destruct();
e6ccf245 580 *bptr = static_cast<size_t>(m * d / u);
9906e724 581}
582
583static size_t
584parseBytesUnits(const char *unit)
585{
586 if (!strncasecmp(unit, B_BYTES_STR, strlen(B_BYTES_STR)))
587 return 1;
588 if (!strncasecmp(unit, B_KBYTES_STR, strlen(B_KBYTES_STR)))
a47b9029 589 return 1 << 10;
9906e724 590 if (!strncasecmp(unit, B_MBYTES_STR, strlen(B_MBYTES_STR)))
a47b9029 591 return 1 << 20;
9906e724 592 if (!strncasecmp(unit, B_GBYTES_STR, strlen(B_GBYTES_STR)))
a47b9029 593 return 1 << 30;
9906e724 594 debug(3, 1) ("parseBytesUnits: unknown bytes unit '%s'\n", unit);
595 return 0;
596}
597
270b86af 598/*****************************************************************************
599 * Max
600 *****************************************************************************/
601
8203a132 602static void
9ef28b60 603dump_acl(StoreEntry * entry, const char *name, acl * ae)
090089c4 604{
56b63fa1 605 wordlist *w;
606 wordlist *v;
9ef28b60 607 while (ae != NULL) {
c68e9c6b 608 debug(3, 3) ("dump_acl: %s %s\n", name, ae->name);
5dee515e 609 storeAppendPrintf(entry, "%s %s %s ",
610 name,
611 ae->name,
612 ae->typeString());
8000a965 613 v = w = ae->dumpGeneric();
56b63fa1 614 while (v != NULL) {
c68e9c6b 615 debug(3, 3) ("dump_acl: %s %s %s\n", name, ae->name, v->key);
5dee515e 616 storeAppendPrintf(entry, "%s ", v->key);
56b63fa1 617 v = v->next;
618 }
5dee515e 619 storeAppendPrintf(entry, "\n");
56b63fa1 620 wordlistDestroy(&w);
9ef28b60 621 ae = ae->next;
56b63fa1 622 }
090089c4 623}
624
8203a132 625static void
9ef28b60 626parse_acl(acl ** ae)
090089c4 627{
8000a965 628 ACL::ParseAclLine(ae);
f1dc9b30 629}
630
631static void
9ef28b60 632free_acl(acl ** ae)
f1dc9b30 633{
9ef28b60 634 aclDestroyAcls(ae);
090089c4 635}
636
8203a132 637static void
d6827718 638dump_acl_list(StoreEntry * entry, acl_list * head)
30a4f2a8 639{
56b63fa1 640 acl_list *l;
d6827718 641 for (l = head; l; l = l->next) {
642 storeAppendPrintf(entry, " %s%s",
643 l->op ? null_string : "!",
29b8d8d6 644 l->_acl->name);
d6827718 645 }
646}
647
b67e2c8c 648void
d6827718 649dump_acl_access(StoreEntry * entry, const char *name, acl_access * head)
650{
651 acl_access *l;
652 for (l = head; l; l = l->next) {
505e35db 653 storeAppendPrintf(entry, "%s %s",
0cdcddb9 654 name,
d6827718 655 l->allow ? "Allow" : "Deny");
29b8d8d6 656 dump_acl_list(entry, l->aclList);
505e35db 657 storeAppendPrintf(entry, "\n");
56b63fa1 658 }
30a4f2a8 659}
090089c4 660
8203a132 661static void
16300b58 662parse_acl_access(acl_access ** head)
090089c4 663{
270b86af 664 aclParseAccessLine(head);
090089c4 665}
666
0153d498 667static void
16300b58 668free_acl_access(acl_access ** head)
0153d498 669{
a47b9029 670 aclDestroyAccessList(head);
0153d498 671}
672
8203a132 673static void
a7d59104 674dump_address(StoreEntry * entry, const char *name, struct in_addr addr)
270b86af 675{
f53b06f9 676 storeAppendPrintf(entry, "%s %s\n", name, inet_ntoa(addr));
270b86af 677}
678
679static void
680parse_address(struct in_addr *addr)
090089c4 681{
0ee4272b 682 const struct hostent *hp;
270b86af 683 char *token = strtok(NULL, w_space);
684
30a4f2a8 685 if (token == NULL)
686 self_destruct();
429fdbec 687 if (safe_inet_addr(token, addr) == 1)
688 (void) 0;
ceb8994e 689 else if ((hp = gethostbyname(token))) /* dont use ipcache */
1d73e33a 690 *addr = inaddrFromHostent(hp);
30a4f2a8 691 else
3003c0f3 692 self_destruct();
090089c4 693}
694
0153d498 695static void
696free_address(struct in_addr *addr)
697{
a47b9029 698 memset(addr, '\0', sizeof(struct in_addr));
0153d498 699}
700
d6827718 701CBDATA_TYPE(acl_address);
702
703static void
704dump_acl_address(StoreEntry * entry, const char *name, acl_address * head)
705{
706 acl_address *l;
707 for (l = head; l; l = l->next) {
708 if (l->addr.s_addr != INADDR_ANY)
709 storeAppendPrintf(entry, "%s %s", name, inet_ntoa(l->addr));
710 else
711 storeAppendPrintf(entry, "%s autoselect", name);
29b8d8d6 712 dump_acl_list(entry, l->aclList);
d6827718 713 storeAppendPrintf(entry, "\n");
714 }
715}
716
717static void
718freed_acl_address(void *data)
719{
e6ccf245 720 acl_address *l = static_cast<acl_address *>(data);
29b8d8d6 721 aclDestroyAclList(&l->aclList);
d6827718 722}
723
724static void
725parse_acl_address(acl_address ** head)
726{
727 acl_address *l;
728 acl_address **tail = head; /* sane name below */
729 CBDATA_INIT_TYPE_FREECB(acl_address, freed_acl_address);
730 l = cbdataAlloc(acl_address);
731 parse_address(&l->addr);
29b8d8d6 732 aclParseAclList(&l->aclList);
d6827718 733 while (*tail)
734 tail = &(*tail)->next;
735 *tail = l;
736}
737
738static void
739free_acl_address(acl_address ** head)
740{
741 while (*head) {
742 acl_address *l = *head;
743 *head = l->next;
744 cbdataFree(l);
745 }
746}
747
748CBDATA_TYPE(acl_tos);
749
750static void
751dump_acl_tos(StoreEntry * entry, const char *name, acl_tos * head)
752{
753 acl_tos *l;
754 for (l = head; l; l = l->next) {
755 if (l->tos > 0)
756 storeAppendPrintf(entry, "%s 0x%02X", name, l->tos);
757 else
758 storeAppendPrintf(entry, "%s none", name);
29b8d8d6 759 dump_acl_list(entry, l->aclList);
d6827718 760 storeAppendPrintf(entry, "\n");
761 }
762}
763
764static void
765freed_acl_tos(void *data)
766{
e6ccf245 767 acl_tos *l = static_cast<acl_tos *>(data);
29b8d8d6 768 aclDestroyAclList(&l->aclList);
d6827718 769}
770
771static void
772parse_acl_tos(acl_tos ** head)
773{
774 acl_tos *l;
775 acl_tos **tail = head; /* sane name below */
776 int tos;
777 char junk;
778 char *token = strtok(NULL, w_space);
779 if (!token)
780 self_destruct();
781 if (sscanf(token, "0x%x%c", &tos, &junk) != 1)
782 self_destruct();
783 if (tos < 0 || tos > 255)
784 self_destruct();
785 CBDATA_INIT_TYPE_FREECB(acl_tos, freed_acl_tos);
786 l = cbdataAlloc(acl_tos);
787 l->tos = tos;
29b8d8d6 788 aclParseAclList(&l->aclList);
d6827718 789 while (*tail)
790 tail = &(*tail)->next;
791 *tail = l;
792}
793
794static void
795free_acl_tos(acl_tos ** head)
796{
797 while (*head) {
798 acl_tos *l = *head;
799 *head = l->next;
800 l->next = NULL;
801 cbdataFree(l);
802 }
803}
804
59715b38 805#if DELAY_POOLS
806
b67e2c8c 807#include "DelayPools.h"
808#include "DelayConfig.h"
59715b38 809/* do nothing - free_delay_pool_count is the magic free function.
810 * this is why delay_pool_count isn't just marked TYPE: ushort
811 */
812#define free_delay_pool_class(X)
813#define free_delay_pool_access(X)
814#define free_delay_pool_rates(X)
815#define dump_delay_pool_class(X, Y, Z)
816#define dump_delay_pool_access(X, Y, Z)
817#define dump_delay_pool_rates(X, Y, Z)
818
819static void
b67e2c8c 820free_delay_pool_count(DelayConfig * cfg)
59715b38 821{
b67e2c8c 822 cfg->freePoolCount();
59715b38 823}
824
825static void
b67e2c8c 826dump_delay_pool_count(StoreEntry * entry, const char *name, DelayConfig &cfg)
59715b38 827{
b67e2c8c 828 cfg.dumpPoolCount (entry, name);
59715b38 829}
830
831static void
b67e2c8c 832parse_delay_pool_count(DelayConfig * cfg)
59715b38 833{
b67e2c8c 834 cfg->parsePoolCount();
59715b38 835}
836
837static void
b67e2c8c 838parse_delay_pool_class(DelayConfig * cfg)
59715b38 839{
b67e2c8c 840 cfg->parsePoolClass();
59715b38 841}
842
843static void
b67e2c8c 844parse_delay_pool_rates(DelayConfig * cfg)
59715b38 845{
b67e2c8c 846 cfg->parsePoolRates();
59715b38 847}
848
849static void
b67e2c8c 850parse_delay_pool_access(DelayConfig * cfg)
59715b38 851{
b67e2c8c 852 cfg->parsePoolAccess();
59715b38 853}
854#endif
855
e6ccf245 856#ifdef HTTP_VIOLATIONS
97474590 857static void
6bccf575 858dump_http_header_access(StoreEntry * entry, const char *name, header_mangler header[])
e3dd531e 859{
efd900cb 860 int i;
6bccf575 861 for (i = 0; i < HDR_ENUM_END; i++) {
862 if (header[i].access_list != NULL) {
72711e31 863 storeAppendPrintf(entry, "%s ", name);
6bccf575 864 dump_acl_access(entry, httpHeaderNameById(i),
865 header[i].access_list);
866 }
efd900cb 867 }
97474590 868}
e3dd531e 869
97474590 870static void
6bccf575 871parse_http_header_access(header_mangler header[])
97474590 872{
6bccf575 873 int id, i;
97474590 874 char *t = NULL;
97474590 875 if ((t = strtok(NULL, w_space)) == NULL) {
876 debug(3, 0) ("%s line %d: %s\n",
877 cfg_filename, config_lineno, config_input_line);
6bccf575 878 debug(3, 0) ("parse_http_header_access: missing header name.\n");
97474590 879 return;
880 }
6bccf575 881 /* Now lookup index of header. */
882 id = httpHeaderIdByNameDef(t, strlen(t));
883 if (strcmp(t, "All") == 0)
884 id = HDR_ENUM_END;
885 else if (strcmp(t, "Other") == 0)
886 id = HDR_OTHER;
887 else if (id == -1) {
97474590 888 debug(3, 0) ("%s line %d: %s\n",
889 cfg_filename, config_lineno, config_input_line);
6bccf575 890 debug(3, 0) ("parse_http_header_access: unknown header name %s.\n", t);
97474590 891 return;
892 }
6bccf575 893 if (id != HDR_ENUM_END) {
894 parse_acl_access(&header[id].access_list);
895 } else {
72711e31 896 char *next_string = t + strlen(t) - 1;
de3ee917 897 *next_string = 'A';
72711e31 898 *(next_string + 1) = ' ';
6bccf575 899 for (i = 0; i < HDR_ENUM_END; i++) {
900 char *new_string = xstrdup(next_string);
de3ee917 901 strtok(new_string, w_space);
6bccf575 902 parse_acl_access(&header[i].access_list);
903 safe_free(new_string);
efd900cb 904 }
97474590 905 }
6bccf575 906}
907
908static void
909free_http_header_access(header_mangler header[])
910{
911 int i;
912 for (i = 0; i < HDR_ENUM_END; i++) {
913 free_acl_access(&header[i].access_list);
914 }
915}
916
917static void
918dump_http_header_replace(StoreEntry * entry, const char *name, header_mangler
919 header[])
920{
921 int i;
6bccf575 922 for (i = 0; i < HDR_ENUM_END; i++) {
923 if (NULL == header[i].replacement)
924 continue;
de3ee917 925 storeAppendPrintf(entry, "%s %s %s\n", name, httpHeaderNameById(i),
6bccf575 926 header[i].replacement);
97474590 927 }
928}
e3dd531e 929
97474590 930static void
6bccf575 931parse_http_header_replace(header_mangler header[])
e3dd531e 932{
6bccf575 933 int id, i;
934 char *t = NULL;
935 if ((t = strtok(NULL, w_space)) == NULL) {
936 debug(3, 0) ("%s line %d: %s\n",
937 cfg_filename, config_lineno, config_input_line);
938 debug(3, 0) ("parse_http_header_replace: missing header name.\n");
939 return;
940 }
941 /* Now lookup index of header. */
942 id = httpHeaderIdByNameDef(t, strlen(t));
943 if (strcmp(t, "All") == 0)
944 id = HDR_ENUM_END;
945 else if (strcmp(t, "Other") == 0)
946 id = HDR_OTHER;
947 else if (id == -1) {
948 debug(3, 0) ("%s line %d: %s\n",
949 cfg_filename, config_lineno, config_input_line);
950 debug(3, 0) ("parse_http_header_replace: unknown header name %s.\n",
951 t);
952 return;
953 }
954 if (id != HDR_ENUM_END) {
955 if (header[id].replacement != NULL)
956 safe_free(header[id].replacement);
957 header[id].replacement = xstrdup(t + strlen(t) + 1);
958 } else {
959 for (i = 0; i < HDR_ENUM_END; i++) {
960 if (header[i].replacement != NULL)
961 safe_free(header[i].replacement);
962 header[i].replacement = xstrdup(t + strlen(t) + 1);
963 }
964 }
965}
966
967static void
968free_http_header_replace(header_mangler header[])
969{
970 int i;
971 for (i = 0; i < HDR_ENUM_END; i++) {
972 if (header[i].replacement != NULL)
973 safe_free(header[i].replacement);
974 }
97474590 975}
9e8b2f1c 976#endif
97474590 977
25a77f03 978void
d3b3ab85 979dump_cachedir_options(StoreEntry * entry, struct cache_dir_option *options, SwapDir const * sd)
25a77f03 980{
981 struct cache_dir_option *option;
982 if (!options)
983 return;
984 for (option = options; option->name; option++)
985 option->dump(entry, option->name, sd);
986}
987
e90100aa 988static void
e6ccf245 989dump_cachedir(StoreEntry * entry, const char *name, _SquidConfig::_cacheSwap swap)
e90100aa 990{
f53b06f9 991 SwapDir *s;
992 int i;
d3b3ab85 993 assert (entry);
a7d59104 994 for (i = 0; i < swap.n_configured; i++) {
d3b3ab85 995 s = swap.swapDirs[i];
25a77f03 996 storeAppendPrintf(entry, "%s %s %s", name, s->type, s->path);
d3b3ab85 997 s->dump(*entry);
25a77f03 998 dump_cachedir_options(entry, common_cachedir_options, s);
999 storeAppendPrintf(entry, "\n");
f53b06f9 1000 }
1001}
1002
1003static int
e6ccf245 1004check_null_cachedir(_SquidConfig::_cacheSwap swap)
f53b06f9 1005{
1006 return swap.swapDirs == NULL;
e90100aa 1007}
1008
53ad48e6 1009static int
1010check_null_string(char *s)
1011{
1012 return s == NULL;
1013}
1014
2d72d4fd 1015static void
94439e4e 1016allocate_new_authScheme(authConfig * cfg)
1017{
1018 if (cfg->schemes == NULL) {
1019 cfg->n_allocated = 4;
e6ccf245 1020 cfg->schemes = static_cast<authScheme *>(xcalloc(cfg->n_allocated, sizeof(authScheme)));
94439e4e 1021 }
1022 if (cfg->n_allocated == cfg->n_configured) {
1023 authScheme *tmp;
1024 cfg->n_allocated <<= 1;
e6ccf245 1025 tmp = static_cast<authScheme *>(xcalloc(cfg->n_allocated, sizeof(authScheme)));
94439e4e 1026 xmemcpy(tmp, cfg->schemes, cfg->n_configured * sizeof(authScheme));
1027 xfree(cfg->schemes);
1028 cfg->schemes = tmp;
1029 }
1030}
1031
1032static void
1033parse_authparam(authConfig * config)
1034{
1035 char *type_str;
1036 char *param_str;
1037 authScheme *scheme = NULL;
1038 int type, i;
1039
1040 if ((type_str = strtok(NULL, w_space)) == NULL)
1041 self_destruct();
1042
1043 if ((param_str = strtok(NULL, w_space)) == NULL)
1044 self_destruct();
1045
1046 if ((type = authenticateAuthSchemeId(type_str)) == -1) {
1047 debug(3, 0) ("Parsing Config File: Unknown authentication scheme '%s'.\n", type_str);
1048 return;
1049 }
1050 for (i = 0; i < config->n_configured; i++) {
1051 if (config->schemes[i].Id == type) {
1052 scheme = config->schemes + i;
1053 }
1054 }
1055
1056 if (scheme == NULL) {
1057 allocate_new_authScheme(config);
1058 scheme = config->schemes + config->n_configured;
1059 config->n_configured++;
1060 scheme->Id = type;
1061 scheme->typestr = authscheme_list[type].typestr;
1062 }
1063 authscheme_list[type].parse(scheme, config->n_configured, param_str);
1064}
1065
1066static void
1067free_authparam(authConfig * cfg)
1068{
1069 authScheme *scheme;
1070 int i;
1071 /* DON'T FREE THESE FOR RECONFIGURE */
1072 if (reconfiguring)
1073 return;
1074 for (i = 0; i < cfg->n_configured; i++) {
1075 scheme = cfg->schemes + i;
1076 authscheme_list[scheme->Id].freeconfig(scheme);
1077 }
1078 safe_free(cfg->schemes);
1079 cfg->schemes = NULL;
1080 cfg->n_allocated = 0;
1081 cfg->n_configured = 0;
1082}
1083
1084static void
1085dump_authparam(StoreEntry * entry, const char *name, authConfig cfg)
1086{
1087 authScheme *scheme;
1088 int i;
1089 for (i = 0; i < cfg.n_configured; i++) {
1090 scheme = cfg.schemes + i;
1091 authscheme_list[scheme->Id].dump(entry, name, scheme);
1092 }
1093}
1094
0e4e0e7d 1095void
e6ccf245 1096allocate_new_swapdir(_SquidConfig::_cacheSwap * swap)
090089c4 1097{
f1dc9b30 1098 if (swap->swapDirs == NULL) {
1099 swap->n_allocated = 4;
d3b3ab85 1100 swap->swapDirs = static_cast<SwapDir **>(xcalloc(swap->n_allocated, sizeof(SwapDir *)));
f1dc9b30 1101 }
1102 if (swap->n_allocated == swap->n_configured) {
d3b3ab85 1103 SwapDir **tmp;
f1dc9b30 1104 swap->n_allocated <<= 1;
d3b3ab85 1105 tmp = static_cast<SwapDir **>(xcalloc(swap->n_allocated, sizeof(SwapDir *)));
1106 xmemcpy(tmp, swap->swapDirs, swap->n_configured * sizeof(SwapDir *));
f1dc9b30 1107 xfree(swap->swapDirs);
1108 swap->swapDirs = tmp;
1109 }
0e4e0e7d 1110}
1111
cd748f27 1112static int
1113find_fstype(char *type)
1114{
1115 int i;
1116 for (i = 0; storefs_list[i].typestr != NULL; i++) {
a4b8110e 1117 if (strcasecmp(type, storefs_list[i].typestr) == 0) {
cd748f27 1118 return i;
1119 }
1120 }
1121 return (-1);
1122}
1123
0e4e0e7d 1124static void
e6ccf245 1125parse_cachedir(_SquidConfig::_cacheSwap * swap)
0e4e0e7d 1126{
1127 char *type_str;
cd748f27 1128 char *path_str;
1129 SwapDir *sd;
1130 int i;
1131 int fs;
cd748f27 1132
0e4e0e7d 1133 if ((type_str = strtok(NULL, w_space)) == NULL)
1134 self_destruct();
cd748f27 1135
cd748f27 1136 if ((path_str = strtok(NULL, w_space)) == NULL)
1137 self_destruct();
1138
1139 /*
1140 * This bit of code is a little strange.
1141 * See, if we find a path and type match for a given line, then
1142 * as long as we're reconfiguring, we can just call its reconfigure
1143 * function. No harm there.
1144 *
1145 * Trouble is, if we find a path match, but not a type match, we have
1146 * a dilemma - we could gracefully shut down the fs, kill it, and
1147 * create a new one of a new type in its place, BUT at this stage the
1148 * fs is meant to be the *NEW* one, and so things go very strange. :-)
1149 *
1150 * So, we'll assume the person isn't going to change the fs type for now,
1151 * and XXX later on we will make sure that its picked up.
1152 *
1153 * (moving around cache_dir lines will be looked at later in a little
1154 * more sane detail..)
1155 */
1156
1157 for (i = 0; i < swap->n_configured; i++) {
d3b3ab85 1158 assert (swap->swapDirs[i]);
1159 if (0 == strcasecmp(path_str, swap->swapDirs[i]->path)) {
cd748f27 1160 /* This is a little weird, you'll appreciate it later */
1161 fs = find_fstype(type_str);
1162 if (fs < 0) {
a4b8110e 1163 fatalf("Unknown cache_dir type '%s'\n", type_str);
cd748f27 1164 }
d3b3ab85 1165 sd = swap->swapDirs[i];
1166 sd->reconfigure (i, path_str);
a4b8110e 1167 update_maxobjsize();
1168 return;
cd748f27 1169 }
1170 }
1171
2b6662ba 1172 assert(swap->n_configured < 63); /* 7 bits, signed */
dc986280 1173
cd748f27 1174 fs = find_fstype(type_str);
1175 if (fs < 0) {
a4b8110e 1176 /* If we get here, we didn't find a matching cache_dir type */
1177 fatalf("Unknown cache_dir type '%s'\n", type_str);
0e4e0e7d 1178 }
cd748f27 1179 allocate_new_swapdir(swap);
d3b3ab85 1180 swap->swapDirs[swap->n_configured] = SwapDir::Factory(storefs_list[fs]);
1181 sd = swap->swapDirs[swap->n_configured];
8e8d4f30 1182 /* parse the FS parameters and options */
d3b3ab85 1183 sd->parse(swap->n_configured, path_str);
1184 ++swap->n_configured;
cd748f27 1185 /* Update the max object size */
1186 update_maxobjsize();
752c3b27 1187}
1188
8e8d4f30 1189static void
1190parse_cachedir_option_readonly(SwapDir * sd, const char *option, const char *value, int reconfiguring)
1191{
1192 int read_only = 0;
1193 if (value)
5c20d6fa 1194 read_only = xatoi(value);
8e8d4f30 1195 else
1196 read_only = 1;
1197 sd->flags.read_only = read_only;
1198}
1199
25a77f03 1200static void
d3b3ab85 1201dump_cachedir_option_readonly(StoreEntry * e, const char *option, SwapDir const * sd)
25a77f03 1202{
1203 if (sd->flags.read_only)
1204 storeAppendPrintf(e, " %s", option);
1205}
1206
8e8d4f30 1207static void
1208parse_cachedir_option_maxsize(SwapDir * sd, const char *option, const char *value, int reconfiguring)
1209{
1210 ssize_t size;
1211
1212 if (!value)
1213 self_destruct();
1214
5c20d6fa 1215 size = xatoi(value);
8e8d4f30 1216
1217 if (reconfiguring && sd->max_objsize != size)
32754419 1218 debug(3, 1) ("Cache dir '%s' max object size now %ld\n", sd->path, (long int) size);
8e8d4f30 1219
1220 sd->max_objsize = size;
1221}
1222
25a77f03 1223static void
d3b3ab85 1224dump_cachedir_option_maxsize(StoreEntry * e, const char *option, SwapDir const * sd)
25a77f03 1225{
1226 if (sd->max_objsize != -1)
32754419 1227 storeAppendPrintf(e, " %s=%ld", option, (long int) sd->max_objsize);
25a77f03 1228}
1229
8e8d4f30 1230void
1231parse_cachedir_options(SwapDir * sd, struct cache_dir_option *options, int reconfiguring)
1232{
e6ccf245 1233 unsigned int old_read_only = sd->flags.read_only;
8e8d4f30 1234 char *name, *value;
1235 struct cache_dir_option *option, *op;
1236
1237 while ((name = strtok(NULL, w_space)) != NULL) {
1238 value = strchr(name, '=');
1239 if (value)
1240 *value++ = '\0'; /* cut on = */
1241 option = NULL;
1242 if (options) {
1243 for (op = options; !option && op->name; op++) {
1244 if (strcmp(op->name, name) == 0) {
1245 option = op;
1246 break;
1247 }
1248 }
1249 }
1250 for (op = common_cachedir_options; !option && op->name; op++) {
1251 if (strcmp(op->name, name) == 0) {
1252 option = op;
1253 break;
1254 }
1255 }
1256 if (!option || !option->parse)
1257 self_destruct();
1258 option->parse(sd, name, value, reconfiguring);
1259 }
1260 /*
1261 * Handle notifications about reconfigured single-options with no value
1262 * where the removal of the option cannot be easily detected in the
1263 * parsing...
1264 */
1265 if (reconfiguring) {
1266 if (old_read_only != sd->flags.read_only) {
1267 debug(3, 1) ("Cache dir '%s' now %s\n",
1268 sd->path, sd->flags.read_only ? "Read-Only" : "Read-Write");
1269 }
1270 }
1271}
1272
8203a132 1273static void
e6ccf245 1274free_cachedir(_SquidConfig::_cacheSwap * swap)
f1dc9b30 1275{
a47b9029 1276 int i;
860ee7e3 1277 /* DON'T FREE THESE FOR RECONFIGURE */
5cd39a10 1278 if (reconfiguring)
860ee7e3 1279 return;
a47b9029 1280 for (i = 0; i < swap->n_configured; i++) {
d3b3ab85 1281 SwapDir * s = swap->swapDirs[i];
1282 swap->swapDirs[i] = NULL;
1283 delete s;
a47b9029 1284 }
1285 safe_free(swap->swapDirs);
1286 swap->swapDirs = NULL;
1287 swap->n_allocated = 0;
1288 swap->n_configured = 0;
f1dc9b30 1289}
1290
2d72d4fd 1291static const char *
505e35db 1292peer_type_str(const peer_t type)
1293{
0cdcddb9 1294 switch (type) {
505e35db 1295 case PEER_PARENT:
1296 return "parent";
1297 break;
1298 case PEER_SIBLING:
1299 return "sibling";
1300 break;
1301 case PEER_MULTICAST:
1302 return "multicast";
1303 break;
1304 default:
1305 return "unknown";
1306 break;
1307 }
1308}
1309
f1dc9b30 1310static void
a7d59104 1311dump_peer(StoreEntry * entry, const char *name, peer * p)
98ffb7e4 1312{
505e35db 1313 domain_ping *d;
505e35db 1314 domain_type *t;
1315 LOCAL_ARRAY(char, xname, 128);
d41de3c1 1316 while (p != NULL) {
1317 storeAppendPrintf(entry, "%s %s %s %d %d",
1318 name,
1319 p->host,
1320 neighborTypeStr(p),
1321 p->http_port,
399cabec 1322 p->icp.port);
a369131d 1323 dump_peer_options(entry, p);
b6a2f15e 1324 for (d = p->peer_domain; d; d = d->next) {
505e35db 1325 storeAppendPrintf(entry, "cache_peer_domain %s %s%s\n",
1326 p->host,
1327 d->do_ping ? null_string : "!",
1328 d->domain);
1329 }
1810dde6 1330 if (p->access) {
be753325 1331 snprintf(xname, 128, "cache_peer_access %s", p->name);
505e35db 1332 dump_acl_access(entry, xname, p->access);
1333 }
1334 for (t = p->typelist; t; t = t->next) {
1335 storeAppendPrintf(entry, "neighbor_type_domain %s %s %s\n",
1336 p->host,
1337 peer_type_str(t->type),
1338 t->domain);
1339 }
d41de3c1 1340 p = p->next;
1341 }
98ffb7e4 1342}
1343
8203a132 1344static void
40a1495e 1345parse_peer(peer ** head)
7813c6d5 1346{
270b86af 1347 char *token = NULL;
40a1495e 1348 peer *p;
7813c6d5 1349 int i;
72711e31 1350 p = cbdataAlloc(peer);
40a1495e 1351 p->http_port = CACHE_HTTP_PORT;
399cabec 1352 p->icp.port = CACHE_ICP_PORT;
40a1495e 1353 p->weight = 1;
d1b63fc8 1354 p->basetime = 0;
dc835977 1355 p->stats.logged_state = PEER_ALIVE;
e481c2dc 1356 if ((token = strtok(NULL, w_space)) == NULL)
270b86af 1357 self_destruct();
40a1495e 1358 p->host = xstrdup(token);
be753325 1359 p->name = xstrdup(token);
e481c2dc 1360 if ((token = strtok(NULL, w_space)) == NULL)
270b86af 1361 self_destruct();
40a1495e 1362 p->type = parseNeighborType(token);
0e4e0e7d 1363 i = GetInteger();
40a1495e 1364 p->http_port = (u_short) i;
0e4e0e7d 1365 i = GetInteger();
399cabec 1366 p->icp.port = (u_short) i;
270b86af 1367 while ((token = strtok(NULL, w_space))) {
1368 if (!strcasecmp(token, "proxy-only")) {
cd196bc8 1369 p->options.proxy_only = 1;
270b86af 1370 } else if (!strcasecmp(token, "no-query")) {
cd196bc8 1371 p->options.no_query = 1;
d1b63fc8 1372 } else if (!strcasecmp(token, "background-ping")) {
1373 p->options.background_ping = 1;
8638fc66 1374 } else if (!strcasecmp(token, "no-digest")) {
cd196bc8 1375 p->options.no_digest = 1;
270b86af 1376 } else if (!strcasecmp(token, "multicast-responder")) {
cd196bc8 1377 p->options.mcast_responder = 1;
270b86af 1378 } else if (!strncasecmp(token, "weight=", 7)) {
5c20d6fa 1379 p->weight = xatoi(token + 7);
d1b63fc8 1380 } else if (!strncasecmp(token, "basetime=", 9)) {
5c20d6fa 1381 p->basetime = xatoi(token + 9);
0103c4c1 1382 } else if (!strcasecmp(token, "closest-only")) {
cd196bc8 1383 p->options.closest_only = 1;
270b86af 1384 } else if (!strncasecmp(token, "ttl=", 4)) {
5c20d6fa 1385 p->mcast.ttl = xatoi(token + 4);
40a1495e 1386 if (p->mcast.ttl < 0)
1387 p->mcast.ttl = 0;
1388 if (p->mcast.ttl > 128)
1389 p->mcast.ttl = 128;
0103c4c1 1390 } else if (!strcasecmp(token, "default")) {
cd196bc8 1391 p->options.default_parent = 1;
0103c4c1 1392 } else if (!strcasecmp(token, "round-robin")) {
cd196bc8 1393 p->options.roundrobin = 1;
d1b63fc8 1394 } else if (!strcasecmp(token, "weighted-round-robin")) {
1395 p->options.weighted_roundrobin = 1;
dc9d133b 1396#if USE_HTCP
0103c4c1 1397 } else if (!strcasecmp(token, "htcp")) {
cd196bc8 1398 p->options.htcp = 1;
dc9d133b 1399#endif
0103c4c1 1400 } else if (!strcasecmp(token, "no-netdb-exchange")) {
cd196bc8 1401 p->options.no_netdb_exchange = 1;
afd88fbe 1402#if USE_CARP
b3995439 1403 } else if (!strcasecmp(token, "carp")) {
afd88fbe 1404 if (p->type != PEER_PARENT)
b3995439 1405 fatalf("parse_peer: non-parent carp peer %s/%d\n", p->host, p->http_port);
1406 p->options.carp = 1;
95e36d02 1407#endif
1408#if DELAY_POOLS
1409 } else if (!strcasecmp(token, "no-delay")) {
cd196bc8 1410 p->options.no_delay = 1;
afd88fbe 1411#endif
c68e9c6b 1412 } else if (!strncasecmp(token, "login=", 6)) {
1413 p->login = xstrdup(token + 6);
4472c779 1414 rfc1738_unescape(p->login);
3f62decd 1415 } else if (!strncasecmp(token, "connect-timeout=", 16)) {
5c20d6fa 1416 p->connect_timeout = xatoi(token + 16);
7e3ce7b9 1417#if USE_CACHE_DIGESTS
1418 } else if (!strncasecmp(token, "digest-url=", 11)) {
1419 p->digest_url = xstrdup(token + 11);
1420#endif
987de783 1421 } else if (!strcasecmp(token, "allow-miss")) {
1422 p->options.allow_miss = 1;
fd359dd6 1423 } else if (!strncasecmp(token, "max-conn=", 9)) {
5c20d6fa 1424 p->max_conn = xatoi(token + 9);
be753325 1425 } else if (!strcasecmp(token, "originserver")) {
1426 p->options.originserver = 1;
1427 } else if (!strncasecmp(token, "name=", 5)) {
1428 safe_free(p->name);
1429 if (token[5])
1430 p->name = xstrdup(token + 5);
1431 } else if (!strncasecmp(token, "forceddomain=", 13)) {
1432 safe_free(p->domain);
1433 if (token[13])
1434 p->domain = xstrdup(token + 13);
a7ad6e4e 1435#if USE_SSL
1436 } else if (strcmp(token, "ssl") == 0) {
1437 p->use_ssl = 1;
1438 } else if (strncmp(token, "sslcert=", 8) == 0) {
1439 safe_free(p->sslcert);
1440 p->sslcert = xstrdup(token + 8);
1441 } else if (strncmp(token, "sslkey=", 7) == 0) {
1442 safe_free(p->sslkey);
1443 p->sslkey = xstrdup(token + 7);
1444 } else if (strncmp(token, "sslversion=", 11) == 0) {
1445 p->sslversion = atoi(token + 11);
1446 } else if (strncmp(token, "ssloptions=", 11) == 0) {
1447 safe_free(p->ssloptions);
1448 p->ssloptions = xstrdup(token + 11);
1449 } else if (strncmp(token, "sslcipher=", 10) == 0) {
1450 safe_free(p->sslcipher);
1451 p->sslcipher = xstrdup(token + 10);
1452 } else if (strncmp(token, "sslcafile=", 10) == 0) {
1453 safe_free(p->sslcafile);
1454 p->sslcipher = xstrdup(token + 10);
1455 } else if (strncmp(token, "sslcapath=", 10) == 0) {
1456 safe_free(p->sslcapath);
1457 p->sslcipher = xstrdup(token + 10);
1458 } else if (strncmp(token, "sslflags=", 9) == 0) {
1459 safe_free(p->sslflags);
1460 p->sslflags = xstrdup(token + 9);
1461 } else if (strncmp(token, "ssldomain=", 10) == 0) {
1462 safe_free(p->ssldomain);
1463 p->ssldomain = xstrdup(token + 10);
1464#endif
1465 } else if (strcmp(token, "front-end-https") == 0) {
1466 p->front_end_https = 1;
1467 } else if (strcmp(token, "front-end-https=on") == 0) {
1468 p->front_end_https = 1;
1469 } else if (strcmp(token, "front-end-https=auto") == 0) {
1470 p->front_end_https = 2;
270b86af 1471 } else {
40a1495e 1472 debug(3, 0) ("parse_peer: token='%s'\n", token);
270b86af 1473 self_destruct();
1474 }
1475 }
be753325 1476 if (peerFindByName(p->name))
1477 fatalf("ERROR: cache_peer %s specified twice\n", p->name);
40a1495e 1478 if (p->weight < 1)
1479 p->weight = 1;
399cabec 1480 p->icp.version = ICP_VERSION_CURRENT;
98829f69 1481 p->tcp_up = PEER_TCP_MAGIC_COUNT;
eb406bb7 1482 p->test_fd = -1;
e13ee7ad 1483#if USE_CACHE_DIGESTS
1484 if (!p->options.no_digest) {
fa80a8ef 1485 /* XXX This looks odd.. who has the original pointer
1486 * then?
1487 */
1488 PeerDigest *pd = peerDigestCreate(p);
1489 p->digest = cbdataReference(pd);
8a6218c6 1490 }
a7ad6e4e 1491#endif
1492#if USE_SSL
1493 if (p->use_ssl) {
1494 p->sslContext = sslCreateClientContext(p->sslcert, p->sslkey, p->sslversion, p->sslcipher, p->ssloptions, p->sslflags, p->sslcafile, p->sslcapath);
1495 }
e13ee7ad 1496#endif
0153d498 1497 while (*head != NULL)
1498 head = &(*head)->next;
1499 *head = p;
40a1495e 1500 Config.npeers++;
82056f1e 1501 peerClearRR(p);
0153d498 1502}
1503
1504static void
40a1495e 1505free_peer(peer ** P)
0153d498 1506{
40a1495e 1507 peer *p;
79d39a72 1508 while ((p = *P) != NULL) {
a47b9029 1509 *P = p->next;
3855c318 1510#if USE_CACHE_DIGESTS
fa80a8ef 1511 cbdataReferenceDone(p->digest);
3855c318 1512#endif
41042c81 1513 cbdataFree(p);
a47b9029 1514 }
987c67d1 1515 Config.npeers = 0;
270b86af 1516}
1517
1518static void
a7d59104 1519dump_cachemgrpasswd(StoreEntry * entry, const char *name, cachemgr_passwd * list)
270b86af 1520{
d41de3c1 1521 wordlist *w;
1522 while (list != NULL) {
74aa8456 1523 if (strcmp(list->passwd, "none") && strcmp(list->passwd, "disable"))
1524 storeAppendPrintf(entry, "%s XXXXXXXXXX", name);
1525 else
1526 storeAppendPrintf(entry, "%s %s", name, list->passwd);
d41de3c1 1527 for (w = list->actions; w != NULL; w = w->next) {
1528 storeAppendPrintf(entry, " %s", w->key);
1529 }
1530 storeAppendPrintf(entry, "\n");
1531 list = list->next;
1532 }
270b86af 1533}
1534
1535static void
a47b9029 1536parse_cachemgrpasswd(cachemgr_passwd ** head)
270b86af 1537{
1538 char *passwd = NULL;
1539 wordlist *actions = NULL;
22f3fd98 1540 cachemgr_passwd *p;
1541 cachemgr_passwd **P;
270b86af 1542 parse_string(&passwd);
1543 parse_wordlist(&actions);
e6ccf245 1544 p = static_cast<cachemgr_passwd *>(xcalloc(1, sizeof(cachemgr_passwd)));
22f3fd98 1545 p->passwd = passwd;
1546 p->actions = actions;
26aa7e31 1547 for (P = head; *P; P = &(*P)->next) {
1548 /*
1549 * See if any of the actions from this line already have a
1550 * password from previous lines. The password checking
1551 * routines in cache_manager.c take the the password from
1552 * the first cachemgr_passwd struct that contains the
1553 * requested action. Thus, we should warn users who might
1554 * think they can have two passwords for the same action.
1555 */
1556 wordlist *w;
1557 wordlist *u;
1558 for (w = (*P)->actions; w; w = w->next) {
1559 for (u = actions; u; u = u->next) {
1560 if (strcmp(w->key, u->key))
1561 continue;
1562 debug(0, 0) ("WARNING: action '%s' (line %d) already has a password\n",
1563 u->key, config_lineno);
1564 }
1565 }
1566 }
22f3fd98 1567 *P = p;
270b86af 1568}
1569
1570static void
a47b9029 1571free_cachemgrpasswd(cachemgr_passwd ** head)
270b86af 1572{
a47b9029 1573 cachemgr_passwd *p;
79d39a72 1574 while ((p = *head) != NULL) {
a47b9029 1575 *head = p->next;
1576 xfree(p->passwd);
22f3fd98 1577 wordlistDestroy(&p->actions);
a47b9029 1578 xfree(p);
1579 }
270b86af 1580}
1581
8203a132 1582static void
16300b58 1583dump_denyinfo(StoreEntry * entry, const char *name, acl_deny_info_list * var)
270b86af 1584{
d41de3c1 1585 acl_name_list *a;
1586 while (var != NULL) {
02922e76 1587 storeAppendPrintf(entry, "%s %s", name, var->err_page_name);
d41de3c1 1588 for (a = var->acl_list; a != NULL; a = a->next)
1589 storeAppendPrintf(entry, " %s", a->name);
1590 storeAppendPrintf(entry, "\n");
1591 var = var->next;
1592 }
270b86af 1593}
1594
1595static void
16300b58 1596parse_denyinfo(acl_deny_info_list ** var)
6e40f263 1597{
f1dc9b30 1598 aclParseDenyInfoLine(var);
6e40f263 1599}
403279e0 1600
1273d501 1601void
a47b9029 1602free_denyinfo(acl_deny_info_list ** list)
3c5557f9 1603{
56b63fa1 1604 acl_deny_info_list *a = NULL;
1605 acl_deny_info_list *a_next = NULL;
1606 acl_name_list *l = NULL;
1607 acl_name_list *l_next = NULL;
1273d501 1608 for (a = *list; a; a = a_next) {
a47b9029 1609 for (l = a->acl_list; l; l = l_next) {
1610 l_next = l->next;
3314e65b 1611 memFree(l, MEM_ACL_NAME_LIST);
eeda4c4d 1612 l = NULL;
a47b9029 1613 }
1614 a_next = a->next;
eeda4c4d 1615 memFree(a, MEM_ACL_DENY_INFO_LIST);
1616 a = NULL;
1273d501 1617 }
1618 *list = NULL;
270b86af 1619}
1620
1621static void
505e35db 1622parse_peer_access(void)
270b86af 1623{
1624 char *host = NULL;
505e35db 1625 peer *p;
270b86af 1626 if (!(host = strtok(NULL, w_space)))
1627 self_destruct();
0cdcddb9 1628 if ((p = peerFindByName(host)) == NULL) {
1629 debug(15, 0) ("%s, line %d: No cache_peer '%s'\n",
1630 cfg_filename, config_lineno, host);
1631 return;
1632 }
505e35db 1633 aclParseAccessLine(&p->access);
270b86af 1634}
1635
270b86af 1636static void
1637parse_hostdomain(void)
1638{
1639 char *host = NULL;
1640 char *domain = NULL;
1641 if (!(host = strtok(NULL, w_space)))
1642 self_destruct();
f1dc9b30 1643 while ((domain = strtok(NULL, list_sep))) {
1644 domain_ping *l = NULL;
1645 domain_ping **L = NULL;
40a1495e 1646 peer *p;
1647 if ((p = peerFindByName(host)) == NULL) {
43c3424b 1648 debug(15, 0) ("%s, line %d: No cache_peer '%s'\n",
f1dc9b30 1649 cfg_filename, config_lineno, host);
1650 continue;
1651 }
e6ccf245 1652 l = static_cast<domain_ping *>(xcalloc(1, sizeof(domain_ping)));
f1dc9b30 1653 l->do_ping = 1;
1654 if (*domain == '!') { /* check for !.edu */
1655 l->do_ping = 0;
1656 domain++;
1657 }
1658 l->domain = xstrdup(domain);
b6a2f15e 1659 for (L = &(p->peer_domain); *L; L = &((*L)->next));
f1dc9b30 1660 *L = l;
1661 }
270b86af 1662}
1663
1664static void
1665parse_hostdomaintype(void)
1666{
1667 char *host = NULL;
1668 char *type = NULL;
1669 char *domain = NULL;
1670 if (!(host = strtok(NULL, w_space)))
1671 self_destruct();
1672 if (!(type = strtok(NULL, w_space)))
1673 self_destruct();
f1dc9b30 1674 while ((domain = strtok(NULL, list_sep))) {
1675 domain_type *l = NULL;
1676 domain_type **L = NULL;
40a1495e 1677 peer *p;
1678 if ((p = peerFindByName(host)) == NULL) {
43c3424b 1679 debug(15, 0) ("%s, line %d: No cache_peer '%s'\n",
f1dc9b30 1680 cfg_filename, config_lineno, host);
1681 return;
1682 }
e6ccf245 1683 l = static_cast<domain_type *>(xcalloc(1, sizeof(domain_type)));
f1dc9b30 1684 l->type = parseNeighborType(type);
1685 l->domain = xstrdup(domain);
1686 for (L = &(p->typelist); *L; L = &((*L)->next));
1687 *L = l;
1688 }
270b86af 1689}
1690
7e3ce7b9 1691#if UNUSED_CODE
270b86af 1692static void
a7d59104 1693dump_ushortlist(StoreEntry * entry, const char *name, ushortlist * u)
090089c4 1694{
270b86af 1695 while (u) {
f53b06f9 1696 storeAppendPrintf(entry, "%s %d\n", name, (int) u->i);
270b86af 1697 u = u->next;
1698 }
1699}
090089c4 1700
f53b06f9 1701static int
1702check_null_ushortlist(ushortlist * u)
1703{
1704 return u == NULL;
1705}
1706
270b86af 1707static void
1708parse_ushortlist(ushortlist ** P)
1709{
1710 char *token;
1711 int i;
1712 ushortlist *u;
1713 ushortlist **U;
1714 while ((token = strtok(NULL, w_space))) {
1715 if (sscanf(token, "%d", &i) != 1)
1716 self_destruct();
1717 if (i < 0)
1718 i = 0;
1719 u = xcalloc(1, sizeof(ushortlist));
1720 u->i = (u_short) i;
1721 for (U = P; *U; U = &(*U)->next);
1722 *U = u;
090089c4 1723 }
270b86af 1724}
090089c4 1725
0153d498 1726static void
a47b9029 1727free_ushortlist(ushortlist ** P)
0153d498 1728{
a47b9029 1729 ushortlist *u;
79d39a72 1730 while ((u = *P) != NULL) {
a47b9029 1731 *P = u->next;
1732 xfree(u);
1733 }
0153d498 1734}
7e3ce7b9 1735#endif
0153d498 1736
270b86af 1737static void
a7d59104 1738dump_int(StoreEntry * entry, const char *name, int var)
270b86af 1739{
f53b06f9 1740 storeAppendPrintf(entry, "%s %d\n", name, var);
270b86af 1741}
c1c29eb6 1742
94439e4e 1743void
270b86af 1744parse_int(int *var)
1745{
270b86af 1746 int i;
0e4e0e7d 1747 i = GetInteger();
270b86af 1748 *var = i;
1749}
090089c4 1750
0153d498 1751static void
1752free_int(int *var)
1753{
a47b9029 1754 *var = 0;
0153d498 1755}
1756
270b86af 1757static void
a7d59104 1758dump_onoff(StoreEntry * entry, const char *name, int var)
270b86af 1759{
f53b06f9 1760 storeAppendPrintf(entry, "%s %s\n", name, var ? "on" : "off");
270b86af 1761}
090089c4 1762
d205783b 1763void
270b86af 1764parse_onoff(int *var)
1765{
1766 char *token = strtok(NULL, w_space);
090089c4 1767
270b86af 1768 if (token == NULL)
1769 self_destruct();
1770 if (!strcasecmp(token, "on") || !strcasecmp(token, "enable"))
1771 *var = 1;
1772 else
1773 *var = 0;
1774}
e90100aa 1775
0153d498 1776#define free_onoff free_int
f1dc9b30 1777#define dump_eol dump_string
1778#define free_eol free_string
30a4f2a8 1779
270b86af 1780static void
a7d59104 1781dump_refreshpattern(StoreEntry * entry, const char *name, refresh_t * head)
270b86af 1782{
d41de3c1 1783 while (head != NULL) {
9f60cfdf 1784 storeAppendPrintf(entry, "%s%s %s %d %d%% %d\n",
c3f6d204 1785 name,
1786 head->flags.icase ? " -i" : null_string,
1787 head->pattern,
1788 (int) head->min / 60,
1789 (int) (100.0 * head->pct + 0.5),
9f60cfdf 1790 (int) head->max / 60);
1791#if HTTP_VIOLATIONS
1792 if (head->flags.override_expire)
1793 storeAppendPrintf(entry, " override-expire");
1794 if (head->flags.override_lastmod)
1795 storeAppendPrintf(entry, " override-lastmod");
1796 if (head->flags.reload_into_ims)
1797 storeAppendPrintf(entry, " reload-into-ims");
1798 if (head->flags.ignore_reload)
1799 storeAppendPrintf(entry, " ignore-reload");
1800#endif
1801 storeAppendPrintf(entry, "\n");
d41de3c1 1802 head = head->next;
1803 }
270b86af 1804}
090089c4 1805
270b86af 1806static void
f1dc9b30 1807parse_refreshpattern(refresh_t ** head)
270b86af 1808{
f1dc9b30 1809 char *token;
1810 char *pattern;
1811 time_t min = 0;
c3f6d204 1812 double pct = 0.0;
f1dc9b30 1813 time_t max = 0;
9f60cfdf 1814#if HTTP_VIOLATIONS
1dfa1d81 1815 int override_expire = 0;
1816 int override_lastmod = 0;
cbe3a719 1817 int reload_into_ims = 0;
1818 int ignore_reload = 0;
9f60cfdf 1819#endif
f1dc9b30 1820 int i;
1821 refresh_t *t;
1822 regex_t comp;
1823 int errcode;
1824 int flags = REG_EXTENDED | REG_NOSUB;
1825 if ((token = strtok(NULL, w_space)) == NULL)
1826 self_destruct();
1827 if (strcmp(token, "-i") == 0) {
1828 flags |= REG_ICASE;
1829 token = strtok(NULL, w_space);
1830 } else if (strcmp(token, "+i") == 0) {
1831 flags &= ~REG_ICASE;
1832 token = strtok(NULL, w_space);
1833 }
1834 if (token == NULL)
1835 self_destruct();
1836 pattern = xstrdup(token);
0e4e0e7d 1837 i = GetInteger(); /* token: min */
f1dc9b30 1838 min = (time_t) (i * 60); /* convert minutes to seconds */
0e4e0e7d 1839 i = GetInteger(); /* token: pct */
c3f6d204 1840 pct = (double) i / 100.0;
0e4e0e7d 1841 i = GetInteger(); /* token: max */
f1dc9b30 1842 max = (time_t) (i * 60); /* convert minutes to seconds */
1dfa1d81 1843 /* Options */
1844 while ((token = strtok(NULL, w_space)) != NULL) {
9f60cfdf 1845#if HTTP_VIOLATIONS
1dfa1d81 1846 if (!strcmp(token, "override-expire"))
1847 override_expire = 1;
255d6021 1848 else if (!strcmp(token, "override-lastmod"))
1dfa1d81 1849 override_lastmod = 1;
cbe3a719 1850 else if (!strcmp(token, "reload-into-ims")) {
1851 reload_into_ims = 1;
1852 refresh_nocache_hack = 1;
1853 /* tell client_side.c that this is used */
1854 } else if (!strcmp(token, "ignore-reload")) {
1855 ignore_reload = 1;
1856 refresh_nocache_hack = 1;
1857 /* tell client_side.c that this is used */
1858 } else
9f60cfdf 1859#endif
cbe3a719 1860 debug(22, 0) ("redreshAddToList: Unknown option '%s': %s\n",
1dfa1d81 1861 pattern, token);
1862 }
f1dc9b30 1863 if ((errcode = regcomp(&comp, pattern, flags)) != 0) {
1864 char errbuf[256];
1865 regerror(errcode, &comp, errbuf, sizeof errbuf);
1866 debug(22, 0) ("%s line %d: %s\n",
1867 cfg_filename, config_lineno, config_input_line);
1868 debug(22, 0) ("refreshAddToList: Invalid regular expression '%s': %s\n",
1869 pattern, errbuf);
1870 return;
1871 }
c3f6d204 1872 pct = pct < 0.0 ? 0.0 : pct;
f1dc9b30 1873 max = max < 0 ? 0 : max;
e6ccf245 1874 t = static_cast<refresh_t *>(xcalloc(1, sizeof(refresh_t)));
f1dc9b30 1875 t->pattern = (char *) xstrdup(pattern);
1876 t->compiled_pattern = comp;
1877 t->min = min;
c3f6d204 1878 t->pct = pct;
f1dc9b30 1879 t->max = max;
c3f6d204 1880 if (flags & REG_ICASE)
1881 t->flags.icase = 1;
9f60cfdf 1882#if HTTP_VIOLATIONS
1dfa1d81 1883 if (override_expire)
1884 t->flags.override_expire = 1;
1885 if (override_lastmod)
1886 t->flags.override_lastmod = 1;
cbe3a719 1887 if (reload_into_ims)
1888 t->flags.reload_into_ims = 1;
1889 if (ignore_reload)
1890 t->flags.ignore_reload = 1;
9f60cfdf 1891#endif
f1dc9b30 1892 t->next = NULL;
1893 while (*head)
1894 head = &(*head)->next;
1895 *head = t;
1896 safe_free(pattern);
270b86af 1897}
090089c4 1898
8e89beb3 1899#if UNUSED_CODE
6b53c392 1900static int
a4b8110e 1901check_null_refreshpattern(refresh_t * data)
6b53c392 1902{
80e073c0 1903 return data == NULL;
6b53c392 1904}
8e89beb3 1905#endif
6b53c392 1906
270b86af 1907static void
a47b9029 1908free_refreshpattern(refresh_t ** head)
270b86af 1909{
f1dc9b30 1910 refresh_t *t;
79d39a72 1911 while ((t = *head) != NULL) {
f1dc9b30 1912 *head = t->next;
1913 safe_free(t->pattern);
1914 regfree(&t->compiled_pattern);
1915 safe_free(t);
1916 }
270b86af 1917}
12b9e9b1 1918
270b86af 1919static void
a7d59104 1920dump_string(StoreEntry * entry, const char *name, char *var)
270b86af 1921{
f53b06f9 1922 if (var != NULL)
a7d59104 1923 storeAppendPrintf(entry, "%s %s\n", name, var);
270b86af 1924}
98ffb7e4 1925
270b86af 1926static void
0153d498 1927parse_string(char **var)
270b86af 1928{
1929 char *token = strtok(NULL, w_space);
270b86af 1930 safe_free(*var);
1931 if (token == NULL)
1932 self_destruct();
1933 *var = xstrdup(token);
1934}
b15e6857 1935
0153d498 1936static void
1937free_string(char **var)
1938{
027acbaf 1939 safe_free(*var);
0153d498 1940}
caebbe00 1941
94439e4e 1942void
f1dc9b30 1943parse_eol(char *volatile *var)
270b86af 1944{
852751f7 1945 unsigned char *token = (unsigned char *) strtok(NULL, null_string);
270b86af 1946 safe_free(*var);
f1dc9b30 1947 if (token == NULL)
2d72d4fd 1948 self_destruct();
1949 while (*token && isspace(*token))
1950 token++;
20cb98c9 1951 if (!*token)
f1dc9b30 1952 self_destruct();
852751f7 1953 *var = xstrdup((char *) token);
270b86af 1954}
090089c4 1955
270b86af 1956static void
a7d59104 1957dump_time_t(StoreEntry * entry, const char *name, time_t var)
090089c4 1958{
f53b06f9 1959 storeAppendPrintf(entry, "%s %d seconds\n", name, (int) var);
090089c4 1960}
1961
94439e4e 1962void
a47b9029 1963parse_time_t(time_t * var)
0ffd22bc 1964{
f1dc9b30 1965 parseTimeLine(var, T_SECOND_STR);
0ffd22bc 1966}
1967
270b86af 1968static void
a47b9029 1969free_time_t(time_t * var)
270b86af 1970{
a47b9029 1971 *var = 0;
270b86af 1972}
9906e724 1973
1974static void
a7d59104 1975dump_size_t(StoreEntry * entry, const char *name, size_t var)
1b635117 1976{
f53b06f9 1977 storeAppendPrintf(entry, "%s %d\n", name, (int) var);
1b635117 1978}
1979
1980static void
a7d59104 1981dump_b_size_t(StoreEntry * entry, const char *name, size_t var)
9906e724 1982{
f53b06f9 1983 storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_BYTES_STR);
9906e724 1984}
1985
1986static void
a7d59104 1987dump_kb_size_t(StoreEntry * entry, const char *name, size_t var)
9906e724 1988{
f53b06f9 1989 storeAppendPrintf(entry, "%s %d %s\n", name, (int) var, B_KBYTES_STR);
9906e724 1990}
1991
1992static void
a47b9029 1993parse_size_t(size_t * var)
1b635117 1994{
1b635117 1995 int i;
0e4e0e7d 1996 i = GetInteger();
1b635117 1997 *var = (size_t) i;
1998}
1999
2000static void
2001parse_b_size_t(size_t * var)
9906e724 2002{
2003 parseBytesLine(var, B_BYTES_STR);
2004}
2005
b671cc68 2006CBDATA_TYPE(body_size);
a560ee93 2007
2008static void
b671cc68 2009parse_body_size_t(dlink_list * bodylist)
a560ee93 2010{
2011 body_size *bs;
b671cc68 2012 CBDATA_INIT_TYPE(body_size);
a560ee93 2013 bs = cbdataAlloc(body_size);
b671cc68 2014 parse_size_t(&bs->maxsize);
a560ee93 2015 aclParseAccessLine(&bs->access_list);
2016
2017 dlinkAddTail(bs, &bs->node, bodylist);
2018}
2019
2020static void
2021dump_body_size_t(StoreEntry * entry, const char *name, dlink_list bodylist)
2022{
2023 body_size *bs;
2024 bs = (body_size *) bodylist.head;
2025 while (bs) {
b671cc68 2026 acl_list *l;
a560ee93 2027 acl_access *head = bs->access_list;
2028 while (head != NULL) {
32754419 2029 storeAppendPrintf(entry, "%s %ld %s", name, (long int) bs->maxsize,
a560ee93 2030 head->allow ? "Allow" : "Deny");
29b8d8d6 2031 for (l = head->aclList; l != NULL; l = l->next) {
b671cc68 2032 storeAppendPrintf(entry, " %s%s",
a560ee93 2033 l->op ? null_string : "!",
29b8d8d6 2034 l->_acl->name);
a560ee93 2035 }
2036 storeAppendPrintf(entry, "\n");
2037 head = head->next;
b671cc68 2038 }
a560ee93 2039 bs = (body_size *) bs->node.next;
2040 }
2041}
2042
2043static void
852751f7 2044free_body_size_t(dlink_list * bodylist)
2045{
a560ee93 2046 body_size *bs, *tempnode;
2047 bs = (body_size *) bodylist->head;
2048 while (bs) {
b671cc68 2049 bs->maxsize = 0;
a560ee93 2050 aclDestroyAccessList(&bs->access_list);
2051 tempnode = (body_size *) bs->node.next;
b671cc68 2052 dlinkDelete(&bs->node, bodylist);
2053 cbdataFree(bs);
a560ee93 2054 bs = tempnode;
2055 }
2056}
2057
2058static int
2059check_null_body_size_t(dlink_list bodylist)
2060{
2061 return bodylist.head == NULL;
2062}
2063
2064
9906e724 2065static void
a47b9029 2066parse_kb_size_t(size_t * var)
9906e724 2067{
2068 parseBytesLine(var, B_KBYTES_STR);
2069}
2070
2071static void
a47b9029 2072free_size_t(size_t * var)
9906e724 2073{
a47b9029 2074 *var = 0;
9906e724 2075}
2076
1b635117 2077#define free_b_size_t free_size_t
9906e724 2078#define free_kb_size_t free_size_t
2079#define free_mb_size_t free_size_t
2080#define free_gb_size_t free_size_t
090089c4 2081
8203a132 2082static void
a7d59104 2083dump_ushort(StoreEntry * entry, const char *name, u_short var)
090089c4 2084{
f53b06f9 2085 storeAppendPrintf(entry, "%s %d\n", name, var);
270b86af 2086}
090089c4 2087
0153d498 2088static void
a47b9029 2089free_ushort(u_short * u)
0153d498 2090{
2091 *u = 0;
2092}
2093
270b86af 2094static void
2095parse_ushort(u_short * var)
b67e2c8c 2096{
2097 ConfigParser::ParseUShort(var);
2098}
2099
2100void
2101ConfigParser::ParseUShort(u_short *var)
270b86af 2102{
270b86af 2103 int i;
090089c4 2104
0e4e0e7d 2105 i = GetInteger();
270b86af 2106 if (i < 0)
2107 i = 0;
2108 *var = (u_short) i;
090089c4 2109}
2110
270b86af 2111static void
a7d59104 2112dump_wordlist(StoreEntry * entry, const char *name, wordlist * list)
270b86af 2113{
270b86af 2114 while (list != NULL) {
f53b06f9 2115 storeAppendPrintf(entry, "%s %s\n", name, list->key);
270b86af 2116 list = list->next;
429fdbec 2117 }
429fdbec 2118}
2119
94439e4e 2120void
270b86af 2121parse_wordlist(wordlist ** list)
429fdbec 2122{
270b86af 2123 char *token;
a3c6890f 2124 char *t = strtok(NULL, "");
2125 while ((token = strwordtok(NULL, &t)))
270b86af 2126 wordlistAdd(list, token);
429fdbec 2127}
270b86af 2128
f8d9f54a 2129static int
5da06f20 2130check_null_wordlist(wordlist * w)
f8d9f54a 2131{
2132 return w == NULL;
2133}
2134
63e9d884 2135static int
c6d5b87b 2136check_null_acl_access(acl_access * a)
63e9d884 2137{
2138 return a == NULL;
2139}
2140
0153d498 2141#define free_wordlist wordlistDestroy
270b86af 2142
d548ee64 2143#define free_uri_whitespace free_int
2144
2145static void
2146parse_uri_whitespace(int *var)
2147{
2148 char *token = strtok(NULL, w_space);
2149 if (token == NULL)
2150 self_destruct();
7e3ce7b9 2151 if (!strcasecmp(token, "strip"))
2152 *var = URI_WHITESPACE_STRIP;
2153 else if (!strcasecmp(token, "deny"))
d548ee64 2154 *var = URI_WHITESPACE_DENY;
2155 else if (!strcasecmp(token, "allow"))
2156 *var = URI_WHITESPACE_ALLOW;
2157 else if (!strcasecmp(token, "encode"))
2158 *var = URI_WHITESPACE_ENCODE;
2159 else if (!strcasecmp(token, "chop"))
2160 *var = URI_WHITESPACE_CHOP;
2161 else
2162 self_destruct();
2163}
2164
2165
2166static void
2167dump_uri_whitespace(StoreEntry * entry, const char *name, int var)
2168{
c193c972 2169 const char *s;
d548ee64 2170 if (var == URI_WHITESPACE_ALLOW)
2171 s = "allow";
2172 else if (var == URI_WHITESPACE_ENCODE)
2173 s = "encode";
2174 else if (var == URI_WHITESPACE_CHOP)
2175 s = "chop";
7e3ce7b9 2176 else if (var == URI_WHITESPACE_DENY)
d548ee64 2177 s = "deny";
7e3ce7b9 2178 else
2179 s = "strip";
d548ee64 2180 storeAppendPrintf(entry, "%s %s\n", name, s);
2181}
2182
6a566b9c 2183static void
c1dd71ae 2184free_removalpolicy(RemovalPolicySettings ** settings)
6a566b9c 2185{
2186 if (!*settings)
2187 return;
2188 free_string(&(*settings)->type);
2189 free_wordlist(&(*settings)->args);
2190 xfree(*settings);
2191 *settings = NULL;
2192}
2193
2194static void
c1dd71ae 2195parse_removalpolicy(RemovalPolicySettings ** settings)
6a566b9c 2196{
2197 if (*settings)
2198 free_removalpolicy(settings);
e6ccf245 2199 *settings = static_cast<RemovalPolicySettings *>(xcalloc(1, sizeof(**settings)));
6a566b9c 2200 parse_string(&(*settings)->type);
2201 parse_wordlist(&(*settings)->args);
2202}
2203
2204static void
c1dd71ae 2205dump_removalpolicy(StoreEntry * entry, const char *name, RemovalPolicySettings * settings)
6a566b9c 2206{
2207 wordlist *args;
2208 storeAppendPrintf(entry, "%s %s", name, settings->type);
2209 args = settings->args;
2210 while (args) {
2211 storeAppendPrintf(entry, " %s", args->key);
2212 args = args->next;
2213 }
be58afb5 2214 storeAppendPrintf(entry, "\n");
6a566b9c 2215}
c1dd71ae 2216
6a566b9c 2217
1ee67578 2218#include "cf_parser.h"
f1dc9b30 2219
2220peer_t
2221parseNeighborType(const char *s)
2222{
2223 if (!strcasecmp(s, "parent"))
2224 return PEER_PARENT;
2225 if (!strcasecmp(s, "neighbor"))
2226 return PEER_SIBLING;
2227 if (!strcasecmp(s, "neighbour"))
2228 return PEER_SIBLING;
2229 if (!strcasecmp(s, "sibling"))
2230 return PEER_SIBLING;
2231 if (!strcasecmp(s, "multicast"))
2232 return PEER_MULTICAST;
2233 debug(15, 0) ("WARNING: Unknown neighbor type: %s\n", s);
2234 return PEER_SIBLING;
2235}
f150dd4b 2236
3f38a55e 2237#if CURRENTLY_UNUSED
2238/* This code was previously used by http_port. Left as it really should
2239 * be used by icp_port and htcp_port
2240 */
52f772de 2241void
2242parse_sockaddr_in_list_token(sockaddr_in_list ** head, char *token)
7e3ce7b9 2243{
7e3ce7b9 2244 char *t;
efd900cb 2245 char *host;
7e3ce7b9 2246 const struct hostent *hp;
efd900cb 2247 unsigned short port;
7e3ce7b9 2248 sockaddr_in_list *s;
52f772de 2249
2250 host = NULL;
2251 port = 0;
2252 if ((t = strchr(token, ':'))) {
2253 /* host:port */
2254 host = token;
2255 *t = '\0';
5c20d6fa 2256 port = (unsigned short) xatoi(t + 1);
52f772de 2257 if (0 == port)
7e3ce7b9 2258 self_destruct();
5c20d6fa 2259 } else if ((port = xatoi(token)) > 0) {
52f772de 2260 /* port */
2261 } else {
2262 self_destruct();
2263 }
e6ccf245 2264 s = static_cast<sockaddr_in_list *>(xcalloc(1, sizeof(*s)));
52f772de 2265 s->s.sin_port = htons(port);
2266 if (NULL == host)
2267 s->s.sin_addr = any_addr;
2268 else if (1 == safe_inet_addr(host, &s->s.sin_addr))
2269 (void) 0;
2270 else if ((hp = gethostbyname(host))) /* dont use ipcache */
2271 s->s.sin_addr = inaddrFromHostent(hp);
2272 else
2273 self_destruct();
2274 while (*head)
2275 head = &(*head)->next;
2276 *head = s;
2277}
2278
2279static void
2280parse_sockaddr_in_list(sockaddr_in_list ** head)
2281{
2282 char *token;
2283 while ((token = strtok(NULL, w_space))) {
2284 parse_sockaddr_in_list_token(head, token);
7e3ce7b9 2285 }
2286}
2287
2288static void
2289dump_sockaddr_in_list(StoreEntry * e, const char *n, const sockaddr_in_list * s)
2290{
2291 while (s) {
2292 storeAppendPrintf(e, "%s %s:%d\n",
2293 n,
2294 inet_ntoa(s->s.sin_addr),
2295 ntohs(s->s.sin_port));
2296 s = s->next;
2297 }
2298}
2299
2300static void
2301free_sockaddr_in_list(sockaddr_in_list ** head)
2302{
2303 sockaddr_in_list *s;
2304 while ((s = *head) != NULL) {
2305 *head = s->next;
2306 xfree(s);
2307 }
2308}
2309
2310static int
2311check_null_sockaddr_in_list(const sockaddr_in_list * s)
2312{
2313 return NULL == s;
2314}
3f38a55e 2315#endif /* CURRENTLY_UNUSED */
7e3ce7b9 2316
d193a436 2317static void
3f38a55e 2318parse_http_port_specification(http_port_list * s, char *token)
d193a436 2319{
3f38a55e 2320 char *host = NULL;
d193a436 2321 const struct hostent *hp;
3f38a55e 2322 unsigned short port = 0;
2323 char *t;
d193a436 2324 if ((t = strchr(token, ':'))) {
2325 /* host:port */
2326 host = token;
2327 *t = '\0';
3f38a55e 2328 port = (unsigned short) atoi(t + 1);
d193a436 2329 if (0 == port)
2330 self_destruct();
3f38a55e 2331 } else if ((port = atoi(token)) > 0) {
d193a436 2332 /* port */
2333 } else {
2334 self_destruct();
2335 }
d193a436 2336 s->s.sin_port = htons(port);
2337 if (NULL == host)
2338 s->s.sin_addr = any_addr;
2339 else if (1 == safe_inet_addr(host, &s->s.sin_addr))
2340 (void) 0;
3f38a55e 2341 else if ((hp = gethostbyname(host))) {
2342 /* dont use ipcache */
d193a436 2343 s->s.sin_addr = inaddrFromHostent(hp);
3f38a55e 2344 s->defaultsite = xstrdup(host);
2345 } else
2346 self_destruct();
2347}
2348
2349static void
2350parse_http_port_option(http_port_list * s, char *token)
2351{
2352 if (strncmp(token, "defaultsite=", 12) == 0) {
2353 safe_free(s->defaultsite);
2354 s->defaultsite = xstrdup(token + 12);
2355 s->accel = 1;
2356 } else if (strncmp(token, "name=", 5) == 0) {
2357 safe_free(s->name);
2358 s->name = xstrdup(token + 5);
2359 } else if (strcmp(token, "transparent") == 0) {
2360 s->transparent = 1;
2361 } else if (strcmp(token, "vhost") == 0) {
2362 s->vhost = 1;
2363 s->accel = 1;
2364 } else if (strcmp(token, "vport") == 0) {
2365 s->vport = -1;
2366 s->accel = 1;
2367 } else if (strncmp(token, "vport=", 6) == 0) {
2368 s->vport = atoi(token + 6);
2369 s->accel = 1;
2370 } else if (strncmp(token, "protocol=", 9) == 0) {
2371 s->protocol = xstrdup(token + 9);
2372 s->accel = 1;
2373 } else if (strcmp(token, "accel") == 0) {
2374 s->accel = 1;
2375 } else {
2376 self_destruct();
2377 }
2378}
2379
2380static void
2381free_generic_http_port_data(http_port_list * s)
2382{
2383 safe_free(s->name);
2384 safe_free(s->defaultsite);
2385}
2386
2387static void
2388cbdataFree_http_port(void *data)
2389{
2390 free_generic_http_port_data((http_port_list *)data);
2391}
2392
2393
2394static http_port_list *
2395create_http_port(char *portspec)
2396{
2397 CBDATA_TYPE(http_port_list);
2398 CBDATA_INIT_TYPE_FREECB(http_port_list, cbdataFree_http_port);
2399
2400 http_port_list *s = cbdataAlloc(http_port_list);
2401 s->protocol = xstrdup("http");
2402 parse_http_port_specification(s, portspec);
2403 return s;
2404}
2405
2406void
2407add_http_port(char *portspec)
2408{
2409 http_port_list *s = create_http_port(portspec);
2410 s->next = Config.Sockaddr.http;
2411 Config.Sockaddr.http = s;
2412}
2413
2414static void
2415parse_http_port_list(http_port_list ** head)
2416{
2417 char *token = strtok(NULL, w_space);
2418 if (!token)
d193a436 2419 self_destruct();
3f38a55e 2420 http_port_list *s = create_http_port(token);
2421 /* parse options ... */
2422 while ((token = strtok(NULL, w_space))) {
2423 parse_http_port_option(s, token);
2424 }
2425 while (*head)
2426 head = &(*head)->next;
2427 *head = s;
2428}
2429
2430static void
2431dump_generic_http_port(StoreEntry * e, const char *n, const http_port_list * s)
2432{
2433 storeAppendPrintf(e, "%s %s:%d",
2434 n,
2435 inet_ntoa(s->s.sin_addr),
2436 ntohs(s->s.sin_port));
2437 if (s->defaultsite)
2438 storeAppendPrintf(e, " defaultsite=%s", s->defaultsite);
2439 if (s->transparent)
2440 storeAppendPrintf(e, " transparent");
2441 if (s->vhost)
2442 storeAppendPrintf(e, " vhost");
2443 if (s->vport)
2444 storeAppendPrintf(e, " vport");
2445}
2446static void
2447dump_http_port_list(StoreEntry * e, const char *n, const http_port_list * s)
2448{
2449 while (s) {
2450 dump_generic_http_port(e, n, s);
2451 storeAppendPrintf(e, "\n");
2452 s = s->next;
2453 }
2454}
2455
2456static void
2457free_http_port_list(http_port_list ** head)
2458{
2459 http_port_list *s;
2460 while ((s = *head) != NULL) {
2461 *head = s->next;
2462 cbdataFree(s);
2463 }
2464}
2465
2466#if UNUSED_CODE
2467static int
2468check_null_http_port_list(const http_port_list * s)
2469{
2470 return NULL == s;
2471}
2472#endif
2473
2474#if USE_SSL
2475static void
2476cbdataFree_https_port(void *data)
2477{
2478 https_port_list *s = (https_port_list *)data;
2479 free_generic_http_port_data(&s->http);
2480 safe_free(s->cert);
2481 safe_free(s->key);
2482}
2483
2484static void
2485parse_https_port_list(https_port_list ** head)
2486{
2487 CBDATA_TYPE(https_port_list);
2488 char *token;
2489 https_port_list *s;
2490 CBDATA_INIT_TYPE_FREECB(https_port_list, cbdataFree_https_port);
2491 token = strtok(NULL, w_space);
2492 if (!token)
2493 self_destruct();
2494 s = cbdataAlloc(https_port_list);
2495 s->http.protocol = xstrdup("https");
2496 parse_http_port_specification(&s->http, token);
d193a436 2497 /* parse options ... */
2498 while ((token = strtok(NULL, w_space))) {
2499 if (strncmp(token, "cert=", 5) == 0) {
2500 safe_free(s->cert);
2501 s->cert = xstrdup(token + 5);
2502 } else if (strncmp(token, "key=", 4) == 0) {
2503 safe_free(s->key);
2504 s->key = xstrdup(token + 4);
79d4ccdf 2505 } else if (strncmp(token, "version=", 8) == 0) {
5c20d6fa 2506 s->version = xatoi(token + 8);
79d4ccdf 2507 } else if (strncmp(token, "options=", 8) == 0) {
2508 safe_free(s->options);
2509 s->options = xstrdup(token + 8);
2510 } else if (strncmp(token, "cipher=", 7) == 0) {
2511 safe_free(s->cipher);
2512 s->cipher = xstrdup(token + 7);
a7ad6e4e 2513 } else if (strncmp(token, "clientca=", 9) == 0) {
2514 safe_free(s->clientca);
2515 s->clientca = xstrdup(token + 9);
2516 } else if (strncmp(token, "cafile=", 7) == 0) {
2517 safe_free(s->cafile);
2518 s->cafile = xstrdup(token + 7);
2519 } else if (strncmp(token, "capath=", 7) == 0) {
2520 safe_free(s->capath);
2521 s->capath = xstrdup(token + 7);
2522 } else if (strncmp(token, "sslflags=", 9) == 0) {
2523 safe_free(s->sslflags);
2524 s->sslflags = xstrdup(token + 9);
d193a436 2525 } else {
3f38a55e 2526 parse_http_port_option(&s->http, token);
d193a436 2527 }
2528 }
a7ad6e4e 2529 s->sslContext = sslCreateServerContext(s->cert, s->key, s->version, s->cipher, s->options, s->sslflags, s->clientca, s->cafile, s->capath);
87ec2a09 2530 if (!s->sslContext)
2531 self_destruct();
3f38a55e 2532 while (*head)
2533 head = (https_port_list **)&(*head)->http.next;
d193a436 2534 *head = s;
2535}
2536
2537static void
2538dump_https_port_list(StoreEntry * e, const char *n, const https_port_list * s)
2539{
2540 while (s) {
3f38a55e 2541 dump_generic_http_port(e, n, &s->http);
a7ad6e4e 2542 if (s->cert)
2543 storeAppendPrintf(e, " cert=%s", s->cert);
2544 if (s->key)
2545 storeAppendPrintf(e, " key=%s", s->cert);
79d4ccdf 2546 if (s->version)
2547 storeAppendPrintf(e, " version=%d", s->version);
2548 if (s->options)
2549 storeAppendPrintf(e, " options=%s", s->options);
2550 if (s->cipher)
2551 storeAppendPrintf(e, " cipher=%s", s->cipher);
a7ad6e4e 2552 if (s->cafile)
2553 storeAppendPrintf(e, " cafile=%s", s->cafile);
2554 if (s->capath)
2555 storeAppendPrintf(e, " capath=%s", s->capath);
2556 if (s->sslflags)
2557 storeAppendPrintf(e, " sslflags=%s", s->sslflags);
79d4ccdf 2558 storeAppendPrintf(e, "\n");
3f38a55e 2559 s = (https_port_list *) s->http.next;
d193a436 2560 }
2561}
2562
2563static void
2564free_https_port_list(https_port_list ** head)
2565{
2566 https_port_list *s;
2567 while ((s = *head) != NULL) {
3f38a55e 2568 *head = (https_port_list *) s->http.next;
2569 cbdataFree(s);
d193a436 2570 }
2571}
2572
2573#if 0
2574static int
2575check_null_https_port_list(const https_port_list * s)
2576{
2577 return NULL == s;
2578}
2579#endif
2580
2581#endif /* USE_SSL */
2582
f150dd4b 2583void
2584configFreeMemory(void)
2585{
23ff6968 2586 free_all();
f150dd4b 2587}
f0b19334 2588
94439e4e 2589void
f0b19334 2590requirePathnameExists(const char *name, const char *path)
2591{
2592 struct stat sb;
08577e16 2593 char pathbuf[BUFSIZ];
f0b19334 2594 assert(path != NULL);
08577e16 2595 if (Config.chroot_dir) {
2596 snprintf(pathbuf, BUFSIZ, "%s/%s", Config.chroot_dir, path);
2597 path = pathbuf;
2598 }
137ee196 2599 if (stat(path, &sb) < 0)
08577e16 2600 fatalf("%s %s: %s", name, path, xstrerror());
f0b19334 2601}
d860a1aa 2602
2603char *
2604strtokFile(void)
2605{
42419a95 2606 static int fromFile = 0;
2607 static FILE *wordFile = NULL;
2608
d860a1aa 2609 char *t, *fn;
2610 LOCAL_ARRAY(char, buf, 256);
2611
2612 strtok_again:
42419a95 2613 if (!fromFile) {
d860a1aa 2614 t = (strtok(NULL, w_space));
2615 if (!t || *t == '#') {
2616 return NULL;
2617 } else if (*t == '\"' || *t == '\'') {
2618 /* quote found, start reading from file */
2619 fn = ++t;
2620 while (*t && *t != '\"' && *t != '\'')
2621 t++;
2622 *t = '\0';
42419a95 2623 if ((wordFile = fopen(fn, "r")) == NULL) {
d860a1aa 2624 debug(28, 0) ("strtokFile: %s not found\n", fn);
2625 return (NULL);
2626 }
2627#if defined(_SQUID_MSWIN_) || defined(_SQUID_CYGWIN_)
42419a95 2628 setmode(fileno(wordFile), O_TEXT);
d860a1aa 2629#endif
42419a95 2630 fromFile = 1;
d860a1aa 2631 } else {
2632 return t;
2633 }
2634 }
42419a95 2635 /* fromFile */
2636 if (fgets(buf, 256, wordFile) == NULL) {
d860a1aa 2637 /* stop reading from file */
42419a95 2638 fclose(wordFile);
2639 wordFile = NULL;
2640 fromFile = 0;
d860a1aa 2641 goto strtok_again;
2642 } else {
40a59db9 2643 char *t2, *t3;
d860a1aa 2644 t = buf;
2645 /* skip leading and trailing white space */
2646 t += strspn(buf, w_space);
40a59db9 2647 t2 = t + strcspn(t, w_space);
2648 t3 = t2 + strspn(t2, w_space);
2649 while (*t3 && *t3 != '#') {
2650 t2 = t3 + strcspn(t3, w_space);
2651 t3 = t2 + strspn(t2, w_space);
2652 }
2653 *t2 = '\0';
d860a1aa 2654 /* skip comments */
2655 if (*t == '#')
2656 goto strtok_again;
2657 /* skip blank lines */
2658 if (!*t)
2659 goto strtok_again;
2660 return t;
2661 }
2662}