3 * $Id: cache_manager.cc,v 1.30 2003/08/10 11:00:42 robertc Exp $
5 * DEBUG: section 16 Cache Manager Objects
6 * AUTHOR: Duane Wessels
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
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.
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.
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.
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
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
37 #include "HttpReply.h"
38 #include "HttpRequest.h"
42 #define MGR_PASSWD_SZ 128
54 typedef struct _action_table
72 struct _action_table
*next
;
77 static action_table
*cachemgrFindAction(const char *action
);
78 static cachemgrStateData
*cachemgrParseUrl(const char *url
);
79 static void cachemgrParseHeaders(cachemgrStateData
* mgr
, const HttpRequest
* request
);
80 static int cachemgrCheckPassword(cachemgrStateData
*);
81 static void cachemgrStateFree(cachemgrStateData
* mgr
);
82 static char *cachemgrPasswdGet(cachemgr_passwd
*, const char *);
83 static const char *cachemgrActionProtection(const action_table
* at
);
84 static OBJH cachemgrShutdown
;
85 static OBJH cachemgrMenu
;
86 static OBJH cachemgrOfflineToggle
;
88 action_table
*ActionTable
= NULL
;
91 cachemgrRegister(const char *action
, const char *desc
, OBJH
* handler
, int pw_req_flag
, int atomic
)
96 if (cachemgrFindAction(action
) != NULL
) {
97 debug(16, 3) ("cachemgrRegister: Duplicate '%s'\n", action
);
101 assert (strstr (" ", action
) == NULL
);
102 a
= (action_table
*)xcalloc(1, sizeof(action_table
));
103 a
->action
= xstrdup(action
);
104 a
->desc
= xstrdup(desc
);
105 a
->handler
= handler
;
106 a
->flags
.pw_req
= pw_req_flag
;
107 a
->flags
.atomic
= atomic
;
109 for (A
= &ActionTable
; *A
; A
= &(*A
)->next
)
114 debug(16, 3) ("cachemgrRegister: registered %s\n", action
);
117 static action_table
*
118 cachemgrFindAction(const char *action
)
122 for (a
= ActionTable
; a
!= NULL
; a
= a
->next
) {
123 if (0 == strcmp(a
->action
, action
))
130 static cachemgrStateData
*
131 cachemgrParseUrl(const char *url
)
134 LOCAL_ARRAY(char, host
, MAX_URL
);
135 LOCAL_ARRAY(char, request
, MAX_URL
);
136 LOCAL_ARRAY(char, password
, MAX_URL
);
138 cachemgrStateData
*mgr
= NULL
;
140 t
= sscanf(url
, "cache_object://%[^/]/%[^@]@%s", host
, request
, password
);
143 xstrncpy(request
, "menu", MAX_URL
);
146 * emx's sscanf insists of returning 2 because it sets request
149 } else if (request
[0] == '\0') {
150 xstrncpy(request
, "menu", MAX_URL
);
153 } else if ((a
= cachemgrFindAction(request
)) == NULL
) {
154 debug(16, 1) ("cachemgrParseUrl: action '%s' not found\n", request
);
157 prot
= cachemgrActionProtection(a
);
159 if (!strcmp(prot
, "disabled") || !strcmp(prot
, "hidden")) {
160 debug(16, 1) ("cachemgrParseUrl: action '%s' is %s\n", request
, prot
);
165 /* set absent entries to NULL so we can test if they are present later */
166 mgr
= (cachemgrStateData
*)xcalloc(1, sizeof(cachemgrStateData
));
168 mgr
->user_name
= NULL
;
170 mgr
->passwd
= t
== 3 ? xstrdup(password
) : NULL
;
172 mgr
->action
= xstrdup(request
);
178 cachemgrParseHeaders(cachemgrStateData
* mgr
, const HttpRequest
* request
)
180 const char *basic_cookie
; /* base 64 _decoded_ user:passwd pair */
181 const char *passwd_del
;
182 assert(mgr
&& request
);
183 basic_cookie
= httpHeaderGetAuth(&request
->header
, HDR_AUTHORIZATION
, "Basic");
188 if (!(passwd_del
= strchr(basic_cookie
, ':'))) {
189 debug(16, 1) ("cachemgrParseHeaders: unknown basic_cookie format '%s'\n", basic_cookie
);
193 /* found user:password pair, reset old values */
194 safe_free(mgr
->user_name
);
196 safe_free(mgr
->passwd
);
198 mgr
->user_name
= xstrdup(basic_cookie
);
200 mgr
->user_name
[passwd_del
- basic_cookie
] = '\0';
202 mgr
->passwd
= xstrdup(passwd_del
+ 1);
204 /* warning: this prints decoded password which maybe not what you want to do @?@ @?@ */
205 debug(16, 9) ("cachemgrParseHeaders: got user: '%s' passwd: '%s'\n", mgr
->user_name
, mgr
->passwd
);
209 * return 0 if mgr->password is good
212 cachemgrCheckPassword(cachemgrStateData
* mgr
)
214 char *pwd
= cachemgrPasswdGet(Config
.passwd_list
, mgr
->action
);
215 action_table
*a
= cachemgrFindAction(mgr
->action
);
219 return a
->flags
.pw_req
;
221 if (strcmp(pwd
, "disable") == 0)
224 if (strcmp(pwd
, "none") == 0)
230 return strcmp(pwd
, mgr
->passwd
);
234 cachemgrStateFree(cachemgrStateData
* mgr
)
236 safe_free(mgr
->action
);
237 safe_free(mgr
->user_name
);
238 safe_free(mgr
->passwd
);
239 storeUnlockObject(mgr
->entry
);
244 cachemgrStart(int fd
, HttpRequest
* request
, StoreEntry
* entry
)
246 cachemgrStateData
*mgr
= NULL
;
247 ErrorState
*err
= NULL
;
249 debug(16, 3) ("objectcacheStart: '%s'\n", storeUrl(entry
));
251 if ((mgr
= cachemgrParseUrl(storeUrl(entry
))) == NULL
) {
252 err
= errorCon(ERR_INVALID_URL
, HTTP_NOT_FOUND
);
253 err
->url
= xstrdup(storeUrl(entry
));
254 errorAppendEntry(entry
, err
);
255 entry
->expires
= squid_curtime
;
260 storeLockObject(entry
);
261 entry
->expires
= squid_curtime
;
262 debug(16, 5) ("CACHEMGR: %s requesting '%s'\n",
263 fd_table
[fd
].ipaddr
, mgr
->action
);
264 /* get additional info from request headers */
265 cachemgrParseHeaders(mgr
, request
);
268 if (cachemgrCheckPassword(mgr
) != 0) {
269 /* build error message */
272 err
= errorCon(ERR_CACHE_MGR_ACCESS_DENIED
, HTTP_UNAUTHORIZED
);
273 /* warn if user specified incorrect password */
276 debug(16, 1) ("CACHEMGR: %s@%s: incorrect password for '%s'\n",
277 mgr
->user_name
? mgr
->user_name
: "<unknown>",
278 fd_table
[fd
].ipaddr
, mgr
->action
);
280 debug(16, 1) ("CACHEMGR: %s@%s: password needed for '%s'\n",
281 mgr
->user_name
? mgr
->user_name
: "<unknown>",
282 fd_table
[fd
].ipaddr
, mgr
->action
);
284 err
->request
= requestLink(request
);
286 rep
= errorBuildReply(err
);
291 * add Authenticate header, use 'action' as a realm because
292 * password depends on action
294 httpHeaderPutAuth(&rep
->header
, "Basic", mgr
->action
);
296 /* store the reply */
297 httpReplySwapOut(rep
, entry
);
299 entry
->expires
= squid_curtime
;
303 cachemgrStateFree(mgr
);
308 debug(16, 1) ("CACHEMGR: %s@%s requesting '%s'\n",
309 mgr
->user_name
? mgr
->user_name
: "<unknown>",
310 fd_table
[fd
].ipaddr
, mgr
->action
);
311 /* retrieve object requested */
312 a
= cachemgrFindAction(mgr
->action
);
319 http_version_t version
;
320 HttpReply
*rep
= httpReplyCreate();
321 httpBuildVersion(&version
, 1, 0);
322 httpReplySetHeaders(rep
,
328 squid_curtime
, /* LMT */
330 httpReplySwapOut(rep
, entry
);
335 if (a
->flags
.atomic
) {
336 storeBufferFlush(entry
);
340 cachemgrStateFree(mgr
);
344 cachemgrShutdown(StoreEntry
* entryunused
)
346 debug(16, 0) ("Shutdown by command.\n");
351 cachemgrOfflineToggle(StoreEntry
* sentry
)
353 Config
.onoff
.offline
= !Config
.onoff
.offline
;
354 debug(16, 0) ("offline_mode now %s.\n",
355 Config
.onoff
.offline
? "ON" : "OFF");
356 storeAppendPrintf(sentry
, "offline_mode is now %s\n",
357 Config
.onoff
.offline
? "ON" : "OFF");
361 cachemgrActionProtection(const action_table
* at
)
365 pwd
= cachemgrPasswdGet(Config
.passwd_list
, at
->action
);
368 return at
->flags
.pw_req
? "hidden" : "public";
370 if (!strcmp(pwd
, "disable"))
373 if (strcmp(pwd
, "none") == 0)
380 cachemgrMenu(StoreEntry
* sentry
)
384 for (a
= ActionTable
; a
!= NULL
; a
= a
->next
) {
385 storeAppendPrintf(sentry
, " %-22s\t%s\t%s\n",
386 a
->action
, a
->desc
, cachemgrActionProtection(a
));
391 cachemgrPasswdGet(cachemgr_passwd
* a
, const char *action
)
396 for (w
= a
->actions
; w
!= NULL
; w
= w
->next
) {
397 if (0 == strcmp(w
->key
, action
))
400 if (0 == strcmp(w
->key
, "all"))
413 cachemgrRegister("menu",
414 "This Cachemanager Menu",
416 cachemgrRegister("shutdown",
417 "Shut Down the Squid Process",
418 cachemgrShutdown
, 1, 1);
419 cachemgrRegister("offline_toggle",
420 "Toggle offline_mode setting",
421 cachemgrOfflineToggle
, 1, 1);