]> git.ipfire.org Git - thirdparty/squid.git/blame - src/cache_manager.cc
Moved the ActionTable to a Vector. Still Kludgy, but getting better.
[thirdparty/squid.git] / src / cache_manager.cc
CommitLineData
22f3fd98 1
2/*
63be0a78 3 * $Id: cache_manager.cc,v 1.49 2008/02/26 21:49:34 amosjeffries 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
62ee09ca 36#include "CacheManager.h"
aa839030 37#include "errorpage.h"
528b2c61 38#include "HttpReply.h"
39#include "HttpRequest.h"
e6ccf245 40#include "Store.h"
528b2c61 41#include "fde.h"
985c86bc 42#include "SquidTime.h"
d295d770 43#include "wordlist.h"
22f3fd98 44
63be0a78 45/**
46 \defgroup CacheManagerInternal Cache Manager Internals
47 \ingroup CacheManagerAPI
48 */
49
50/// \ingroup CacheManagerInternal
22f3fd98 51#define MGR_PASSWD_SZ 128
52
c83f0bd5 53
22f3fd98 54
63be0a78 55/// \ingroup CacheManagerInternal
03c4599f 56CacheManagerActionList *ActionsList = NULL;
62ee09ca 57
58CacheManager::CacheManager()
59{
03c4599f
K
60 if (ActionsList != NULL)
61 delete(ActionsList); //TODO: Laaazy. Will be moved to class member
62 ActionsList = new CacheManagerActionList;
c83f0bd5 63 registerAction("menu", "This Cachemanager Menu", MenuCommand, 0, 1);
62ee09ca 64 registerAction("shutdown",
65 "Shut Down the Squid Process",
c83f0bd5 66 ShutdownCommand, 1, 1);
757a2291
GS
67 registerAction("reconfigure",
68 "Reconfigure the Squid Process",
c83f0bd5 69 ReconfigureCommand, 1, 1);
62ee09ca 70 registerAction("offline_toggle",
71 "Toggle offline_mode setting",
c83f0bd5 72 OfflineToggleCommand, 1, 1);
62ee09ca 73}
22f3fd98 74
75void
62ee09ca 76CacheManager::registerAction(char const * action, char const * desc, OBJH * handler, int pw_req_flag, int atomic)
22f3fd98 77{
c83f0bd5 78 CacheManagerActionLegacy *a;
62e76326 79
62ee09ca 80 if (findAction(action) != NULL) {
03c4599f 81 debugs(16, 2, "CacheManager::registerAction: Duplicate '" << action << "'. Skipping.");
62e76326 82 return;
e45867bd 83 }
62e76326 84
528b2c61 85 assert (strstr (" ", action) == NULL);
2f53e904 86 a = new CacheManagerActionLegacy(action,desc,pw_req_flag,atomic,handler);
62e76326 87
03c4599f 88 *ActionsList += a;
62e76326 89
62ee09ca 90 debugs(16, 3, "CacheManager::registerAction: registered " << action);
91}
92
c83f0bd5 93/// \ingroup CacheManagerInternal
62ee09ca 94CacheManagerAction *
95CacheManager::findAction(char const * action)
22f3fd98 96{
03c4599f
K
97 CacheManagerActionList::iterator a;
98
99 debugs(16, 5, "CacheManager::findAction: looking for action " << action);
100 for ( a = ActionsList->begin(); a != ActionsList->end(); a++) {
101 //debugs(16, 6, " checking against '" << (*a)->action << "'");
102 if (0 == strcmp((*a)->action, action)) {
103 debugs(16, 6, " found");
104 return *a;
105 }
22f3fd98 106 }
62e76326 107
03c4599f 108 debugs(16, 6, "Action not found.");
22f3fd98 109 return NULL;
110}
111
63be0a78 112/// \ingroup CacheManagerInternal
c83f0bd5
K
113cachemgrStateData *
114CacheManager::ParseUrl(const char *url)
22f3fd98 115{
116 int t;
117 LOCAL_ARRAY(char, host, MAX_URL);
118 LOCAL_ARRAY(char, request, MAX_URL);
119 LOCAL_ARRAY(char, password, MAX_URL);
62ee09ca 120 CacheManagerAction *a;
22f3fd98 121 cachemgrStateData *mgr = NULL;
7395afb8 122 const char *prot;
22f3fd98 123 t = sscanf(url, "cache_object://%[^/]/%[^@]@%s", host, request, password);
62e76326 124
22f3fd98 125 if (t < 2) {
62e76326 126 xstrncpy(request, "menu", MAX_URL);
cd377065 127#ifdef _SQUID_OS2_
62e76326 128 /*
129 * emx's sscanf insists of returning 2 because it sets request
130 * to null
131 */
cd377065 132 } else if (request[0] == '\0') {
62e76326 133 xstrncpy(request, "menu", MAX_URL);
cd377065 134#endif
62e76326 135
c83f0bd5
K
136 } else if ((a = findAction(request)) == NULL) {
137 debugs(16, 1, "CacheManager::ParseUrl: action '" << request << "' not found");
62e76326 138 return NULL;
7395afb8 139 } else {
c83f0bd5 140 prot = ActionProtection(a);
62e76326 141
142 if (!strcmp(prot, "disabled") || !strcmp(prot, "hidden")) {
c83f0bd5 143 debugs(16, 1, "CacheManager::ParseUrl: action '" << request << "' is " << prot);
62e76326 144 return NULL;
145 }
22f3fd98 146 }
62e76326 147
63259c34 148 /* set absent entries to NULL so we can test if they are present later */
e6ccf245 149 mgr = (cachemgrStateData *)xcalloc(1, sizeof(cachemgrStateData));
62e76326 150
63259c34 151 mgr->user_name = NULL;
62e76326 152
63259c34 153 mgr->passwd = t == 3 ? xstrdup(password) : NULL;
62e76326 154
22f3fd98 155 mgr->action = xstrdup(request);
62e76326 156
22f3fd98 157 return mgr;
158}
159
63be0a78 160/// \ingroup CacheManagerInternal
c83f0bd5
K
161void
162CacheManager::ParseHeaders(cachemgrStateData * mgr, const HttpRequest * request)
63259c34 163{
2ac76861 164 const char *basic_cookie; /* base 64 _decoded_ user:passwd pair */
63259c34 165 const char *passwd_del;
166 assert(mgr && request);
a9925b40 167 basic_cookie = request->header.getAuth(HDR_AUTHORIZATION, "Basic");
62e76326 168
99edd1c3 169 if (!basic_cookie)
62e76326 170 return;
171
63259c34 172 if (!(passwd_del = strchr(basic_cookie, ':'))) {
c83f0bd5 173 debugs(16, 1, "CacheManager::ParseHeaders: unknown basic_cookie format '" << basic_cookie << "'");
62e76326 174 return;
63259c34 175 }
62e76326 176
63259c34 177 /* found user:password pair, reset old values */
178 safe_free(mgr->user_name);
62e76326 179
63259c34 180 safe_free(mgr->passwd);
62e76326 181
2ac76861 182 mgr->user_name = xstrdup(basic_cookie);
62e76326 183
63259c34 184 mgr->user_name[passwd_del - basic_cookie] = '\0';
62e76326 185
2ac76861 186 mgr->passwd = xstrdup(passwd_del + 1);
62e76326 187
63259c34 188 /* warning: this prints decoded password which maybe not what you want to do @?@ @?@ */
c83f0bd5 189 debugs(16, 9, "CacheManager::ParseHeaders: got user: '" << mgr->user_name << "' passwd: '" << mgr->passwd << "'");
63259c34 190}
191
63be0a78 192/**
193 \ingroup CacheManagerInternal
194 *
195 \retval 0 if mgr->password is good or "none"
196 \retval 1 if mgr->password is "disable"
197 \retval !0 if mgr->password does not match configured password
22f3fd98 198 */
c83f0bd5
K
199int
200CacheManager::CheckPassword(cachemgrStateData * mgr)
22f3fd98 201{
c83f0bd5
K
202 char *pwd = PasswdGet(Config.passwd_list, mgr->action);
203 CacheManagerAction *a = findAction(mgr->action);
03c4599f
K
204
205 debugs(16, 4, "CacheManager::CheckPassword for action " << mgr->action);
22f3fd98 206 assert(a != NULL);
62e76326 207
22f3fd98 208 if (pwd == NULL)
62e76326 209 return a->flags.pw_req;
210
22f3fd98 211 if (strcmp(pwd, "disable") == 0)
62e76326 212 return 1;
213
22f3fd98 214 if (strcmp(pwd, "none") == 0)
62e76326 215 return 0;
216
63259c34 217 if (!mgr->passwd)
62e76326 218 return 1;
219
22f3fd98 220 return strcmp(pwd, mgr->passwd);
221}
222
63be0a78 223/// \ingroup CacheManagerInternal
c83f0bd5
K
224void
225CacheManager::StateFree(cachemgrStateData * mgr)
22f3fd98 226{
2ac76861 227 safe_free(mgr->action);
228 safe_free(mgr->user_name);
229 safe_free(mgr->passwd);
97b5e68f 230 mgr->entry->unlock();
2ac76861 231 xfree(mgr);
22f3fd98 232}
233
63be0a78 234// API
22f3fd98 235void
c83f0bd5 236CacheManager::Start(int fd, HttpRequest * request, StoreEntry * entry)
22f3fd98 237{
238 cachemgrStateData *mgr = NULL;
239 ErrorState *err = NULL;
62ee09ca 240 CacheManagerAction *a;
bf8fe701 241 debugs(16, 3, "objectcacheStart: '" << entry->url() << "'" );
62e76326 242
c83f0bd5 243 if ((mgr = ParseUrl(entry->url())) == NULL) {
2cc81f1f 244 err = errorCon(ERR_INVALID_URL, HTTP_NOT_FOUND, request);
3900307b 245 err->url = xstrdup(entry->url());
62e76326 246 errorAppendEntry(entry, err);
247 entry->expires = squid_curtime;
248 return;
22f3fd98 249 }
62e76326 250
22f3fd98 251 mgr->entry = entry;
34266cde 252
3d0ac046 253 entry->lock();
22f3fd98 254 entry->expires = squid_curtime;
34266cde 255
bf8fe701 256 debugs(16, 5, "CACHEMGR: " << fd_table[fd].ipaddr << " requesting '" << mgr->action << "'");
34266cde 257
63259c34 258 /* get additional info from request headers */
c83f0bd5 259 ParseHeaders(mgr, request);
34266cde 260
22f3fd98 261 /* Check password */
62e76326 262
c83f0bd5 263 if (CheckPassword(mgr) != 0) {
62e76326 264 /* build error message */
265 ErrorState *err;
266 HttpReply *rep;
2cc81f1f 267 err = errorCon(ERR_CACHE_MGR_ACCESS_DENIED, HTTP_UNAUTHORIZED, request);
62e76326 268 /* warn if user specified incorrect password */
269
270 if (mgr->passwd)
bf8fe701 271 debugs(16, 1, "CACHEMGR: " <<
272 (mgr->user_name ? mgr->user_name : "<unknown>") << "@" <<
273 fd_table[fd].ipaddr << ": incorrect password for '" <<
274 mgr->action << "'" );
62e76326 275 else
bf8fe701 276 debugs(16, 1, "CACHEMGR: " <<
277 (mgr->user_name ? mgr->user_name : "<unknown>") << "@" <<
278 fd_table[fd].ipaddr << ": password needed for '" <<
279 mgr->action << "'" );
62e76326 280
62e76326 281 rep = errorBuildReply(err);
282
283 errorStateFree(err);
284
285 /*
286 * add Authenticate header, use 'action' as a realm because
287 * password depends on action
288 */
a9925b40 289 rep->header.putAuth("Basic", mgr->action);
62e76326 290
291 /* store the reply */
db237875 292 entry->replaceHttpReply(rep);
62e76326 293
294 entry->expires = squid_curtime;
295
296 entry->complete();
297
c83f0bd5 298 StateFree(mgr);
62e76326 299
300 return;
22f3fd98 301 }
62e76326 302
bf8fe701 303 debugs(16, 1, "CACHEMGR: " <<
304 (mgr->user_name ? mgr->user_name : "<unknown>") << "@" <<
305 fd_table[fd].ipaddr << " requesting '" <<
306 mgr->action << "'" );
22f3fd98 307 /* retrieve object requested */
c83f0bd5 308 a = findAction(mgr->action);
22f3fd98 309 assert(a != NULL);
62e76326 310
3900307b 311 entry->buffer();
62e76326 312
cb69b4c7 313 {
450e0c10 314 HttpVersion version(1,0);
06a5ae20 315 HttpReply *rep = new HttpReply;
316 rep->setHeaders(version,
317 HTTP_OK,
318 NULL,
319 "text/plain",
320 -1, /* C-Len */
321 squid_curtime, /* LMT */
322 squid_curtime);
db237875 323 entry->replaceHttpReply(rep);
cb69b4c7 324 }
62e76326 325
c83f0bd5 326 a->run(entry);
62e76326 327
3900307b 328 entry->flush();
b66315e4 329
330 if (a->flags.atomic)
62e76326 331 entry->complete();
62e76326 332
c83f0bd5 333 StateFree(mgr);
22f3fd98 334}
335
63be0a78 336/// \ingroup CacheManagerInternal
c83f0bd5
K
337void
338CacheManager::ShutdownCommand(StoreEntry *unused)
339{
340 debugs(16, 0, "Shutdown by command.");
341 shut_down(0);
342}
343void CacheManagerShutdownAction::run(StoreEntry *sentry)
22f3fd98 344{
bf8fe701 345 debugs(16, 0, "Shutdown by command.");
22f3fd98 346 shut_down(0);
347}
348
757a2291 349/// \ingroup CacheManagerInternal
c83f0bd5
K
350void
351CacheManager::ReconfigureCommand(StoreEntry * sentry)
757a2291
GS
352{
353 debug(16, 0) ("Reconfigure by command.\n");
354 storeAppendPrintf(sentry, "Reconfiguring Squid Process ....");
355 reconfigure(SIGHUP);
356}
357
63be0a78 358/// \ingroup CacheManagerInternal
c83f0bd5
K
359void
360CacheManager::OfflineToggleCommand(StoreEntry * sentry)
d20b1cd0 361{
362 Config.onoff.offline = !Config.onoff.offline;
bf8fe701 363 debugs(16, 0, "offline_mode now " << (Config.onoff.offline ? "ON" : "OFF") << ".");
364
d20b1cd0 365 storeAppendPrintf(sentry, "offline_mode is now %s\n",
62e76326 366 Config.onoff.offline ? "ON" : "OFF");
d20b1cd0 367}
368
63be0a78 369/// \ingroup CacheManagerInternal
c83f0bd5
K
370const char *
371CacheManager::ActionProtection(const CacheManagerAction * at)
7395afb8 372{
373 char *pwd;
374 assert(at);
c83f0bd5 375 pwd = PasswdGet(Config.passwd_list, at->action);
62e76326 376
7395afb8 377 if (!pwd)
62e76326 378 return at->flags.pw_req ? "hidden" : "public";
379
7395afb8 380 if (!strcmp(pwd, "disable"))
62e76326 381 return "disabled";
382
7395afb8 383 if (strcmp(pwd, "none") == 0)
62e76326 384 return "public";
385
7395afb8 386 return "protected";
387}
388
63be0a78 389/// \ingroup CacheManagerInternal
c83f0bd5
K
390void
391CacheManager::MenuCommand(StoreEntry * sentry)
22f3fd98 392{
03c4599f 393 CacheManagerActionList::iterator a;
62e76326 394
03c4599f
K
395 debugs(16, 4, "CacheManager::MenuCommand invoked");
396 for (a = ActionsList->begin(); a != ActionsList->end(); ++a) {
397 debugs(16, 5, " showing action " << (*a)->action);
e1a88700 398 storeAppendPrintf(sentry, " %-22s\t%-32s\t%s\n",
03c4599f 399 (*a)->action, (*a)->desc, CacheManager::GetInstance()->ActionProtection(*a));
7395afb8 400 }
22f3fd98 401}
402
63be0a78 403/// \ingroup CacheManagerInternal
c83f0bd5
K
404char *
405CacheManager::PasswdGet(cachemgr_passwd * a, const char *action)
22f3fd98 406{
407 wordlist *w;
62e76326 408
22f3fd98 409 while (a != NULL) {
62e76326 410 for (w = a->actions; w != NULL; w = w->next) {
411 if (0 == strcmp(w->key, action))
412 return a->passwd;
413
414 if (0 == strcmp(w->key, "all"))
415 return a->passwd;
416 }
417
418 a = a->next;
22f3fd98 419 }
62e76326 420
22f3fd98 421 return NULL;
422}
c83f0bd5
K
423
424CacheManager* CacheManager::instance=0;
425
426CacheManager*
427CacheManager::GetInstance() {
03c4599f
K
428 if (instance == 0) {
429 debugs(16, 6, "CacheManager::GetInstance: starting cachemanager up");
430 instance = new CacheManager;
431 }
432 return instance;
c83f0bd5
K
433}
434
435
436void CacheManagerActionLegacy::run(StoreEntry *sentry)
437{
438 handler(sentry);
439}
440
2f53e904
K
441CacheManagerAction::CacheManagerAction(char const *anAction, char const *aDesc, unsigned int isPwReq, unsigned int isAtomic)
442{
443 flags.pw_req = isPwReq;
444 flags.atomic = isAtomic;
445 action = xstrdup (anAction);
446 desc = xstrdup (aDesc);
447}
448CacheManagerAction::~CacheManagerAction() {
449 xfree(action);
450 xfree(desc);
451}
452
453CacheManagerActionLegacy::CacheManagerActionLegacy(char const *anAction, char const *aDesc, unsigned int isPwReq, unsigned int isAtomic, OBJH *aHandler) : CacheManagerAction(anAction, aDesc, isPwReq, isAtomic), handler(aHandler)
454{
455}