]> git.ipfire.org Git - thirdparty/squid.git/blame - tools/cachemgr.cc
SourceFormat Enforcement
[thirdparty/squid.git] / tools / cachemgr.cc
CommitLineData
5d985213 1/*
4ac4a490 2 * Copyright (C) 1996-2017 The Squid Software Foundation and contributors
d23f4e1b 3 *
5f623035
AJ
4 * Squid software is distributed under GPLv2+ license and includes
5 * contributions from numerous individuals and organizations.
6 * Please see the COPYING and CONTRIBUTORS files for details.
30a4f2a8 7 */
234967c9 8
f7f3304a 9#include "squid.h"
25f98340 10#include "base64.h"
055421ee 11#include "getfullhostname.h"
25f98340 12#include "html_quote.h"
055421ee 13#include "ip/Address.h"
1f1eee3f 14#include "MemBuf.h"
25f98340 15#include "rfc1123.h"
1fa9b1a7 16#include "rfc1738.h"
055421ee 17#include "util.h"
234967c9 18
074d6a40
AJ
19#include <cctype>
20#include <cerrno>
21#include <csignal>
22#include <cstring>
23#include <ctime>
30a4f2a8 24#if HAVE_UNISTD_H
234967c9 25#include <unistd.h>
30a4f2a8 26#endif
30a4f2a8 27#if HAVE_FCNTL_H
234967c9 28#include <fcntl.h>
30a4f2a8 29#endif
30#if HAVE_GRP_H
234967c9 31#include <grp.h>
30a4f2a8 32#endif
88738790 33#if HAVE_GNUMALLOC_H
34#include <gnumalloc.h>
482aa790 35#elif HAVE_MALLOC_H
234967c9 36#include <malloc.h>
983061ed 37#endif
30a4f2a8 38#if HAVE_MEMORY_H
234967c9 39#include <memory.h>
30a4f2a8 40#endif
489520a9 41#if HAVE_NETDB_H
234967c9 42#include <netdb.h>
30a4f2a8 43#endif
44#if HAVE_PWD_H
234967c9 45#include <pwd.h>
30a4f2a8 46#endif
30a4f2a8 47#if HAVE_SYS_PARAM_H
234967c9 48#include <sys/param.h>
30a4f2a8 49#endif
30a4f2a8 50#if HAVE_SYS_SOCKET_H
234967c9 51#include <sys/socket.h>
30a4f2a8 52#endif
53#if HAVE_NETINET_IN_H
234967c9 54#include <netinet/in.h>
30a4f2a8 55#endif
56#if HAVE_ARPA_INET_H
234967c9 57#include <arpa/inet.h>
30a4f2a8 58#endif
59#if HAVE_SYS_STAT_H
234967c9 60#include <sys/stat.h>
30a4f2a8 61#endif
62#if HAVE_SYS_UN_H
234967c9 63#include <sys/un.h>
30a4f2a8 64#endif
65#if HAVE_SYS_WAIT_H
234967c9 66#include <sys/wait.h>
30a4f2a8 67#endif
68#if HAVE_LIBC_H
69#include <libc.h>
70#endif
30a4f2a8 71#if HAVE_STRINGS_H
234967c9 72#include <strings.h>
73#endif
234967c9 74#if HAVE_BSTRING_H
75#include <bstring.h>
76#endif
30a4f2a8 77#if HAVE_CRYPT_H
234967c9 78#include <crypt.h>
79#endif
42ad37af 80#if HAVE_FNMATCH_H
e1381638 81extern "C" {
42ad37af 82#include <fnmatch.h>
7dcff512 83}
42ad37af 84#endif
090089c4 85
42ad37af 86#ifndef DEFAULT_CACHEMGR_CONFIG
b4ee1908 87#define DEFAULT_CACHEMGR_CONFIG "/etc/squid/cachemgr.conf"
42ad37af 88#endif
89
3afd7aae 90typedef struct {
42ad37af 91 char *server;
d23f4e1b 92 char *hostname;
93 int port;
94 char *action;
7395afb8 95 char *user_name;
d23f4e1b 96 char *passwd;
7395afb8 97 char *pub_auth;
3469551a
CT
98 char *workers;
99 char *processes;
2fadd50d 100} cachemgr_request;
090089c4 101
7395afb8 102/*
103 * Static variables and constants
104 */
f53969cc 105static const time_t passwd_ttl = 60 * 60 * 3; /* in sec */
0ee4272b 106static const char *script_name = "/cgi-bin/cachemgr.cgi";
0ee4272b 107static const char *progname = NULL;
d1a43e28 108static time_t now;
62e76326 109
d23f4e1b 110/*
111 * Function prototypes
112 */
7395afb8 113static const char *safe_str(const char *str);
a2c963ae 114static const char *xstrtok(char **str, char del);
f5b8bbc4 115static void print_trailer(void);
a2c963ae 116static void auth_html(const char *host, int port, const char *user_name);
d23f4e1b 117static void error_html(const char *msg);
7395afb8 118static char *menu_url(cachemgr_request * req, const char *action);
119static int parse_status_line(const char *sline, const char **statusStr);
d23f4e1b 120static cachemgr_request *read_request(void);
121static char *read_get_request(void);
122static char *read_post_request(void);
123
2ac76861 124static void make_pub_auth(cachemgr_request * req);
125static void decode_pub_auth(cachemgr_request * req);
126static void reset_auth(cachemgr_request * req);
127static const char *make_auth_header(const cachemgr_request * req);
7395afb8 128
42ad37af 129static int check_target_acl(const char *hostname, int port);
130
7aa9bb3e 131#if _SQUID_WINDOWS_
099a1791 132static int s_iInitCount = 0;
a760862a 133
099a1791 134int Win32SockInit(void)
135{
136 int iVersionRequested;
137 WSADATA wsaData;
138 int err;
139
140 if (s_iInitCount > 0) {
14942edd 141 ++s_iInitCount;
62e76326 142 return (0);
143 } else if (s_iInitCount < 0)
144 return (s_iInitCount);
099a1791 145
146 /* s_iInitCount == 0. Do the initailization */
147 iVersionRequested = MAKEWORD(2, 0);
62e76326 148
099a1791 149 err = WSAStartup((WORD) iVersionRequested, &wsaData);
62e76326 150
099a1791 151 if (err) {
62e76326 152 s_iInitCount = -1;
153 return (s_iInitCount);
099a1791 154 }
62e76326 155
099a1791 156 if (LOBYTE(wsaData.wVersion) != 2 ||
62e76326 157 HIBYTE(wsaData.wVersion) != 0) {
158 s_iInitCount = -2;
159 WSACleanup();
160 return (s_iInitCount);
099a1791 161 }
62e76326 162
14942edd 163 ++s_iInitCount;
099a1791 164 return (s_iInitCount);
165}
166
167void Win32SockCleanup(void)
168{
169 if (--s_iInitCount == 0)
62e76326 170 WSACleanup();
171
099a1791 172 return;
173}
62e76326 174
1191b93b 175#endif
7395afb8 176
2ac76861 177static const char *
178safe_str(const char *str)
7395afb8 179{
180 return str ? str : "";
181}
182
7021844c 183/* relaxed number format */
184static int
185is_number(const char *str)
186{
187 return strspn(str, "\t -+01234567890./\n") == strlen(str);
188}
189
a2c963ae 190static const char *
2ac76861 191xstrtok(char **str, char del)
7395afb8 192{
193 if (*str) {
62e76326 194 char *p = strchr(*str, del);
195 char *tok = *str;
196 int len;
197
198 if (p) {
199 *str = p + 1;
200 *p = '\0';
201 } else
202 *str = NULL;
203
204 /* trim */
205 len = strlen(tok);
206
207 while (len && xisspace(tok[len - 1]))
208 tok[--len] = '\0';
209
210 while (xisspace(*tok))
14942edd 211 ++tok;
62e76326 212
213 return tok;
7395afb8 214 } else
62e76326 215 return "";
7395afb8 216}
090089c4 217
24382924 218static void
8203a132 219print_trailer(void)
090089c4 220{
df339671 221 printf("<HR noshade size=\"1px\">\n");
090089c4 222 printf("<ADDRESS>\n");
223 printf("Generated %s, by %s/%s@%s\n",
62e76326 224 mkrfc1123(now), progname, VERSION, getfullhostname());
a8f7d3ee 225 printf("</ADDRESS></BODY></HTML>\n");
090089c4 226}
227
24382924 228static void
a2c963ae 229auth_html(const char *host, int port, const char *user_name)
090089c4 230{
42ad37af 231 FILE *fp;
232 int need_host = 1;
233
2ac76861 234 if (!user_name)
62e76326 235 user_name = "";
236
2ac76861 237 if (!host || !strlen(host))
42ad37af 238 host = "";
62e76326 239
b073fc4b
AJ
240 fp = fopen("cachemgr.conf", "r");
241
242 if (fp == NULL)
243 fp = fopen(DEFAULT_CACHEMGR_CONFIG, "r");
244
245 if (fp == NULL)
246 printf("X-Error: message=\"Unable to open config %s\"", DEFAULT_CACHEMGR_CONFIG);
247
df339671 248 printf("Content-Type: text/html\r\n\r\n");
62e76326 249
df339671 250 printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n");
62e76326 251
df339671 252 printf("<HTML><HEAD><TITLE>Cache Manager Interface</TITLE>\n");
62e76326 253
b073fc4b
AJ
254 printf("<STYLE type=\"text/css\"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}--></STYLE>\n");
255
256 printf("<script type=\"text/javascript\">\n");
257 printf("function TS(t, s) {\n");
258 printf(" var x = new XMLHttpRequest();\n");
259 printf(" x.open('GET', 'http' + s + '://' + t + '/squid-internal-mgr/', true);\n");
260 printf(" x.onreadystatechange=function() {\n");
261 printf(" if (x.readyState==4) {\n");
262 printf(" if ((x.status>=200 && x.status <= 299) || x.status==401) {\n");
263 printf(" var v = x.getResponseHeader('Server');\n");
264 printf(" if (v.substring(0,8) == 'squid/3.' && (v[8]=='H' || parseInt(v.substring(8)) >= 2)) {\n");
265 printf(" var d = document.getElementById('H' + s + 'mgr');\n");
266 printf(" if (d.innerHTML == '') d.innerHTML = '<h2>HTTP' + (s=='s'?'S':'') + ' Managed Proxies</h2>';\n");
267 printf(" d.innerHTML = d.innerHTML + '<p>Host: <a href=\"http' + s + '://' + t + '/squid-internal-mgr/\">' + t + '</a></p>';\n");
268 printf(" }}}}\n");
269 printf(" x.send(null);\n");
270 printf("}\n");
271 printf("</script>\n");
272
273 printf("</HEAD>\n");
62e76326 274
a8f7d3ee 275 printf("<BODY><H1>Cache Manager Interface</H1>\n");
62e76326 276
f7d9a2ad 277 printf("<P>This is a WWW interface to the instrumentation interface\n");
62e76326 278
f7d9a2ad 279 printf("for the Squid object cache.</P>\n");
62e76326 280
df339671 281 printf("<HR noshade size=\"1px\">\n");
62e76326 282
b073fc4b
AJ
283 printf("<div id=\"Hsmgr\"></div>\n");
284 printf("<div id=\"Hmgr\"></div>\n");
285 printf("<div id=\"Cmgr\">\n");
286 printf("<h2>CGI Managed Proxies</h2>\n");
f23f96e6 287 printf("<FORM METHOD=\"POST\" ACTION=\"%s\">\n", script_name);
62e76326 288
d980562f 289 printf("<TABLE BORDER=\"0\" CELLPADDING=\"10\" CELLSPACING=\"1\">\n");
62e76326 290
42ad37af 291 if (fp != NULL) {
292 int servers = 0;
293 char config_line[BUFSIZ];
294
295 while (fgets(config_line, BUFSIZ, fp)) {
296 char *server, *comment;
297 strtok(config_line, "\r\n");
298
299 if (config_line[0] == '#')
300 continue;
301
302 if (config_line[0] == '\0')
303 continue;
304
305 if ((server = strtok(config_line, " \t")) == NULL)
306 continue;
307
308 if (strchr(server, '*') || strchr(server, '[') || strchr(server, '?')) {
309 need_host = -1;
310 continue;
311 }
312
313 comment = strtok(NULL, "");
314
315 if (comment)
316 while (*comment == ' ' || *comment == '\t')
14942edd 317 ++comment;
42ad37af 318
319 if (!comment || !*comment)
320 comment = server;
321
b073fc4b
AJ
322 if (!servers)
323 printf("<TR><TH ALIGN=\"left\">Cache Server:</TH><TD><SELECT id=\"server\" NAME=\"server\">\n");
42ad37af 324
325 printf("<OPTION VALUE=\"%s\"%s>%s</OPTION>\n", server, (servers || *host) ? "" : " SELECTED", comment);
14942edd 326 ++servers;
42ad37af 327 }
328
329 if (servers) {
330 if (need_host == 1 && !*host)
331 need_host = 0;
332
333 if (need_host)
334 printf("<OPTION VALUE=\"\"%s>Other</OPTION>\n", (*host) ? " SELECTED" : "");
335
336 printf("</SELECT></TR>\n");
337 }
338
339 fclose(fp);
340 }
341
342 if (need_host) {
343 if (need_host == 1 && !*host)
344 host = "localhost";
345
346 printf("<TR><TH ALIGN=\"left\">Cache Host:</TH><TD><INPUT NAME=\"host\" ");
62e76326 347
42ad37af 348 printf("size=\"30\" VALUE=\"%s\"></TD></TR>\n", host);
62e76326 349
42ad37af 350 printf("<TR><TH ALIGN=\"left\">Cache Port:</TH><TD><INPUT NAME=\"port\" ");
351
352 printf("size=\"30\" VALUE=\"%d\"></TD></TR>\n", port);
353 }
62e76326 354
7395afb8 355 printf("<TR><TH ALIGN=\"left\">Manager name:</TH><TD><INPUT NAME=\"user_name\" ");
62e76326 356
df339671 357 printf("size=\"30\" VALUE=\"%s\"></TD></TR>\n", user_name);
62e76326 358
7395afb8 359 printf("<TR><TH ALIGN=\"left\">Password:</TH><TD><INPUT TYPE=\"password\" NAME=\"passwd\" ");
62e76326 360
df339671 361 printf("size=\"30\" VALUE=\"\"></TD></TR>\n");
62e76326 362
7395afb8 363 printf("</TABLE><BR CLEAR=\"all\">\n");
62e76326 364
d23f4e1b 365 printf("<INPUT TYPE=\"submit\" VALUE=\"Continue...\">\n");
62e76326 366
b073fc4b
AJ
367 printf("</FORM></div>\n");
368
369 printf("<script type=\"text/javascript\">\n");
370 printf("var s = document.getElementById(\"server\");\n");
371 printf("for (var i = 0; i < s.childElementCount; i++) {\n");
372 printf(" TS(s.children[i].value, '');\n");
373 printf(" TS(s.children[i].value, 's');\n");
374 printf("}</script>\n");
62e76326 375
090089c4 376 print_trailer();
377}
378
d23f4e1b 379static void
380error_html(const char *msg)
090089c4 381{
df339671 382 printf("Content-Type: text/html\r\n\r\n");
383 printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n");
384 printf("<HTML><HEAD><TITLE>Cache Manager Error</TITLE>\n");
d8c0128e 385 printf("<STYLE type=\"text/css\"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}--></STYLE></HEAD>\n");
d23f4e1b 386 printf("<BODY><H1>Cache Manager Error</H1>\n");
9a6a600f 387 printf("<P>\n%s</P>\n", html_quote(msg));
d23f4e1b 388 print_trailer();
090089c4 389}
390
7395afb8 391/* returns http status extracted from status line or -1 on parsing failure */
392static int
393parse_status_line(const char *sline, const char **statusStr)
394{
395 const char *sp = strchr(sline, ' ');
62e76326 396
7395afb8 397 if (statusStr)
62e76326 398 *statusStr = NULL;
399
7395afb8 400 if (strncasecmp(sline, "HTTP/", 5) || !sp)
62e76326 401 return -1;
402
3d0ac046 403 while (xisspace(*++sp));
b6a2f15e 404 if (!xisdigit(*sp))
62e76326 405 return -1;
406
7395afb8 407 if (statusStr)
62e76326 408 *statusStr = sp;
409
7395afb8 410 return atoi(sp);
411}
412
d23f4e1b 413static char *
7395afb8 414menu_url(cachemgr_request * req, const char *action)
090089c4 415{
d23f4e1b 416 static char url[1024];
137ee196 417 snprintf(url, sizeof(url), "%s?host=%s&port=%d&user_name=%s&operation=%s&auth=%s",
62e76326 418 script_name,
419 req->hostname,
420 req->port,
421 safe_str(req->user_name),
422 action,
423 safe_str(req->pub_auth));
d23f4e1b 424 return url;
090089c4 425}
426
1f1eee3f
AJ
427static void
428munge_menu_line(MemBuf &out, const char *buf, cachemgr_request * req)
090089c4 429{
d23f4e1b 430 char *x;
7395afb8 431 const char *a;
432 const char *d;
433 const char *p;
434 char *a_url;
7021844c 435 char *buf_copy;
62e76326 436
1f1eee3f
AJ
437 const char bufLen = strlen(buf);
438 if (bufLen < 1 || *buf != ' ') {
439 out.append(buf, bufLen);
440 return;
441 }
62e76326 442
1f1eee3f 443 buf_copy = x = xstrndup(buf, bufLen);
62e76326 444
7395afb8 445 a = xstrtok(&x, '\t');
62e76326 446
7395afb8 447 d = xstrtok(&x, '\t');
62e76326 448
7395afb8 449 p = xstrtok(&x, '\t');
62e76326 450
7395afb8 451 a_url = xstrdup(menu_url(req, a));
62e76326 452
7395afb8 453 /* no reason to give a url for a disabled action */
454 if (!strcmp(p, "disabled"))
1f1eee3f 455 out.appendf("<LI type=\"circle\">%s (disabled)<A HREF=\"%s\">.</A>\n", d, a_url);
7395afb8 456 else
62e76326 457 /* disable a hidden action (requires a password, but password is not in squid.conf) */
458 if (!strcmp(p, "hidden"))
1f1eee3f 459 out.appendf("<LI type=\"circle\">%s (hidden)<A HREF=\"%s\">.</A>\n", d, a_url);
62e76326 460 else
461 /* disable link if authentication is required and we have no password */
462 if (!strcmp(p, "protected") && !req->passwd)
1f1eee3f
AJ
463 out.appendf("<LI type=\"circle\">%s (requires <a href=\"%s\">authentication</a>)<A HREF=\"%s\">.</A>\n",
464 d, menu_url(req, "authenticate"), a_url);
62e76326 465 else
466 /* highlight protected but probably available entries */
467 if (!strcmp(p, "protected"))
1f1eee3f
AJ
468 out.appendf("<LI type=\"square\"><A HREF=\"%s\"><font color=\"#FF0000\">%s</font></A>\n",
469 a_url, d);
62e76326 470
7395afb8 471 /* public entry or unknown type of protection */
62e76326 472 else
1f1eee3f 473 out.appendf("<LI type=\"disk\"><A HREF=\"%s\">%s</A>\n", a_url, d);
62e76326 474
7395afb8 475 xfree(a_url);
62e76326 476
7021844c 477 xfree(buf_copy);
7021844c 478}
479
1f1eee3f
AJ
480static void
481munge_other_line(MemBuf &out, const char *buf, cachemgr_request *)
7021844c 482{
62e76326 483 static const char *ttags[] = {"td", "th"};
484
728da2ee 485 static int table_line_num = 0;
486 static int next_is_header = 0;
7021844c 487 int is_header = 0;
488 const char *ttag;
7021844c 489 char *buf_copy;
b9bc2838 490 char *x, *p;
7021844c 491 /* does it look like a table? */
62e76326 492
7021844c 493 if (!strchr(buf, '\t') || *buf == '\t') {
62e76326 494 /* nope, just text */
1f1eee3f
AJ
495 if (table_line_num)
496 out.append("</table>\n<pre>", 14);
497 out.appendf("%s", html_quote(buf));
62e76326 498 table_line_num = 0;
1f1eee3f 499 return;
7021844c 500 }
62e76326 501
b9bc2838 502 /* start html table */
503 if (!table_line_num) {
1f1eee3f 504 out.append("</pre><table cellpadding=\"2\" cellspacing=\"1\">\n", 46);
62e76326 505 next_is_header = 0;
b9bc2838 506 }
62e76326 507
b9bc2838 508 /* remove '\n' */
509 is_header = (!table_line_num || next_is_header) && !strchr(buf, ':') && !is_number(buf);
62e76326 510
7021844c 511 ttag = ttags[is_header];
62e76326 512
7021844c 513 /* record starts */
1f1eee3f 514 out.append("<tr>", 4);
62e76326 515
7021844c 516 /* substitute '\t' */
517 buf_copy = x = xstrdup(buf);
62e76326 518
399e85ea 519 if ((p = strchr(x, '\n')))
62e76326 520 *p = '\0';
521
b9bc2838 522 while (x && strlen(x)) {
62e76326 523 int column_span = 1;
524 const char *cell = xstrtok(&x, '\t');
525
526 while (x && *x == '\t') {
14942edd
FC
527 ++column_span;
528 ++x;
62e76326 529 }
530
1f1eee3f
AJ
531 out.appendf("<%s colspan=\"%d\" align=\"%s\">%s</%s>",
532 ttag, column_span,
533 is_header ? "center" : is_number(cell) ? "right" : "left",
534 html_quote(cell), ttag);
7021844c 535 }
62e76326 536
7021844c 537 xfree(buf_copy);
538 /* record ends */
1f1eee3f 539 out.append("</tr>\n", 6);
b9bc2838 540 next_is_header = is_header && strstr(buf, "\t\t");
14942edd 541 ++table_line_num;
090089c4 542}
543
e313f2b8
AJ
544static const char *
545munge_action_line(const char *_buf, cachemgr_request * req)
546{
547 static char html[2 * 1024];
548 char *buf = xstrdup(_buf);
549 char *x = buf;
550 const char *action, *description;
551 char *p;
552
553 if ((p = strchr(x, '\n')))
3afd7aae 554 *p = '\0';
e313f2b8 555 action = xstrtok(&x, '\t');
958caaf8
AJ
556 if (!action) {
557 xfree(buf);
558 return "";
559 }
e313f2b8
AJ
560 description = xstrtok(&x, '\t');
561 if (!description)
3afd7aae 562 description = action;
e313f2b8 563 snprintf(html, sizeof(html), " <a href=\"%s\">%s</a>", menu_url(req, action), description);
958caaf8 564 xfree(buf);
e313f2b8
AJ
565 return html;
566}
567
d23f4e1b 568static int
569read_reply(int s, cachemgr_request * req)
090089c4 570{
2ac76861 571 char buf[4 * 1024];
7aa9bb3e 572#if _SQUID_WINDOWS_
62e76326 573
099a1791 574 int reply;
a760862a 575 char *tmpfile = tempnam(NULL, "tmp0000");
576 FILE *fp = fopen(tmpfile, "w+");
099a1791 577#else
62e76326 578
d23f4e1b 579 FILE *fp = fdopen(s, "r");
099a1791 580#endif
7395afb8 581 /* interpretation states */
2ac76861 582 enum {
e313f2b8 583 isStatusLine, isHeaders, isActions, isBodyStart, isBody, isForward, isEof, isForwardEof, isSuccess, isError
2ac76861 584 } istate = isStatusLine;
d23f4e1b 585 int parse_menu = 0;
7395afb8 586 const char *action = req->action;
587 const char *statusStr = NULL;
588 int status = -1;
62e76326 589
d23f4e1b 590 if (0 == strlen(req->action))
62e76326 591 parse_menu = 1;
d23f4e1b 592 else if (0 == strcasecmp(req->action, "menu"))
62e76326 593 parse_menu = 1;
594
d23f4e1b 595 if (fp == NULL) {
7aa9bb3e 596#if _SQUID_WINDOWS_
a760862a 597 perror(tmpfile);
598 xfree(tmpfile);
599#else
bba20018 600
62e76326 601 perror("fdopen");
d52318df 602#endif
bba20018
AJ
603
604 close(s);
62e76326 605 return 1;
090089c4 606 }
62e76326 607
7aa9bb3e 608#if _SQUID_WINDOWS_
ad1fa9c9 609
610 while ((reply=recv(s, buf , sizeof(buf), 0)) > 0)
611 fwrite(buf, 1, reply, fp);
62e76326 612
099a1791 613 rewind(fp);
62e76326 614
099a1791 615#endif
62e76326 616
7395afb8 617 if (parse_menu)
62e76326 618 action = "menu";
619
7395afb8 620 /* read reply interpreting one line at a time depending on state */
621 while (istate < isEof) {
62e76326 622 if (!fgets(buf, sizeof(buf), fp))
623 istate = istate == isForward ? isForwardEof : isEof;
624
625 switch (istate) {
626
627 case isStatusLine:
628 /* get HTTP status */
629 /* uncomment the following if you want to debug headers */
630 /* fputs("\r\n\r\n", stdout); */
631 status = parse_status_line(buf, &statusStr);
632 istate = status == 200 ? isHeaders : isForward;
633 /* if cache asks for authentication, we have to reset our info */
634
635 if (status == 401 || status == 407) {
636 reset_auth(req);
f53969cc 637 status = 403; /* Forbiden, see comments in case isForward: */
62e76326 638 }
639
640 /* this is a way to pass HTTP status to the Web server */
641 if (statusStr)
f53969cc 642 printf("Status: %d %s", status, statusStr); /* statusStr has '\n' */
62e76326 643
644 break;
645
646 case isHeaders:
647 /* forward header field */
f53969cc
SM
648 if (!strcmp(buf, "\r\n")) { /* end of headers */
649 fputs("Content-Type: text/html\r\n", stdout); /* add our type */
62e76326 650 istate = isBodyStart;
651 }
652
f53969cc 653 if (strncasecmp(buf, "Content-Type:", 13)) /* filter out their type */
62e76326 654 fputs(buf, stdout);
655
656 break;
657
658 case isBodyStart:
659 printf("<!DOCTYPE HTML PUBLIC \"-//W3C//DTD HTML 4.01 Transitional//EN\" \"http://www.w3.org/TR/html4/loose.dtd\">\n");
660
661 printf("<HTML><HEAD><TITLE>CacheMgr@%s: %s</TITLE>\n",
662 req->hostname, action);
663
907e86e0 664 printf("<STYLE type=\"text/css\"><!--BODY{background-color:#ffffff;font-family:verdana,sans-serif}TABLE{background-color:#333333;border:0pt;padding:0pt}TH,TD{background-color:#ffffff;white-space:nowrap}--></STYLE>\n");
62e76326 665
666 printf("</HEAD><BODY>\n");
667
668 if (parse_menu) {
669 printf("<H2><a href=\"%s\">Cache Manager</a> menu for %s:</H2>",
670 menu_url(req, "authenticate"), req->hostname);
671 printf("<UL>\n");
672 } else {
673 printf("<P><A HREF=\"%s\">%s</A>\n<HR noshade size=\"1px\">\n",
674 menu_url(req, "menu"), "Cache Manager menu");
675 printf("<PRE>\n");
676 }
677
e313f2b8 678 istate = isActions;
f53969cc 679 /* yes, fall through, we do not want to loose the first line */
e313f2b8
AJ
680
681 case isActions:
682 if (strncmp(buf, "action:", 7) == 0) {
683 fputs(" ", stdout);
684 fputs(munge_action_line(buf + 7, req), stdout);
685 break;
686 }
687 if (parse_menu) {
688 printf("<UL>\n");
689 } else {
690 printf("<HR noshade size=\"1px\">\n");
691 printf("<PRE>\n");
692 }
693
62e76326 694 istate = isBody;
f53969cc 695 /* yes, fall through, we do not want to loose the first line */
62e76326 696
697 case isBody:
1f1eee3f 698 {
62e76326 699 /* interpret [and reformat] cache response */
1f1eee3f
AJ
700 MemBuf out;
701 out.init();
62e76326 702 if (parse_menu)
1f1eee3f 703 munge_menu_line(out, buf, req);
62e76326 704 else
1f1eee3f 705 munge_other_line(out, buf, req);
62e76326 706
1f1eee3f
AJ
707 fputs(out.buf, stdout);
708 }
709 break;
62e76326 710
711 case isForward:
712 /* forward: no modifications allowed */
713 /*
714 * Note: we currently do not know any way to get browser.reply to
715 * 401 to .cgi because web server filters out all auth info. Thus we
716 * disable authentication headers for now.
717 */
f53969cc 718 if (!strncasecmp(buf, "WWW-Authenticate:", 17) || !strncasecmp(buf, "Proxy-Authenticate:", 19)); /* skip */
62e76326 719 else
720 fputs(buf, stdout);
721
722 break;
723
724 case isEof:
725 /* print trailers */
726 if (parse_menu)
727 printf("</UL>\n");
728 else
729 printf("</table></PRE>\n");
730
731 print_trailer();
732
733 istate = isSuccess;
734
735 break;
736
737 case isForwardEof:
738 /* indicate that we finished processing an "error" sequence */
739 istate = isError;
740
741 break;
742
743 default:
744 printf("%s: internal bug: invalid state reached: %d", script_name, istate);
745
746 istate = isError;
747 }
d23f4e1b 748 }
62e76326 749
4300768d 750 fclose(fp);
7aa9bb3e 751#if _SQUID_WINDOWS_
bba20018 752
a760862a 753 remove(tmpfile);
754 xfree(tmpfile);
755 close(s);
bba20018 756
a760862a 757#endif
758
d23f4e1b 759 return 0;
d1a43e28 760}
090089c4 761
d23f4e1b 762static int
763process_request(cachemgr_request * req)
090089c4 764{
62e76326 765
cc192b50 766 char ipbuf[MAX_IPSTRLEN];
767 struct addrinfo *AI = NULL;
b7ac5457 768 Ip::Address S;
d23f4e1b 769 int s;
770 int l;
62e76326 771
2ac76861 772 static char buf[2 * 1024];
62e76326 773
d23f4e1b 774 if (req == NULL) {
62e76326 775 auth_html(CACHEMGR_HOSTNAME, CACHE_HTTP_PORT, "");
776 return 1;
d23f4e1b 777 }
62e76326 778
d23f4e1b 779 if (req->hostname == NULL) {
62e76326 780 req->hostname = xstrdup(CACHEMGR_HOSTNAME);
d23f4e1b 781 }
62e76326 782
d23f4e1b 783 if (req->port == 0) {
62e76326 784 req->port = CACHE_HTTP_PORT;
d23f4e1b 785 }
62e76326 786
d23f4e1b 787 if (req->action == NULL) {
62e76326 788 req->action = xstrdup("");
d23f4e1b 789 }
62e76326 790
42ad37af 791 if (strcmp(req->action, "authenticate") == 0) {
62e76326 792 auth_html(req->hostname, req->port, req->user_name);
793 return 0;
7395afb8 794 }
62e76326 795
42ad37af 796 if (!check_target_acl(req->hostname, req->port)) {
958caaf8 797 snprintf(buf, sizeof(buf), "target %s:%d not allowed in cachemgr.conf\n", req->hostname, req->port);
42ad37af 798 error_html(buf);
799 return 1;
800 }
801
cc192b50 802 S = *gethostbyname(req->hostname);
62e76326 803
4dd643d5 804 if ( !S.isAnyAddr() ) {
cc192b50 805 (void) 0;
8df44716 806 } else if ((S = req->hostname))
62e76326 807 (void) 0;
d23f4e1b 808 else {
958caaf8 809 snprintf(buf, sizeof(buf), "Unknown host: %s\n", req->hostname);
62e76326 810 error_html(buf);
811 return 1;
d23f4e1b 812 }
62e76326 813
4dd643d5 814 S.port(req->port);
cc192b50 815
4dd643d5 816 S.getAddrInfo(AI);
62e76326 817
616f5a95
AJ
818#if USE_IPV6
819 if ((s = socket( AI->ai_family, SOCK_STREAM, 0)) < 0) {
820#else
821 if ((s = socket(PF_INET, SOCK_STREAM, 0)) < 0) {
822#endif
b69e9ffa
AJ
823 int xerrno = errno;
824 snprintf(buf, sizeof(buf), "socket: %s\n", xstrerr(xerrno));
616f5a95 825 error_html(buf);
851614a8 826 Ip::Address::FreeAddr(AI);
616f5a95
AJ
827 return 1;
828 }
829
cc192b50 830 if (connect(s, AI->ai_addr, AI->ai_addrlen) < 0) {
b69e9ffa
AJ
831 int xerrno = errno;
832 snprintf(buf, sizeof(buf), "connect %s: %s\n", S.toUrl(ipbuf,MAX_IPSTRLEN), xstrerr(xerrno));
62e76326 833 error_html(buf);
851614a8 834 Ip::Address::FreeAddr(AI);
958caaf8 835 close(s);
62e76326 836 return 1;
d23f4e1b 837 }
62e76326 838
851614a8 839 Ip::Address::FreeAddr(AI);
cc192b50 840
7395afb8 841 l = snprintf(buf, sizeof(buf),
3469551a 842 "GET cache_object://%s/%s%s%s HTTP/1.0\r\n"
e4e635e1 843 "User-Agent: cachemgr.cgi/%s\r\n"
62e76326 844 "Accept: */*\r\n"
f53969cc 845 "%s" /* Authentication info or nothing */
62e76326 846 "\r\n",
847 req->hostname,
848 req->action,
3469551a
CT
849 req->workers? "?workers=" : (req->processes ? "?processes=" : ""),
850 req->workers? req->workers : (req->processes ? req->processes: ""),
e4e635e1 851 VERSION,
62e76326 852 make_auth_header(req));
5fbb6c94 853 if (write(s, buf, l) < 0) {
ec85ebda 854 fprintf(stderr,"ERROR: (%d) writing request: '%s'\n", errno, buf);
5fbb6c94 855 } else {
ec85ebda 856 debug("wrote request: '%s'\n", buf);
5fbb6c94 857 }
d23f4e1b 858 return read_reply(s, req);
090089c4 859}
860
684c2720 861int
e1381638
AJ
862main(int argc, char *argv[])
863{
d23f4e1b 864 char *s;
865 cachemgr_request *req;
62e76326 866
d1a43e28 867 now = time(NULL);
7aa9bb3e 868#if _SQUID_WINDOWS_
62e76326 869
099a1791 870 Win32SockInit();
a760862a 871 atexit(Win32SockCleanup);
ad1fa9c9 872 _setmode( _fileno( stdin ), _O_BINARY );
873 _setmode( _fileno( stdout ), _O_BINARY );
874 _fmode = _O_BINARY;
875
099a1791 876 if ((s = strrchr(argv[0], '\\')))
877#else
62e76326 878
090089c4 879 if ((s = strrchr(argv[0], '/')))
099a1791 880#endif
62e76326 881
882 progname = xstrdup(s + 1);
090089c4 883 else
62e76326 884 progname = xstrdup(argv[0]);
885
d23f4e1b 886 if ((s = getenv("SCRIPT_NAME")) != NULL)
62e76326 887 script_name = xstrdup(s);
888
f54f527e
AJ
889 char **args = argv;
890 while (argc > 1 && args[1][0] == '-') {
ec85ebda
AJ
891// const char *value = "";
892 char option = args[1][1];
893 switch (option) {
894 case 'd':
895 debug_enabled = 1;
896 break;
897 default:
898#if 0 // unused for now.
899 if (strlen(args[1]) > 2) {
900 value = args[1] + 2;
901 } else if (argc > 2) {
902 value = args[2];
14942edd 903 ++args;
5e263176 904 --argc;
ec85ebda
AJ
905 } else
906 value = "";
ec85ebda 907#endif
ded1ca0b 908 break;
ec85ebda 909 }
14942edd 910 ++args;
5e263176 911 --argc;
ec85ebda
AJ
912 }
913
d23f4e1b 914 req = read_request();
62e76326 915
d23f4e1b 916 return process_request(req);
090089c4 917}
918
d23f4e1b 919static char *
e1381638
AJ
920read_post_request(void)
921{
d23f4e1b 922 char *s;
62e76326 923
d23f4e1b 924 if ((s = getenv("REQUEST_METHOD")) == NULL)
62e76326 925 return NULL;
926
d23f4e1b 927 if (0 != strcasecmp(s, "POST"))
62e76326 928 return NULL;
929
d23f4e1b 930 if ((s = getenv("CONTENT_LENGTH")) == NULL)
62e76326 931 return NULL;
932
958caaf8 933 if (*s == '-') // negative length content huh?
62e76326 934 return NULL;
935
958caaf8 936 uint64_t len;
62e76326 937
958caaf8
AJ
938 char *endptr = s+ strlen(s);
939 if ((len = strtoll(s, &endptr, 10)) <= 0)
bdcd85c3 940 return NULL;
62e76326 941
958caaf8
AJ
942 // limit the input to something reasonable.
943 // 4KB should be enough for the GET/POST data length, but may be extended.
e4877287 944 size_t bufLen = (len < 4096 ? len : 4095);
958caaf8
AJ
945 char *buf = (char *)xmalloc(bufLen + 1);
946
e4877287 947 size_t readLen = fread(buf, 1, bufLen, stdin);
958caaf8
AJ
948 if (readLen == 0) {
949 xfree(buf);
950 return NULL;
951 }
952 buf[readLen] = '\0';
953 len -= readLen;
954
955 // purge the remainder of the request entity
4bc67ec8 956 while (len > 0 && readLen) {
958caaf8 957 char temp[65535];
e4877287 958 readLen = fread(temp, 1, 65535, stdin);
958caaf8
AJ
959 len -= readLen;
960 }
62e76326 961
d23f4e1b 962 return buf;
963}
090089c4 964
d23f4e1b 965static char *
e1381638
AJ
966read_get_request(void)
967{
d23f4e1b 968 char *s;
62e76326 969
d23f4e1b 970 if ((s = getenv("QUERY_STRING")) == NULL)
62e76326 971 return NULL;
972
d23f4e1b 973 return xstrdup(s);
974}
090089c4 975
099a1791 976static cachemgr_request *
e1381638
AJ
977read_request(void)
978{
d23f4e1b 979 char *buf;
62e76326 980
d23f4e1b 981 cachemgr_request *req;
982 char *s;
03336c67 983 char *t = NULL;
d23f4e1b 984 char *q;
62e76326 985
d23f4e1b 986 if ((buf = read_post_request()) != NULL)
62e76326 987 (void) 0;
d23f4e1b 988 else if ((buf = read_get_request()) != NULL)
62e76326 989 (void) 0;
233794cd 990 else
62e76326 991 return NULL;
992
7aa9bb3e 993#if _SQUID_WINDOWS_
62e76326 994
099a1791 995 if (strlen(buf) == 0 || strlen(buf) == 4000)
996#else
62e76326 997
d23f4e1b 998 if (strlen(buf) == 0)
099a1791 999#endif
368520fc 1000 {
34ede744 1001 xfree(buf);
62e76326 1002 return NULL;
368520fc 1003 }
62e76326 1004
e6ccf245 1005 req = (cachemgr_request *)xcalloc(1, sizeof(cachemgr_request));
62e76326 1006
d23f4e1b 1007 for (s = strtok(buf, "&"); s != NULL; s = strtok(NULL, "&")) {
03336c67 1008 safe_free(t);
62e76326 1009 t = xstrdup(s);
1010
1011 if ((q = strchr(t, '=')) == NULL)
1012 continue;
1013
14942edd
FC
1014 *q = '\0';
1015 ++q;
62e76326 1016
42ad37af 1017 rfc1738_unescape(t);
1018
1019 rfc1738_unescape(q);
1020
a37d6070 1021 if (0 == strcmp(t, "server") && strlen(q))
42ad37af 1022 req->server = xstrdup(q);
a37d6070 1023 else if (0 == strcmp(t, "host") && strlen(q))
62e76326 1024 req->hostname = xstrdup(q);
a37d6070 1025 else if (0 == strcmp(t, "port") && strlen(q))
62e76326 1026 req->port = atoi(q);
a37d6070 1027 else if (0 == strcmp(t, "user_name") && strlen(q))
62e76326 1028 req->user_name = xstrdup(q);
a37d6070 1029 else if (0 == strcmp(t, "passwd") && strlen(q))
62e76326 1030 req->passwd = xstrdup(q);
a37d6070 1031 else if (0 == strcmp(t, "auth") && strlen(q))
62e76326 1032 req->pub_auth = xstrdup(q), decode_pub_auth(req);
a37d6070 1033 else if (0 == strcmp(t, "operation"))
62e76326 1034 req->action = xstrdup(q);
a37d6070 1035 else if (0 == strcmp(t, "workers") && strlen(q))
3469551a 1036 req->workers = xstrdup(q);
a37d6070 1037 else if (0 == strcmp(t, "processes") && strlen(q))
3469551a 1038 req->processes = xstrdup(q);
d23f4e1b 1039 }
03336c67 1040 safe_free(t);
62e76326 1041
42ad37af 1042 if (req->server && !req->hostname) {
1043 char *p;
1044 req->hostname = strtok(req->server, ":");
1045
1046 if ((p = strtok(NULL, ":")))
1047 req->port = atoi(p);
1048 }
1049
7395afb8 1050 make_pub_auth(req);
3469551a
CT
1051 debug("cmgr: got req: host: '%s' port: %d uname: '%s' passwd: '%s' auth: '%s' oper: '%s' workers: '%s' processes: '%s'\n",
1052 safe_str(req->hostname), req->port, safe_str(req->user_name), safe_str(req->passwd), safe_str(req->pub_auth), safe_str(req->action), safe_str(req->workers), safe_str(req->processes));
d23f4e1b 1053 return req;
090089c4 1054}
7395afb8 1055
7395afb8 1056/* Routines to support authentication */
1057
1058/*
3afd7aae 1059 * Encodes auth info into a "public" form.
7395afb8 1060 * Currently no powerful encryption is used.
1061 */
1062static void
e1381638
AJ
1063make_pub_auth(cachemgr_request * req)
1064{
7395afb8 1065 static char buf[1024];
1066 safe_free(req->pub_auth);
ec85ebda 1067 debug("cmgr: encoding for pub...\n");
62e76326 1068
7021844c 1069 if (!req->passwd || !strlen(req->passwd))
62e76326 1070 return;
1071
7395afb8 1072 /* host | time | user | passwd */
8bdd0cec
AJ
1073 const int bufLen = snprintf(buf, sizeof(buf), "%s|%d|%s|%s",
1074 req->hostname,
1075 (int) now,
1076 req->user_name ? req->user_name : "",
1077 req->passwd);
ec85ebda 1078 debug("cmgr: pre-encoded for pub: %s\n", buf);
62e76326 1079
8bdd0cec
AJ
1080 const int encodedLen = base64_encode_len(bufLen);
1081 req->pub_auth = (char *) xmalloc(encodedLen);
aadbbd7d
AJ
1082 struct base64_encode_ctx ctx;
1083 base64_encode_init(&ctx);
1084 size_t blen = base64_encode_update(&ctx, reinterpret_cast<uint8_t*>(req->pub_auth), bufLen, reinterpret_cast<uint8_t*>(buf));
1085 blen += base64_encode_final(&ctx, reinterpret_cast<uint8_t*>(req->pub_auth)+blen);
1086 req->pub_auth[blen] = '\0';
8bdd0cec 1087 debug("cmgr: encoded: '%s'\n", req->pub_auth);
7395afb8 1088}
1089
1090static void
e1381638
AJ
1091decode_pub_auth(cachemgr_request * req)
1092{
7395afb8 1093 char *buf;
1094 const char *host_name;
1095 const char *time_str;
1096 const char *user_name;
1097 const char *passwd;
1098
ec85ebda 1099 debug("cmgr: decoding pub: '%s'\n", safe_str(req->pub_auth));
7395afb8 1100 safe_free(req->passwd);
62e76326 1101
7395afb8 1102 if (!req->pub_auth || strlen(req->pub_auth) < 4 + strlen(safe_str(req->hostname)))
62e76326 1103 return;
1104
aadbbd7d 1105 size_t decodedLen = BASE64_DECODE_LENGTH(strlen(req->pub_auth));
8bdd0cec 1106 buf = (char*)xmalloc(decodedLen);
aadbbd7d
AJ
1107 struct base64_decode_ctx ctx;
1108 base64_decode_init(&ctx);
ccd727e0
AJ
1109 if (!base64_decode_update(&ctx, &decodedLen, reinterpret_cast<uint8_t*>(buf), strlen(req->pub_auth), reinterpret_cast<const uint8_t*>(req->pub_auth)) ||
1110 !base64_decode_final(&ctx)) {
aadbbd7d
AJ
1111 debug("cmgr: base64 decode failure. Incomplete auth token string.\n");
1112 xfree(buf);
1113 return;
1114 }
62e76326 1115
ec85ebda 1116 debug("cmgr: length ok\n");
62e76326 1117
7395afb8 1118 /* parse ( a lot of memory leaks, but that is cachemgr style :) */
90212e68
AJ
1119 if ((host_name = strtok(buf, "|")) == NULL) {
1120 xfree(buf);
62e76326 1121 return;
90212e68 1122 }
62e76326 1123
ec85ebda 1124 debug("cmgr: decoded host: '%s'\n", host_name);
62e76326 1125
90212e68
AJ
1126 if ((time_str = strtok(NULL, "|")) == NULL) {
1127 xfree(buf);
62e76326 1128 return;
90212e68 1129 }
62e76326 1130
ec85ebda 1131 debug("cmgr: decoded time: '%s' (now: %d)\n", time_str, (int) now);
62e76326 1132
90212e68
AJ
1133 if ((user_name = strtok(NULL, "|")) == NULL) {
1134 xfree(buf);
62e76326 1135 return;
90212e68 1136 }
62e76326 1137
ec85ebda 1138 debug("cmgr: decoded uname: '%s'\n", user_name);
62e76326 1139
90212e68
AJ
1140 if ((passwd = strtok(NULL, "|")) == NULL) {
1141 xfree(buf);
62e76326 1142 return;
90212e68 1143 }
62e76326 1144
ec85ebda 1145 debug("cmgr: decoded passwd: '%s'\n", passwd);
62e76326 1146
7395afb8 1147 /* verify freshness and validity */
90212e68
AJ
1148 if (atoi(time_str) + passwd_ttl < now) {
1149 xfree(buf);
62e76326 1150 return;
90212e68 1151 }
62e76326 1152
90212e68
AJ
1153 if (strcasecmp(host_name, req->hostname)) {
1154 xfree(buf);
62e76326 1155 return;
90212e68 1156 }
62e76326 1157
ec85ebda 1158 debug("cmgr: verified auth. info.\n");
62e76326 1159
7395afb8 1160 /* ok, accept */
90212e68 1161 safe_free(req->user_name);
62e76326 1162
7395afb8 1163 req->user_name = xstrdup(user_name);
62e76326 1164
7395afb8 1165 req->passwd = xstrdup(passwd);
62e76326 1166
7395afb8 1167 xfree(buf);
1168}
1169
1170static void
e1381638
AJ
1171reset_auth(cachemgr_request * req)
1172{
7395afb8 1173 safe_free(req->passwd);
1174 safe_free(req->pub_auth);
1175}
1176
1177static const char *
e1381638
AJ
1178make_auth_header(const cachemgr_request * req)
1179{
7395afb8 1180 static char buf[1024];
e6ccf245 1181 size_t stringLength = 0;
62e76326 1182
2ac76861 1183 if (!req->passwd)
62e76326 1184 return "";
7395afb8 1185
8bdd0cec
AJ
1186 int bufLen = snprintf(buf, sizeof(buf), "%s:%s",
1187 req->user_name ? req->user_name : "",
1188 req->passwd);
1189
1190 int encodedLen = base64_encode_len(bufLen);
1191 if (encodedLen <= 0)
1192 return "";
7395afb8 1193
aadbbd7d
AJ
1194 uint8_t *str64 = static_cast<uint8_t*>(xmalloc(encodedLen));
1195 struct base64_encode_ctx ctx;
1196 base64_encode_init(&ctx);
1197 size_t blen = base64_encode_update(&ctx, str64, bufLen, reinterpret_cast<uint8_t*>(buf));
1198 blen += base64_encode_final(&ctx, str64+blen);
1199 str64[blen] = '\0';
62e76326 1200
bb64d879 1201 stringLength += snprintf(buf, sizeof(buf), "Authorization: Basic %.*s\r\n", (int)blen, str64);
62e76326 1202
e6ccf245 1203 assert(stringLength < sizeof(buf));
62e76326 1204
bb64d879 1205 snprintf(&buf[stringLength], sizeof(buf) - stringLength, "Proxy-Authorization: Basic %.*s\r\n", (int)blen, str64);
62e76326 1206
95a59bc9 1207 xfree(str64);
7395afb8 1208 return buf;
1209}
42ad37af 1210
1211static int
e1381638
AJ
1212check_target_acl(const char *hostname, int port)
1213{
42ad37af 1214 char config_line[BUFSIZ];
1215 FILE *fp = NULL;
1216 int ret = 0;
1217 fp = fopen("cachemgr.conf", "r");
1218
1219 if (fp == NULL)
1220 fp = fopen(DEFAULT_CACHEMGR_CONFIG, "r");
1221
1222 if (fp == NULL) {
1223#ifdef CACHEMGR_HOSTNAME_DEFINED
1224
1225 if (strcmp(hostname, CACHEMGR_HOSTNAME) == 0 && port == CACHE_HTTP_PORT)
1226 return 1;
1227
1228#else
1229
1230 if (strcmp(hostname, "localhost") == 0)
1231 return 1;
1232
1233 if (strcmp(hostname, getfullhostname()) == 0)
1234 return 1;
1235
1236#endif
1237
1238 return 0;
1239 }
1240
1241 while (fgets(config_line, BUFSIZ, fp)) {
1242 char *token = NULL;
1243 strtok(config_line, " \r\n\t");
1244
1245 if (config_line[0] == '#')
1246 continue;
1247
1248 if (config_line[0] == '\0')
1249 continue;
1250
1251 if ((token = strtok(config_line, ":")) == NULL)
1252 continue;
1253
1254#if HAVE_FNMATCH_H
1255
1256 if (fnmatch(token, hostname, 0) != 0)
1257 continue;
1258
1259#else
1260
1261 if (strcmp(token, hostname) != 0)
1262 continue;
1263
1264#endif
1265
1266 if ((token = strtok(NULL, ":")) != NULL) {
1267 int i;
1268
b4ee1908 1269 if (strcmp(token, "*") == 0)
1270
1271 ; /* Wildcard port specification */
a37d6070 1272 else if (strcmp(token, "any") == 0)
b4ee1908 1273
1274 ; /* Wildcard port specification */
1275 else if (sscanf(token, "%d", &i) != 1)
42ad37af 1276 continue;
1277
b4ee1908 1278 else if (i != port)
42ad37af 1279 continue;
1280 } else if (port != CACHE_HTTP_PORT)
1281 continue;
1282
1283 ret = 1;
1284
1285 break;
1286 }
1287
1288 fclose(fp);
1289 return ret;
1290}
f53969cc 1291