]> git.ipfire.org Git - thirdparty/squid.git/blob - src/cache_manager.cc
Summary: Final MSVC fixups.
[thirdparty/squid.git] / src / cache_manager.cc
1
2 /*
3 * $Id: cache_manager.cc,v 1.30 2003/08/10 11:00:42 robertc Exp $
4 *
5 * DEBUG: section 16 Cache Manager Objects
6 * AUTHOR: Duane Wessels
7 *
8 * SQUID Web Proxy Cache http://www.squid-cache.org/
9 * ----------------------------------------------------------
10 *
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.
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
32 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
33 *
34 */
35
36 #include "squid.h"
37 #include "HttpReply.h"
38 #include "HttpRequest.h"
39 #include "Store.h"
40 #include "fde.h"
41
42 #define MGR_PASSWD_SZ 128
43
44 typedef struct
45 {
46 StoreEntry *entry;
47 char *action;
48 char *user_name;
49 char *passwd;
50 }
51
52 cachemgrStateData;
53
54 typedef struct _action_table
55 {
56 char *action;
57 char *desc;
58 OBJH *handler;
59
60 struct
61 {
62
63 unsigned int pw_req:
64 1;
65
66 unsigned int atomic:
67 1;
68 }
69
70 flags;
71
72 struct _action_table *next;
73 }
74
75 action_table;
76
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;
87
88 action_table *ActionTable = NULL;
89
90 void
91 cachemgrRegister(const char *action, const char *desc, OBJH * handler, int pw_req_flag, int atomic)
92 {
93 action_table *a;
94 action_table **A;
95
96 if (cachemgrFindAction(action) != NULL) {
97 debug(16, 3) ("cachemgrRegister: Duplicate '%s'\n", action);
98 return;
99 }
100
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;
108
109 for (A = &ActionTable; *A; A = &(*A)->next)
110
111 ;
112 *A = a;
113
114 debug(16, 3) ("cachemgrRegister: registered %s\n", action);
115 }
116
117 static action_table *
118 cachemgrFindAction(const char *action)
119 {
120 action_table *a;
121
122 for (a = ActionTable; a != NULL; a = a->next) {
123 if (0 == strcmp(a->action, action))
124 return a;
125 }
126
127 return NULL;
128 }
129
130 static cachemgrStateData *
131 cachemgrParseUrl(const char *url)
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;
139 const char *prot;
140 t = sscanf(url, "cache_object://%[^/]/%[^@]@%s", host, request, password);
141
142 if (t < 2) {
143 xstrncpy(request, "menu", MAX_URL);
144 #ifdef _SQUID_OS2_
145 /*
146 * emx's sscanf insists of returning 2 because it sets request
147 * to null
148 */
149 } else if (request[0] == '\0') {
150 xstrncpy(request, "menu", MAX_URL);
151 #endif
152
153 } else if ((a = cachemgrFindAction(request)) == NULL) {
154 debug(16, 1) ("cachemgrParseUrl: action '%s' not found\n", request);
155 return NULL;
156 } else {
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 }
163 }
164
165 /* set absent entries to NULL so we can test if they are present later */
166 mgr = (cachemgrStateData *)xcalloc(1, sizeof(cachemgrStateData));
167
168 mgr->user_name = NULL;
169
170 mgr->passwd = t == 3 ? xstrdup(password) : NULL;
171
172 mgr->action = xstrdup(request);
173
174 return mgr;
175 }
176
177 static void
178 cachemgrParseHeaders(cachemgrStateData * mgr, const HttpRequest * request)
179 {
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");
184
185 if (!basic_cookie)
186 return;
187
188 if (!(passwd_del = strchr(basic_cookie, ':'))) {
189 debug(16, 1) ("cachemgrParseHeaders: unknown basic_cookie format '%s'\n", basic_cookie);
190 return;
191 }
192
193 /* found user:password pair, reset old values */
194 safe_free(mgr->user_name);
195
196 safe_free(mgr->passwd);
197
198 mgr->user_name = xstrdup(basic_cookie);
199
200 mgr->user_name[passwd_del - basic_cookie] = '\0';
201
202 mgr->passwd = xstrdup(passwd_del + 1);
203
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);
206 }
207
208 /*
209 * return 0 if mgr->password is good
210 */
211 static int
212 cachemgrCheckPassword(cachemgrStateData * mgr)
213 {
214 char *pwd = cachemgrPasswdGet(Config.passwd_list, mgr->action);
215 action_table *a = cachemgrFindAction(mgr->action);
216 assert(a != NULL);
217
218 if (pwd == NULL)
219 return a->flags.pw_req;
220
221 if (strcmp(pwd, "disable") == 0)
222 return 1;
223
224 if (strcmp(pwd, "none") == 0)
225 return 0;
226
227 if (!mgr->passwd)
228 return 1;
229
230 return strcmp(pwd, mgr->passwd);
231 }
232
233 static void
234 cachemgrStateFree(cachemgrStateData * mgr)
235 {
236 safe_free(mgr->action);
237 safe_free(mgr->user_name);
238 safe_free(mgr->passwd);
239 storeUnlockObject(mgr->entry);
240 xfree(mgr);
241 }
242
243 void
244 cachemgrStart(int fd, HttpRequest * request, StoreEntry * entry)
245 {
246 cachemgrStateData *mgr = NULL;
247 ErrorState *err = NULL;
248 action_table *a;
249 debug(16, 3) ("objectcacheStart: '%s'\n", storeUrl(entry));
250
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;
256 return;
257 }
258
259 mgr->entry = entry;
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);
266 /* Check password */
267
268 if (cachemgrCheckPassword(mgr) != 0) {
269 /* build error message */
270 ErrorState *err;
271 HttpReply *rep;
272 err = errorCon(ERR_CACHE_MGR_ACCESS_DENIED, HTTP_UNAUTHORIZED);
273 /* warn if user specified incorrect password */
274
275 if (mgr->passwd)
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);
279 else
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);
283
284 err->request = requestLink(request);
285
286 rep = errorBuildReply(err);
287
288 errorStateFree(err);
289
290 /*
291 * add Authenticate header, use 'action' as a realm because
292 * password depends on action
293 */
294 httpHeaderPutAuth(&rep->header, "Basic", mgr->action);
295
296 /* store the reply */
297 httpReplySwapOut(rep, entry);
298
299 entry->expires = squid_curtime;
300
301 entry->complete();
302
303 cachemgrStateFree(mgr);
304
305 return;
306 }
307
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);
313 assert(a != NULL);
314
315 if (a->flags.atomic)
316 storeBuffer(entry);
317
318 {
319 http_version_t version;
320 HttpReply *rep = httpReplyCreate();
321 httpBuildVersion(&version, 1, 0);
322 httpReplySetHeaders(rep,
323 version,
324 HTTP_OK,
325 NULL,
326 "text/plain",
327 -1, /* C-Len */
328 squid_curtime, /* LMT */
329 squid_curtime);
330 httpReplySwapOut(rep, entry);
331 }
332
333 a->handler(entry);
334
335 if (a->flags.atomic) {
336 storeBufferFlush(entry);
337 entry->complete();
338 }
339
340 cachemgrStateFree(mgr);
341 }
342
343 static void
344 cachemgrShutdown(StoreEntry * entryunused)
345 {
346 debug(16, 0) ("Shutdown by command.\n");
347 shut_down(0);
348 }
349
350 static void
351 cachemgrOfflineToggle(StoreEntry * sentry)
352 {
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");
358 }
359
360 static const char *
361 cachemgrActionProtection(const action_table * at)
362 {
363 char *pwd;
364 assert(at);
365 pwd = cachemgrPasswdGet(Config.passwd_list, at->action);
366
367 if (!pwd)
368 return at->flags.pw_req ? "hidden" : "public";
369
370 if (!strcmp(pwd, "disable"))
371 return "disabled";
372
373 if (strcmp(pwd, "none") == 0)
374 return "public";
375
376 return "protected";
377 }
378
379 static void
380 cachemgrMenu(StoreEntry * sentry)
381 {
382 action_table *a;
383
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));
387 }
388 }
389
390 static char *
391 cachemgrPasswdGet(cachemgr_passwd * a, const char *action)
392 {
393 wordlist *w;
394
395 while (a != NULL) {
396 for (w = a->actions; w != NULL; w = w->next) {
397 if (0 == strcmp(w->key, action))
398 return a->passwd;
399
400 if (0 == strcmp(w->key, "all"))
401 return a->passwd;
402 }
403
404 a = a->next;
405 }
406
407 return NULL;
408 }
409
410 void
411 cachemgrInit(void)
412 {
413 cachemgrRegister("menu",
414 "This Cachemanager Menu",
415 cachemgrMenu, 0, 1);
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);
422 }