]> git.ipfire.org Git - thirdparty/squid.git/blob - src/cache_manager.cc
Updated copyright
[thirdparty/squid.git] / src / cache_manager.cc
1
2 /*
3 * $Id: cache_manager.cc,v 1.25 2001/01/12 00:37:15 wessels 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
38 #define MGR_PASSWD_SZ 128
39
40 typedef struct {
41 StoreEntry *entry;
42 char *action;
43 char *user_name;
44 char *passwd;
45 } cachemgrStateData;
46
47 typedef struct _action_table {
48 char *action;
49 char *desc;
50 OBJH *handler;
51 struct {
52 int pw_req:1;
53 int atomic:1;
54 } flags;
55 struct _action_table *next;
56 } action_table;
57
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;
68
69 action_table *ActionTable = NULL;
70
71 void
72 cachemgrRegister(const char *action, const char *desc, OBJH * handler, int pw_req_flag, int atomic)
73 {
74 action_table *a;
75 action_table **A;
76 if (cachemgrFindAction(action) != NULL) {
77 debug(16, 3) ("cachemgrRegister: Duplicate '%s'\n", action);
78 return;
79 }
80 a = xcalloc(1, sizeof(action_table));
81 a->action = xstrdup(action);
82 a->desc = xstrdup(desc);
83 a->handler = handler;
84 a->flags.pw_req = pw_req_flag;
85 a->flags.atomic = atomic;
86 for (A = &ActionTable; *A; A = &(*A)->next);
87 *A = a;
88 debug(16, 3) ("cachemgrRegister: registered %s\n", action);
89 }
90
91 static action_table *
92 cachemgrFindAction(const char *action)
93 {
94 action_table *a;
95 for (a = ActionTable; a != NULL; a = a->next) {
96 if (0 == strcmp(a->action, action))
97 return a;
98 }
99 return NULL;
100 }
101
102 static cachemgrStateData *
103 cachemgrParseUrl(const char *url)
104 {
105 int t;
106 LOCAL_ARRAY(char, host, MAX_URL);
107 LOCAL_ARRAY(char, request, MAX_URL);
108 LOCAL_ARRAY(char, password, MAX_URL);
109 action_table *a;
110 cachemgrStateData *mgr = NULL;
111 const char *prot;
112 t = sscanf(url, "cache_object://%[^/]/%[^@]@%s", host, request, password);
113 if (t < 2) {
114 xstrncpy(request, "menu", MAX_URL);
115 #ifdef _SQUID_OS2_
116 /*
117 * emx's sscanf insists of returning 2 because it sets request
118 * to null
119 */
120 } else if (request[0] == '\0') {
121 xstrncpy(request, "menu", MAX_URL);
122 #endif
123 } else if ((a = cachemgrFindAction(request)) == NULL) {
124 debug(16, 1) ("cachemgrParseUrl: action '%s' not found\n", request);
125 return NULL;
126 } else {
127 prot = cachemgrActionProtection(a);
128 if (!strcmp(prot, "disabled") || !strcmp(prot, "hidden")) {
129 debug(16, 1) ("cachemgrParseUrl: action '%s' is %s\n", request, prot);
130 return NULL;
131 }
132 }
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);
138 return mgr;
139 }
140
141 static void
142 cachemgrParseHeaders(cachemgrStateData * mgr, const request_t * request)
143 {
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");
148 if (!basic_cookie)
149 return;
150 if (!(passwd_del = strchr(basic_cookie, ':'))) {
151 debug(16, 1) ("cachemgrParseHeaders: unknown basic_cookie format '%s'\n", basic_cookie);
152 return;
153 }
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);
162 }
163
164 /*
165 * return 0 if mgr->password is good
166 */
167 static int
168 cachemgrCheckPassword(cachemgrStateData * mgr)
169 {
170 char *pwd = cachemgrPasswdGet(Config.passwd_list, mgr->action);
171 action_table *a = cachemgrFindAction(mgr->action);
172 assert(a != NULL);
173 if (pwd == NULL)
174 return a->flags.pw_req;
175 if (strcmp(pwd, "disable") == 0)
176 return 1;
177 if (strcmp(pwd, "none") == 0)
178 return 0;
179 if (!mgr->passwd)
180 return 1;
181 return strcmp(pwd, mgr->passwd);
182 }
183
184 static void
185 cachemgrStateFree(cachemgrStateData * mgr)
186 {
187 safe_free(mgr->action);
188 safe_free(mgr->user_name);
189 safe_free(mgr->passwd);
190 storeUnlockObject(mgr->entry);
191 xfree(mgr);
192 }
193
194 void
195 cachemgrStart(int fd, request_t * request, StoreEntry * entry)
196 {
197 cachemgrStateData *mgr = NULL;
198 ErrorState *err = NULL;
199 action_table *a;
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;
206 return;
207 }
208 mgr->entry = entry;
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);
215 /* Check password */
216 if (cachemgrCheckPassword(mgr) != 0) {
217 /* build error message */
218 ErrorState *err;
219 HttpReply *rep;
220 err = errorCon(ERR_CACHE_MGR_ACCESS_DENIED, HTTP_UNAUTHORIZED);
221 /* warn if user specified incorrect password */
222 if (mgr->passwd)
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);
226 else
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);
232 errorStateFree(err);
233 /*
234 * add Authenticate header, use 'action' as a realm because
235 * password depends on action
236 */
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);
245 return;
246 }
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);
252 assert(a != NULL);
253 if (a->flags.atomic)
254 storeBuffer(entry);
255 {
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,
262 version,
263 HTTP_OK,
264 NULL,
265 "text/plain",
266 -1, /* C-Len */
267 squid_curtime, /* LMT */
268 squid_curtime);
269 httpReplySwapOut(rep, entry);
270 }
271 a->handler(entry);
272 if (a->flags.atomic) {
273 storeBufferFlush(entry);
274 storeComplete(entry);
275 }
276 cachemgrStateFree(mgr);
277 }
278
279 static void
280 cachemgrShutdown(StoreEntry * entryunused)
281 {
282 debug(16, 0) ("Shutdown by command.\n");
283 shut_down(0);
284 }
285
286 static void
287 cachemgrOfflineToggle(StoreEntry * sentry)
288 {
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");
294 }
295
296 static const char *
297 cachemgrActionProtection(const action_table * at)
298 {
299 char *pwd;
300 assert(at);
301 pwd = cachemgrPasswdGet(Config.passwd_list, at->action);
302 if (!pwd)
303 return at->flags.pw_req ? "hidden" : "public";
304 if (!strcmp(pwd, "disable"))
305 return "disabled";
306 if (strcmp(pwd, "none") == 0)
307 return "public";
308 return "protected";
309 }
310
311 static void
312 cachemgrMenu(StoreEntry * sentry)
313 {
314 action_table *a;
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));
318 }
319 }
320
321 static char *
322 cachemgrPasswdGet(cachemgr_passwd * a, const char *action)
323 {
324 wordlist *w;
325 while (a != NULL) {
326 for (w = a->actions; w != NULL; w = w->next) {
327 if (0 == strcmp(w->key, action))
328 return a->passwd;
329 if (0 == strcmp(w->key, "all"))
330 return a->passwd;
331 }
332 a = a->next;
333 }
334 return NULL;
335 }
336
337 void
338 cachemgrInit(void)
339 {
340 cachemgrRegister("menu",
341 "This Cachemanager Menu",
342 cachemgrMenu, 0, 1);
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);
349 }