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