]> git.ipfire.org Git - thirdparty/squid.git/blame - src/cache_manager.cc
Removed static requestLink() and requestUnlink() methods. Replaced them
[thirdparty/squid.git] / src / cache_manager.cc
CommitLineData
22f3fd98 1
2/*
6dd9f4bd 3 * $Id: cache_manager.cc,v 1.36 2006/02/17 18:10:59 wessels Exp $
22f3fd98 4 *
5 * DEBUG: section 16 Cache Manager Objects
6 * AUTHOR: Duane Wessels
7 *
2b6662ba 8 * SQUID Web Proxy Cache http://www.squid-cache.org/
e25c139f 9 * ----------------------------------------------------------
22f3fd98 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.
22f3fd98 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 *
22f3fd98 34 */
35
36#include "squid.h"
528b2c61 37#include "HttpReply.h"
38#include "HttpRequest.h"
e6ccf245 39#include "Store.h"
528b2c61 40#include "fde.h"
22f3fd98 41
42#define MGR_PASSWD_SZ 128
43
62e76326 44typedef struct
45{
22f3fd98 46 StoreEntry *entry;
47 char *action;
63259c34 48 char *user_name;
22f3fd98 49 char *passwd;
62e76326 50}
51
52cachemgrStateData;
22f3fd98 53
62e76326 54typedef struct _action_table
55{
22f3fd98 56 char *action;
57 char *desc;
58 OBJH *handler;
62e76326 59
60 struct
61 {
62
63unsigned int pw_req:
64 1;
65
66unsigned int atomic:
67 1;
68 }
69
70 flags;
71
22f3fd98 72 struct _action_table *next;
62e76326 73}
74
75action_table;
22f3fd98 76
2ac76861 77static action_table *cachemgrFindAction(const char *action);
63259c34 78static cachemgrStateData *cachemgrParseUrl(const char *url);
190154cf 79static void cachemgrParseHeaders(cachemgrStateData * mgr, const HttpRequest * request);
22f3fd98 80static int cachemgrCheckPassword(cachemgrStateData *);
2ac76861 81static void cachemgrStateFree(cachemgrStateData * mgr);
22f3fd98 82static char *cachemgrPasswdGet(cachemgr_passwd *, const char *);
2ac76861 83static const char *cachemgrActionProtection(const action_table * at);
22f3fd98 84static OBJH cachemgrShutdown;
85static OBJH cachemgrMenu;
d20b1cd0 86static OBJH cachemgrOfflineToggle;
22f3fd98 87
88action_table *ActionTable = NULL;
89
90void
1da3b90b 91cachemgrRegister(const char *action, const char *desc, OBJH * handler, int pw_req_flag, int atomic)
22f3fd98 92{
93 action_table *a;
94 action_table **A;
62e76326 95
e45867bd 96 if (cachemgrFindAction(action) != NULL) {
62e76326 97 debug(16, 3) ("cachemgrRegister: Duplicate '%s'\n", action);
98 return;
e45867bd 99 }
62e76326 100
528b2c61 101 assert (strstr (" ", action) == NULL);
e6ccf245 102 a = (action_table *)xcalloc(1, sizeof(action_table));
22f3fd98 103 a->action = xstrdup(action);
104 a->desc = xstrdup(desc);
105 a->handler = handler;
1da3b90b 106 a->flags.pw_req = pw_req_flag;
107 a->flags.atomic = atomic;
62e76326 108
109 for (A = &ActionTable; *A; A = &(*A)->next)
110
111 ;
22f3fd98 112 *A = a;
62e76326 113
2ac76861 114 debug(16, 3) ("cachemgrRegister: registered %s\n", action);
22f3fd98 115}
116
117static action_table *
118cachemgrFindAction(const char *action)
119{
120 action_table *a;
62e76326 121
22f3fd98 122 for (a = ActionTable; a != NULL; a = a->next) {
62e76326 123 if (0 == strcmp(a->action, action))
124 return a;
22f3fd98 125 }
62e76326 126
22f3fd98 127 return NULL;
128}
129
130static cachemgrStateData *
63259c34 131cachemgrParseUrl(const char *url)
22f3fd98 132{
133 int t;
134 LOCAL_ARRAY(char, host, MAX_URL);
135 LOCAL_ARRAY(char, request, MAX_URL);
136 LOCAL_ARRAY(char, password, MAX_URL);
137 action_table *a;
138 cachemgrStateData *mgr = NULL;
7395afb8 139 const char *prot;
22f3fd98 140 t = sscanf(url, "cache_object://%[^/]/%[^@]@%s", host, request, password);
62e76326 141
22f3fd98 142 if (t < 2) {
62e76326 143 xstrncpy(request, "menu", MAX_URL);
cd377065 144#ifdef _SQUID_OS2_
62e76326 145 /*
146 * emx's sscanf insists of returning 2 because it sets request
147 * to null
148 */
cd377065 149 } else if (request[0] == '\0') {
62e76326 150 xstrncpy(request, "menu", MAX_URL);
cd377065 151#endif
62e76326 152
22f3fd98 153 } else if ((a = cachemgrFindAction(request)) == NULL) {
62e76326 154 debug(16, 1) ("cachemgrParseUrl: action '%s' not found\n", request);
155 return NULL;
7395afb8 156 } else {
62e76326 157 prot = cachemgrActionProtection(a);
158
159 if (!strcmp(prot, "disabled") || !strcmp(prot, "hidden")) {
160 debug(16, 1) ("cachemgrParseUrl: action '%s' is %s\n", request, prot);
161 return NULL;
162 }
22f3fd98 163 }
62e76326 164
63259c34 165 /* set absent entries to NULL so we can test if they are present later */
e6ccf245 166 mgr = (cachemgrStateData *)xcalloc(1, sizeof(cachemgrStateData));
62e76326 167
63259c34 168 mgr->user_name = NULL;
62e76326 169
63259c34 170 mgr->passwd = t == 3 ? xstrdup(password) : NULL;
62e76326 171
22f3fd98 172 mgr->action = xstrdup(request);
62e76326 173
22f3fd98 174 return mgr;
175}
176
63259c34 177static void
190154cf 178cachemgrParseHeaders(cachemgrStateData * mgr, const HttpRequest * request)
63259c34 179{
2ac76861 180 const char *basic_cookie; /* base 64 _decoded_ user:passwd pair */
63259c34 181 const char *passwd_del;
182 assert(mgr && request);
99edd1c3 183 basic_cookie = httpHeaderGetAuth(&request->header, HDR_AUTHORIZATION, "Basic");
62e76326 184
99edd1c3 185 if (!basic_cookie)
62e76326 186 return;
187
63259c34 188 if (!(passwd_del = strchr(basic_cookie, ':'))) {
62e76326 189 debug(16, 1) ("cachemgrParseHeaders: unknown basic_cookie format '%s'\n", basic_cookie);
190 return;
63259c34 191 }
62e76326 192
63259c34 193 /* found user:password pair, reset old values */
194 safe_free(mgr->user_name);
62e76326 195
63259c34 196 safe_free(mgr->passwd);
62e76326 197
2ac76861 198 mgr->user_name = xstrdup(basic_cookie);
62e76326 199
63259c34 200 mgr->user_name[passwd_del - basic_cookie] = '\0';
62e76326 201
2ac76861 202 mgr->passwd = xstrdup(passwd_del + 1);
62e76326 203
63259c34 204 /* warning: this prints decoded password which maybe not what you want to do @?@ @?@ */
2ac76861 205 debug(16, 9) ("cachemgrParseHeaders: got user: '%s' passwd: '%s'\n", mgr->user_name, mgr->passwd);
63259c34 206}
207
22f3fd98 208/*
209 * return 0 if mgr->password is good
210 */
211static int
212cachemgrCheckPassword(cachemgrStateData * mgr)
213{
214 char *pwd = cachemgrPasswdGet(Config.passwd_list, mgr->action);
215 action_table *a = cachemgrFindAction(mgr->action);
216 assert(a != NULL);
62e76326 217
22f3fd98 218 if (pwd == NULL)
62e76326 219 return a->flags.pw_req;
220
22f3fd98 221 if (strcmp(pwd, "disable") == 0)
62e76326 222 return 1;
223
22f3fd98 224 if (strcmp(pwd, "none") == 0)
62e76326 225 return 0;
226
63259c34 227 if (!mgr->passwd)
62e76326 228 return 1;
229
22f3fd98 230 return strcmp(pwd, mgr->passwd);
231}
232
233static void
2ac76861 234cachemgrStateFree(cachemgrStateData * mgr)
22f3fd98 235{
2ac76861 236 safe_free(mgr->action);
237 safe_free(mgr->user_name);
238 safe_free(mgr->passwd);
b771e69f 239 storeUnlockObject(mgr->entry);
2ac76861 240 xfree(mgr);
22f3fd98 241}
242
243void
190154cf 244cachemgrStart(int fd, HttpRequest * request, StoreEntry * entry)
22f3fd98 245{
246 cachemgrStateData *mgr = NULL;
247 ErrorState *err = NULL;
22f3fd98 248 action_table *a;
249 debug(16, 3) ("objectcacheStart: '%s'\n", storeUrl(entry));
62e76326 250
63259c34 251 if ((mgr = cachemgrParseUrl(storeUrl(entry))) == NULL) {
62e76326 252 err = errorCon(ERR_INVALID_URL, HTTP_NOT_FOUND);
253 err->url = xstrdup(storeUrl(entry));
6dd9f4bd 254 err->request = HTTPMSGLOCK(request);
62e76326 255 errorAppendEntry(entry, err);
256 entry->expires = squid_curtime;
257 return;
22f3fd98 258 }
62e76326 259
22f3fd98 260 mgr->entry = entry;
b771e69f 261 storeLockObject(entry);
22f3fd98 262 entry->expires = squid_curtime;
63259c34 263 debug(16, 5) ("CACHEMGR: %s requesting '%s'\n",
62e76326 264 fd_table[fd].ipaddr, mgr->action);
63259c34 265 /* get additional info from request headers */
266 cachemgrParseHeaders(mgr, request);
22f3fd98 267 /* Check password */
62e76326 268
22f3fd98 269 if (cachemgrCheckPassword(mgr) != 0) {
62e76326 270 /* build error message */
271 ErrorState *err;
272 HttpReply *rep;
273 err = errorCon(ERR_CACHE_MGR_ACCESS_DENIED, HTTP_UNAUTHORIZED);
274 /* warn if user specified incorrect password */
275
276 if (mgr->passwd)
277 debug(16, 1) ("CACHEMGR: %s@%s: incorrect password for '%s'\n",
278 mgr->user_name ? mgr->user_name : "<unknown>",
279 fd_table[fd].ipaddr, mgr->action);
280 else
281 debug(16, 1) ("CACHEMGR: %s@%s: password needed for '%s'\n",
282 mgr->user_name ? mgr->user_name : "<unknown>",
283 fd_table[fd].ipaddr, mgr->action);
284
6dd9f4bd 285 err->request = HTTPMSGLOCK(request);
62e76326 286
287 rep = errorBuildReply(err);
288
289 errorStateFree(err);
290
291 /*
292 * add Authenticate header, use 'action' as a realm because
293 * password depends on action
294 */
295 httpHeaderPutAuth(&rep->header, "Basic", mgr->action);
296
297 /* store the reply */
4a56ee8d 298 storeEntryReplaceObject(entry, rep);
62e76326 299
300 entry->expires = squid_curtime;
301
302 entry->complete();
303
304 cachemgrStateFree(mgr);
305
306 return;
22f3fd98 307 }
62e76326 308
b771e69f 309 debug(16, 1) ("CACHEMGR: %s@%s requesting '%s'\n",
62e76326 310 mgr->user_name ? mgr->user_name : "<unknown>",
311 fd_table[fd].ipaddr, mgr->action);
22f3fd98 312 /* retrieve object requested */
313 a = cachemgrFindAction(mgr->action);
314 assert(a != NULL);
62e76326 315
b66315e4 316 storeBuffer(entry);
62e76326 317
cb69b4c7 318 {
450e0c10 319 HttpVersion version(1,0);
06a5ae20 320 HttpReply *rep = new HttpReply;
321 rep->setHeaders(version,
322 HTTP_OK,
323 NULL,
324 "text/plain",
325 -1, /* C-Len */
326 squid_curtime, /* LMT */
327 squid_curtime);
4a56ee8d 328 storeEntryReplaceObject(entry, rep);
cb69b4c7 329 }
62e76326 330
22f3fd98 331 a->handler(entry);
62e76326 332
b66315e4 333 storeBufferFlush(entry);
334
335 if (a->flags.atomic)
62e76326 336 entry->complete();
62e76326 337
22f3fd98 338 cachemgrStateFree(mgr);
339}
340
341static void
342cachemgrShutdown(StoreEntry * entryunused)
343{
344 debug(16, 0) ("Shutdown by command.\n");
345 shut_down(0);
346}
347
d20b1cd0 348static void
349cachemgrOfflineToggle(StoreEntry * sentry)
350{
351 Config.onoff.offline = !Config.onoff.offline;
352 debug(16, 0) ("offline_mode now %s.\n",
62e76326 353 Config.onoff.offline ? "ON" : "OFF");
d20b1cd0 354 storeAppendPrintf(sentry, "offline_mode is now %s\n",
62e76326 355 Config.onoff.offline ? "ON" : "OFF");
d20b1cd0 356}
357
7395afb8 358static const char *
2ac76861 359cachemgrActionProtection(const action_table * at)
7395afb8 360{
361 char *pwd;
362 assert(at);
363 pwd = cachemgrPasswdGet(Config.passwd_list, at->action);
62e76326 364
7395afb8 365 if (!pwd)
62e76326 366 return at->flags.pw_req ? "hidden" : "public";
367
7395afb8 368 if (!strcmp(pwd, "disable"))
62e76326 369 return "disabled";
370
7395afb8 371 if (strcmp(pwd, "none") == 0)
62e76326 372 return "public";
373
7395afb8 374 return "protected";
375}
376
22f3fd98 377static void
2ac76861 378cachemgrMenu(StoreEntry * sentry)
22f3fd98 379{
7395afb8 380 action_table *a;
62e76326 381
7395afb8 382 for (a = ActionTable; a != NULL; a = a->next) {
62e76326 383 storeAppendPrintf(sentry, " %-22s\t%s\t%s\n",
384 a->action, a->desc, cachemgrActionProtection(a));
7395afb8 385 }
22f3fd98 386}
387
388static char *
389cachemgrPasswdGet(cachemgr_passwd * a, const char *action)
390{
391 wordlist *w;
62e76326 392
22f3fd98 393 while (a != NULL) {
62e76326 394 for (w = a->actions; w != NULL; w = w->next) {
395 if (0 == strcmp(w->key, action))
396 return a->passwd;
397
398 if (0 == strcmp(w->key, "all"))
399 return a->passwd;
400 }
401
402 a = a->next;
22f3fd98 403 }
62e76326 404
22f3fd98 405 return NULL;
406}
407
408void
409cachemgrInit(void)
410{
411 cachemgrRegister("menu",
62e76326 412 "This Cachemanager Menu",
413 cachemgrMenu, 0, 1);
22f3fd98 414 cachemgrRegister("shutdown",
62e76326 415 "Shut Down the Squid Process",
416 cachemgrShutdown, 1, 1);
d20b1cd0 417 cachemgrRegister("offline_toggle",
62e76326 418 "Toggle offline_mode setting",
419 cachemgrOfflineToggle, 1, 1);
22f3fd98 420}