]>
Commit | Line | Data |
---|---|---|
22f3fd98 | 1 | |
2 | /* | |
d8b249ef | 3 | * $Id: cache_manager.cc,v 1.10 1998/03/20 18:06:41 rousskov Exp $ |
22f3fd98 | 4 | * |
5 | * DEBUG: section 16 Cache Manager Objects | |
6 | * AUTHOR: Duane Wessels | |
7 | * | |
8 | * SQUID Internet Object Cache http://squid.nlanr.net/Squid/ | |
9 | * -------------------------------------------------------- | |
10 | * | |
11 | * Squid is the result of efforts by numerous individuals from the | |
12 | * Internet community. Development is led by Duane Wessels of the | |
13 | * National Laboratory for Applied Network Research and funded by | |
14 | * the National Science Foundation. | |
15 | * | |
16 | * This program is free software; you can redistribute it and/or modify | |
17 | * it under the terms of the GNU General Public License as published by | |
18 | * the Free Software Foundation; either version 2 of the License, or | |
19 | * (at your option) any later version. | |
20 | * | |
21 | * This program is distributed in the hope that it will be useful, | |
22 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
23 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
24 | * GNU General Public License for more details. | |
25 | * | |
26 | * You should have received a copy of the GNU General Public License | |
27 | * along with this program; if not, write to the Free Software | |
28 | * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. | |
29 | * | |
30 | */ | |
31 | ||
32 | #include "squid.h" | |
33 | ||
34 | #define MGR_PASSWD_SZ 128 | |
35 | ||
36 | typedef struct { | |
37 | StoreEntry *entry; | |
38 | char *action; | |
63259c34 | 39 | char *user_name; |
22f3fd98 | 40 | char *passwd; |
41 | } cachemgrStateData; | |
42 | ||
43 | typedef struct _action_table { | |
44 | char *action; | |
45 | char *desc; | |
46 | OBJH *handler; | |
47 | int pw_req_flag; | |
48 | struct _action_table *next; | |
49 | } action_table; | |
50 | ||
2ac76861 | 51 | static action_table *cachemgrFindAction(const char *action); |
63259c34 | 52 | static cachemgrStateData *cachemgrParseUrl(const char *url); |
2ac76861 | 53 | static void cachemgrParseHeaders(cachemgrStateData * mgr, const request_t * request); |
22f3fd98 | 54 | static int cachemgrCheckPassword(cachemgrStateData *); |
2ac76861 | 55 | static void cachemgrStateFree(cachemgrStateData * mgr); |
22f3fd98 | 56 | static char *cachemgrPasswdGet(cachemgr_passwd *, const char *); |
2ac76861 | 57 | static const char *cachemgrActionProtection(const action_table * at); |
22f3fd98 | 58 | static OBJH cachemgrShutdown; |
59 | static OBJH cachemgrMenu; | |
60 | ||
61 | action_table *ActionTable = NULL; | |
62 | ||
63 | void | |
64 | cachemgrRegister(const char *action, const char *desc, OBJH * handler, int pw_req_flag) | |
65 | { | |
66 | action_table *a; | |
67 | action_table **A; | |
e45867bd | 68 | if (cachemgrFindAction(action) != NULL) { |
2ac76861 | 69 | debug(16, 3) ("cachemgrRegister: Duplicate '%s'\n", action); |
e45867bd | 70 | return; |
71 | } | |
22f3fd98 | 72 | a = xcalloc(1, sizeof(action_table)); |
73 | a->action = xstrdup(action); | |
74 | a->desc = xstrdup(desc); | |
75 | a->handler = handler; | |
76 | a->pw_req_flag = pw_req_flag; | |
77 | for (A = &ActionTable; *A; A = &(*A)->next); | |
78 | *A = a; | |
2ac76861 | 79 | debug(16, 3) ("cachemgrRegister: registered %s\n", action); |
22f3fd98 | 80 | } |
81 | ||
82 | static action_table * | |
83 | cachemgrFindAction(const char *action) | |
84 | { | |
85 | action_table *a; | |
86 | for (a = ActionTable; a != NULL; a = a->next) { | |
87 | if (0 == strcmp(a->action, action)) | |
88 | return a; | |
89 | } | |
90 | return NULL; | |
91 | } | |
92 | ||
93 | static cachemgrStateData * | |
63259c34 | 94 | cachemgrParseUrl(const char *url) |
22f3fd98 | 95 | { |
96 | int t; | |
97 | LOCAL_ARRAY(char, host, MAX_URL); | |
98 | LOCAL_ARRAY(char, request, MAX_URL); | |
99 | LOCAL_ARRAY(char, password, MAX_URL); | |
100 | action_table *a; | |
101 | cachemgrStateData *mgr = NULL; | |
7395afb8 | 102 | const char *prot; |
22f3fd98 | 103 | t = sscanf(url, "cache_object://%[^/]/%[^@]@%s", host, request, password); |
104 | if (t < 2) { | |
105 | xstrncpy(request, "menu", MAX_URL); | |
106 | } else if ((a = cachemgrFindAction(request)) == NULL) { | |
63259c34 | 107 | debug(16, 0) ("cachemgrParseUrl: action '%s' not found\n", request); |
22f3fd98 | 108 | return NULL; |
7395afb8 | 109 | } else { |
2ac76861 | 110 | prot = cachemgrActionProtection(a); |
7395afb8 | 111 | if (!strcmp(prot, "disabled") || !strcmp(prot, "hidden")) { |
112 | debug(16, 0) ("cachemgrParseUrl: action '%s' is %s\n", request, prot); | |
113 | return NULL; | |
114 | } | |
22f3fd98 | 115 | } |
63259c34 | 116 | /* set absent entries to NULL so we can test if they are present later */ |
22f3fd98 | 117 | mgr = xcalloc(1, sizeof(cachemgrStateData)); |
63259c34 | 118 | mgr->user_name = NULL; |
119 | mgr->passwd = t == 3 ? xstrdup(password) : NULL; | |
22f3fd98 | 120 | mgr->action = xstrdup(request); |
121 | return mgr; | |
122 | } | |
123 | ||
63259c34 | 124 | static void |
2ac76861 | 125 | cachemgrParseHeaders(cachemgrStateData * mgr, const request_t * request) |
63259c34 | 126 | { |
2ac76861 | 127 | const char *basic_cookie; /* base 64 _decoded_ user:passwd pair */ |
63259c34 | 128 | const char *authField; |
129 | const char *passwd_del; | |
130 | assert(mgr && request); | |
131 | /* this parsing will go away when hdrs are added to request_t @?@ */ | |
132 | basic_cookie = mime_get_auth(request->headers, "Basic", &authField); | |
2ac76861 | 133 | debug(16, 9) ("cachemgrParseHeaders: got auth: '%s'\n", authField ? authField : "<none>"); |
63259c34 | 134 | if (!authField) |
135 | return; | |
136 | if (!basic_cookie) { | |
137 | debug(16, 1) ("cachemgrParseHeaders: unknown auth format in '%s'\n", authField); | |
138 | return; | |
139 | } | |
140 | if (!(passwd_del = strchr(basic_cookie, ':'))) { | |
141 | debug(16, 1) ("cachemgrParseHeaders: unknown basic_cookie '%s' format in '%s'\n", basic_cookie, authField); | |
142 | return; | |
143 | } | |
144 | /* found user:password pair, reset old values */ | |
145 | safe_free(mgr->user_name); | |
146 | safe_free(mgr->passwd); | |
2ac76861 | 147 | mgr->user_name = xstrdup(basic_cookie); |
63259c34 | 148 | mgr->user_name[passwd_del - basic_cookie] = '\0'; |
2ac76861 | 149 | mgr->passwd = xstrdup(passwd_del + 1); |
63259c34 | 150 | /* warning: this prints decoded password which maybe not what you want to do @?@ @?@ */ |
2ac76861 | 151 | debug(16, 9) ("cachemgrParseHeaders: got user: '%s' passwd: '%s'\n", mgr->user_name, mgr->passwd); |
63259c34 | 152 | } |
153 | ||
22f3fd98 | 154 | /* |
155 | * return 0 if mgr->password is good | |
156 | */ | |
157 | static int | |
158 | cachemgrCheckPassword(cachemgrStateData * mgr) | |
159 | { | |
160 | char *pwd = cachemgrPasswdGet(Config.passwd_list, mgr->action); | |
161 | action_table *a = cachemgrFindAction(mgr->action); | |
162 | assert(a != NULL); | |
163 | if (pwd == NULL) | |
164 | return a->pw_req_flag; | |
165 | if (strcmp(pwd, "disable") == 0) | |
166 | return 1; | |
167 | if (strcmp(pwd, "none") == 0) | |
168 | return 0; | |
63259c34 | 169 | if (!mgr->passwd) |
170 | return 1; | |
22f3fd98 | 171 | return strcmp(pwd, mgr->passwd); |
172 | } | |
173 | ||
174 | static void | |
2ac76861 | 175 | cachemgrStateFree(cachemgrStateData * mgr) |
22f3fd98 | 176 | { |
2ac76861 | 177 | safe_free(mgr->action); |
178 | safe_free(mgr->user_name); | |
179 | safe_free(mgr->passwd); | |
b771e69f | 180 | storeUnlockObject(mgr->entry); |
2ac76861 | 181 | xfree(mgr); |
22f3fd98 | 182 | } |
183 | ||
184 | void | |
2ac76861 | 185 | cachemgrStart(int fd, request_t * request, StoreEntry * entry) |
22f3fd98 | 186 | { |
187 | cachemgrStateData *mgr = NULL; | |
188 | ErrorState *err = NULL; | |
22f3fd98 | 189 | action_table *a; |
190 | debug(16, 3) ("objectcacheStart: '%s'\n", storeUrl(entry)); | |
63259c34 | 191 | if ((mgr = cachemgrParseUrl(storeUrl(entry))) == NULL) { |
22f3fd98 | 192 | err = errorCon(ERR_INVALID_URL, HTTP_NOT_FOUND); |
193 | err->url = xstrdup(storeUrl(entry)); | |
194 | errorAppendEntry(entry, err); | |
195 | entry->expires = squid_curtime; | |
196 | return; | |
197 | } | |
198 | mgr->entry = entry; | |
b771e69f | 199 | storeLockObject(entry); |
22f3fd98 | 200 | entry->expires = squid_curtime; |
63259c34 | 201 | debug(16, 5) ("CACHEMGR: %s requesting '%s'\n", |
22f3fd98 | 202 | fd_table[fd].ipaddr, mgr->action); |
63259c34 | 203 | /* get additional info from request headers */ |
204 | cachemgrParseHeaders(mgr, request); | |
22f3fd98 | 205 | /* Check password */ |
206 | if (cachemgrCheckPassword(mgr) != 0) { | |
b771e69f | 207 | /* build error message */ |
208 | ErrorState *err; | |
209 | HttpReply *rep; | |
210 | err = errorCon(ERR_CACHE_MGR_ACCESS_DENIED, HTTP_UNAUTHORIZED); | |
211 | /* warn if user specified incorrect password */ | |
212 | if (mgr->passwd) | |
213 | debug(16, 1) ("CACHEMGR: %s@%s: incorrect password for '%s'\n", | |
214 | mgr->user_name ? mgr->user_name : "<unknown>", | |
215 | fd_table[fd].ipaddr, mgr->action); | |
216 | else | |
217 | debug(16, 1) ("CACHEMGR: %s@%s: password needed for '%s'\n", | |
218 | mgr->user_name ? mgr->user_name : "<unknown>", | |
219 | fd_table[fd].ipaddr, mgr->action); | |
220 | err->request = requestLink(request); | |
221 | rep = errorBuildReply(err); | |
222 | errorStateFree(err); | |
223 | /* | |
224 | * add Authenticate header, use 'action' as a realm because | |
225 | * password depends on action | |
226 | */ | |
d8b249ef | 227 | httpHeaderPutAuth(&rep->header, "Basic", mgr->action); |
b771e69f | 228 | /* move info to the mem_obj->reply */ |
229 | httpReplyAbsorb(entry->mem_obj->reply, rep); | |
230 | /* store the reply */ | |
231 | httpReplySwapOut(entry->mem_obj->reply, entry); | |
22f3fd98 | 232 | entry->expires = squid_curtime; |
233 | storeComplete(entry); | |
b771e69f | 234 | cachemgrStateFree(mgr); |
22f3fd98 | 235 | return; |
236 | } | |
b771e69f | 237 | debug(16, 1) ("CACHEMGR: %s@%s requesting '%s'\n", |
238 | mgr->user_name ? mgr->user_name : "<unknown>", | |
239 | fd_table[fd].ipaddr, mgr->action); | |
22f3fd98 | 240 | /* retrieve object requested */ |
241 | a = cachemgrFindAction(mgr->action); | |
242 | assert(a != NULL); | |
243 | storeBuffer(entry); | |
cb69b4c7 | 244 | { |
245 | HttpReply *rep = httpReplyCreate(); | |
b771e69f | 246 | httpReplySetHeaders(rep, |
247 | (double) 1.0, | |
248 | HTTP_OK, | |
249 | NULL, | |
250 | "text/plain", | |
251 | -1, /* C-Len */ | |
252 | squid_curtime, /* LMT */ | |
253 | squid_curtime); | |
cb69b4c7 | 254 | httpReplySwapOut(rep, entry); |
255 | httpReplyDestroy(rep); | |
256 | } | |
22f3fd98 | 257 | a->handler(entry); |
258 | storeBufferFlush(entry); | |
259 | storeComplete(entry); | |
260 | cachemgrStateFree(mgr); | |
261 | } | |
262 | ||
263 | static void | |
264 | cachemgrShutdown(StoreEntry * entryunused) | |
265 | { | |
266 | debug(16, 0) ("Shutdown by command.\n"); | |
267 | shut_down(0); | |
268 | } | |
269 | ||
7395afb8 | 270 | static const char * |
2ac76861 | 271 | cachemgrActionProtection(const action_table * at) |
7395afb8 | 272 | { |
273 | char *pwd; | |
274 | assert(at); | |
275 | pwd = cachemgrPasswdGet(Config.passwd_list, at->action); | |
276 | if (!pwd) | |
277 | return at->pw_req_flag ? "hidden" : "public"; | |
278 | if (!strcmp(pwd, "disable")) | |
279 | return "disabled"; | |
280 | if (strcmp(pwd, "none") == 0) | |
281 | return "public"; | |
282 | return "protected"; | |
283 | } | |
284 | ||
22f3fd98 | 285 | static void |
2ac76861 | 286 | cachemgrMenu(StoreEntry * sentry) |
22f3fd98 | 287 | { |
7395afb8 | 288 | action_table *a; |
289 | for (a = ActionTable; a != NULL; a = a->next) { | |
290 | storeAppendPrintf(sentry, " %-22s\t%s\t%s\n", | |
291 | a->action, a->desc, cachemgrActionProtection(a)); | |
292 | } | |
22f3fd98 | 293 | } |
294 | ||
295 | static char * | |
296 | cachemgrPasswdGet(cachemgr_passwd * a, const char *action) | |
297 | { | |
298 | wordlist *w; | |
299 | while (a != NULL) { | |
300 | for (w = a->actions; w != NULL; w = w->next) { | |
301 | if (0 == strcmp(w->key, action)) | |
302 | return a->passwd; | |
303 | if (0 == strcmp(w->key, "all")) | |
304 | return a->passwd; | |
305 | } | |
306 | a = a->next; | |
307 | } | |
308 | return NULL; | |
309 | } | |
310 | ||
311 | void | |
312 | cachemgrInit(void) | |
313 | { | |
314 | cachemgrRegister("menu", | |
315 | "This Cachemanager Menu", | |
316 | cachemgrMenu, 0); | |
317 | cachemgrRegister("shutdown", | |
318 | "Shut Down the Squid Process", | |
319 | cachemgrShutdown, 1); | |
320 | } |