3 * $Id: cache_manager.cc,v 1.25 2001/01/12 00:37:15 wessels 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.
38 #define MGR_PASSWD_SZ 128
47 typedef struct _action_table
{
55 struct _action_table
*next
;
58 static action_table
*cachemgrFindAction(const char *action
);
59 static cachemgrStateData
*cachemgrParseUrl(const char *url
);
60 static void cachemgrParseHeaders(cachemgrStateData
* mgr
, const request_t
* request
);
61 static int cachemgrCheckPassword(cachemgrStateData
*);
62 static void cachemgrStateFree(cachemgrStateData
* mgr
);
63 static char *cachemgrPasswdGet(cachemgr_passwd
*, const char *);
64 static const char *cachemgrActionProtection(const action_table
* at
);
65 static OBJH cachemgrShutdown
;
66 static OBJH cachemgrMenu
;
67 static OBJH cachemgrOfflineToggle
;
69 action_table
*ActionTable
= NULL
;
72 cachemgrRegister(const char *action
, const char *desc
, OBJH
* handler
, int pw_req_flag
, int atomic
)
76 if (cachemgrFindAction(action
) != NULL
) {
77 debug(16, 3) ("cachemgrRegister: Duplicate '%s'\n", action
);
80 a
= xcalloc(1, sizeof(action_table
));
81 a
->action
= xstrdup(action
);
82 a
->desc
= xstrdup(desc
);
84 a
->flags
.pw_req
= pw_req_flag
;
85 a
->flags
.atomic
= atomic
;
86 for (A
= &ActionTable
; *A
; A
= &(*A
)->next
);
88 debug(16, 3) ("cachemgrRegister: registered %s\n", action
);
92 cachemgrFindAction(const char *action
)
95 for (a
= ActionTable
; a
!= NULL
; a
= a
->next
) {
96 if (0 == strcmp(a
->action
, action
))
102 static cachemgrStateData
*
103 cachemgrParseUrl(const char *url
)
106 LOCAL_ARRAY(char, host
, MAX_URL
);
107 LOCAL_ARRAY(char, request
, MAX_URL
);
108 LOCAL_ARRAY(char, password
, MAX_URL
);
110 cachemgrStateData
*mgr
= NULL
;
112 t
= sscanf(url
, "cache_object://%[^/]/%[^@]@%s", host
, request
, password
);
114 xstrncpy(request
, "menu", MAX_URL
);
117 * emx's sscanf insists of returning 2 because it sets request
120 } else if (request
[0] == '\0') {
121 xstrncpy(request
, "menu", MAX_URL
);
123 } else if ((a
= cachemgrFindAction(request
)) == NULL
) {
124 debug(16, 1) ("cachemgrParseUrl: action '%s' not found\n", request
);
127 prot
= cachemgrActionProtection(a
);
128 if (!strcmp(prot
, "disabled") || !strcmp(prot
, "hidden")) {
129 debug(16, 1) ("cachemgrParseUrl: action '%s' is %s\n", request
, prot
);
133 /* set absent entries to NULL so we can test if they are present later */
134 mgr
= xcalloc(1, sizeof(cachemgrStateData
));
135 mgr
->user_name
= NULL
;
136 mgr
->passwd
= t
== 3 ? xstrdup(password
) : NULL
;
137 mgr
->action
= xstrdup(request
);
142 cachemgrParseHeaders(cachemgrStateData
* mgr
, const request_t
* request
)
144 const char *basic_cookie
; /* base 64 _decoded_ user:passwd pair */
145 const char *passwd_del
;
146 assert(mgr
&& request
);
147 basic_cookie
= httpHeaderGetAuth(&request
->header
, HDR_AUTHORIZATION
, "Basic");
150 if (!(passwd_del
= strchr(basic_cookie
, ':'))) {
151 debug(16, 1) ("cachemgrParseHeaders: unknown basic_cookie format '%s'\n", basic_cookie
);
154 /* found user:password pair, reset old values */
155 safe_free(mgr
->user_name
);
156 safe_free(mgr
->passwd
);
157 mgr
->user_name
= xstrdup(basic_cookie
);
158 mgr
->user_name
[passwd_del
- basic_cookie
] = '\0';
159 mgr
->passwd
= xstrdup(passwd_del
+ 1);
160 /* warning: this prints decoded password which maybe not what you want to do @?@ @?@ */
161 debug(16, 9) ("cachemgrParseHeaders: got user: '%s' passwd: '%s'\n", mgr
->user_name
, mgr
->passwd
);
165 * return 0 if mgr->password is good
168 cachemgrCheckPassword(cachemgrStateData
* mgr
)
170 char *pwd
= cachemgrPasswdGet(Config
.passwd_list
, mgr
->action
);
171 action_table
*a
= cachemgrFindAction(mgr
->action
);
174 return a
->flags
.pw_req
;
175 if (strcmp(pwd
, "disable") == 0)
177 if (strcmp(pwd
, "none") == 0)
181 return strcmp(pwd
, mgr
->passwd
);
185 cachemgrStateFree(cachemgrStateData
* mgr
)
187 safe_free(mgr
->action
);
188 safe_free(mgr
->user_name
);
189 safe_free(mgr
->passwd
);
190 storeUnlockObject(mgr
->entry
);
195 cachemgrStart(int fd
, request_t
* request
, StoreEntry
* entry
)
197 cachemgrStateData
*mgr
= NULL
;
198 ErrorState
*err
= NULL
;
200 debug(16, 3) ("objectcacheStart: '%s'\n", storeUrl(entry
));
201 if ((mgr
= cachemgrParseUrl(storeUrl(entry
))) == NULL
) {
202 err
= errorCon(ERR_INVALID_URL
, HTTP_NOT_FOUND
);
203 err
->url
= xstrdup(storeUrl(entry
));
204 errorAppendEntry(entry
, err
);
205 entry
->expires
= squid_curtime
;
209 storeLockObject(entry
);
210 entry
->expires
= squid_curtime
;
211 debug(16, 5) ("CACHEMGR: %s requesting '%s'\n",
212 fd_table
[fd
].ipaddr
, mgr
->action
);
213 /* get additional info from request headers */
214 cachemgrParseHeaders(mgr
, request
);
216 if (cachemgrCheckPassword(mgr
) != 0) {
217 /* build error message */
220 err
= errorCon(ERR_CACHE_MGR_ACCESS_DENIED
, HTTP_UNAUTHORIZED
);
221 /* warn if user specified incorrect password */
223 debug(16, 1) ("CACHEMGR: %s@%s: incorrect password for '%s'\n",
224 mgr
->user_name
? mgr
->user_name
: "<unknown>",
225 fd_table
[fd
].ipaddr
, mgr
->action
);
227 debug(16, 1) ("CACHEMGR: %s@%s: password needed for '%s'\n",
228 mgr
->user_name
? mgr
->user_name
: "<unknown>",
229 fd_table
[fd
].ipaddr
, mgr
->action
);
230 err
->request
= requestLink(request
);
231 rep
= errorBuildReply(err
);
234 * add Authenticate header, use 'action' as a realm because
235 * password depends on action
237 httpHeaderPutAuth(&rep
->header
, "Basic", mgr
->action
);
238 /* move info to the mem_obj->reply */
239 httpReplyAbsorb(entry
->mem_obj
->reply
, rep
);
240 /* store the reply */
241 httpReplySwapOut(entry
->mem_obj
->reply
, entry
);
242 entry
->expires
= squid_curtime
;
243 storeComplete(entry
);
244 cachemgrStateFree(mgr
);
247 debug(16, 1) ("CACHEMGR: %s@%s requesting '%s'\n",
248 mgr
->user_name
? mgr
->user_name
: "<unknown>",
249 fd_table
[fd
].ipaddr
, mgr
->action
);
250 /* retrieve object requested */
251 a
= cachemgrFindAction(mgr
->action
);
256 http_version_t version
;
257 HttpReply
*rep
= entry
->mem_obj
->reply
;
258 /* prove there are no previous reply headers around */
259 assert(0 == rep
->sline
.status
);
260 httpBuildVersion(&version
, 1, 0);
261 httpReplySetHeaders(rep
,
267 squid_curtime
, /* LMT */
269 httpReplySwapOut(rep
, entry
);
272 if (a
->flags
.atomic
) {
273 storeBufferFlush(entry
);
274 storeComplete(entry
);
276 cachemgrStateFree(mgr
);
280 cachemgrShutdown(StoreEntry
* entryunused
)
282 debug(16, 0) ("Shutdown by command.\n");
287 cachemgrOfflineToggle(StoreEntry
* sentry
)
289 Config
.onoff
.offline
= !Config
.onoff
.offline
;
290 debug(16, 0) ("offline_mode now %s.\n",
291 Config
.onoff
.offline
? "ON" : "OFF");
292 storeAppendPrintf(sentry
, "offline_mode is now %s\n",
293 Config
.onoff
.offline
? "ON" : "OFF");
297 cachemgrActionProtection(const action_table
* at
)
301 pwd
= cachemgrPasswdGet(Config
.passwd_list
, at
->action
);
303 return at
->flags
.pw_req
? "hidden" : "public";
304 if (!strcmp(pwd
, "disable"))
306 if (strcmp(pwd
, "none") == 0)
312 cachemgrMenu(StoreEntry
* sentry
)
315 for (a
= ActionTable
; a
!= NULL
; a
= a
->next
) {
316 storeAppendPrintf(sentry
, " %-22s\t%s\t%s\n",
317 a
->action
, a
->desc
, cachemgrActionProtection(a
));
322 cachemgrPasswdGet(cachemgr_passwd
* a
, const char *action
)
326 for (w
= a
->actions
; w
!= NULL
; w
= w
->next
) {
327 if (0 == strcmp(w
->key
, action
))
329 if (0 == strcmp(w
->key
, "all"))
340 cachemgrRegister("menu",
341 "This Cachemanager Menu",
343 cachemgrRegister("shutdown",
344 "Shut Down the Squid Process",
345 cachemgrShutdown
, 1, 1);
346 cachemgrRegister("offline_toggle",
347 "Toggle offline_mode setting",
348 cachemgrOfflineToggle
, 1, 1);