~clint-fewbar/ubuntu/precise/squid3/ignore-sighup-early

« back to all changes in this revision

Viewing changes to src/cache_manager.cc

  • Committer: Bazaar Package Importer
  • Author(s): Luigi Gangitano
  • Date: 2010-05-04 11:15:49 UTC
  • mfrom: (1.3.1 upstream)
  • mto: (20.3.1 squeeze) (21.2.1 sid)
  • mto: This revision was merged to the branch mainline in revision 21.
  • Revision ID: james.westby@ubuntu.com-20100504111549-1apjh2g5sndki4te
Tags: upstream-3.1.3
ImportĀ upstreamĀ versionĀ 3.1.3

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
1
 
2
2
/*
3
 
 * $Id: cache_manager.cc,v 1.48 2007/10/31 04:52:16 amosjeffries Exp $
 
3
 * $Id$
4
4
 *
5
5
 * DEBUG: section 16    Cache Manager Objects
6
6
 * AUTHOR: Duane Wessels
21
21
 *  it under the terms of the GNU General Public License as published by
22
22
 *  the Free Software Foundation; either version 2 of the License, or
23
23
 *  (at your option) any later version.
24
 
 *  
 
24
 *
25
25
 *  This program is distributed in the hope that it will be useful,
26
26
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
27
27
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
28
28
 *  GNU General Public License for more details.
29
 
 *  
 
29
 *
30
30
 *  You should have received a copy of the GNU General Public License
31
31
 *  along with this program; if not, write to the Free Software
32
32
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111, USA.
41
41
#include "fde.h"
42
42
#include "SquidTime.h"
43
43
#include "wordlist.h"
 
44
#include "Debug.h"
44
45
 
 
46
/// \ingroup CacheManagerInternal
45
47
#define MGR_PASSWD_SZ 128
46
48
 
47
 
typedef struct
48
 
{
49
 
    StoreEntry *entry;
50
 
    char *action;
51
 
    char *user_name;
52
 
    char *passwd;
53
 
}
54
 
 
55
 
cachemgrStateData;
56
 
 
57
 
 
58
 
static CacheManagerAction *cachemgrFindAction(const char *action);
59
 
static cachemgrStateData *cachemgrParseUrl(const char *url);
60
 
static void cachemgrParseHeaders(cachemgrStateData * mgr, const HttpRequest * 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 CacheManagerAction * at);
65
 
static OBJH cachemgrShutdown;
66
 
static OBJH cachemgrReconfigure;
67
 
static OBJH cachemgrMenu;
68
 
static OBJH cachemgrOfflineToggle;
69
 
 
70
 
CacheManagerAction *ActionTable = NULL;
71
 
 
 
49
 
 
50
/**
 
51
 \ingroup CacheManagerInternals
 
52
 * Constructor. Its purpose is to register internal commands
 
53
 */
72
54
CacheManager::CacheManager()
73
55
{
74
 
    registerAction("menu", "This Cachemanager Menu", cachemgrMenu, 0, 1);
75
 
    registerAction("shutdown",
76
 
                   "Shut Down the Squid Process",
77
 
                   cachemgrShutdown, 1, 1);
78
 
    registerAction("reconfigure",
79
 
                     "Reconfigure the Squid Process",
80
 
                     cachemgrReconfigure, 1, 1);
81
 
    registerAction("offline_toggle",
82
 
                   "Toggle offline_mode setting",
83
 
                   cachemgrOfflineToggle, 1, 1);
 
56
    registerAction(new OfflineToggleAction);
 
57
    registerAction(new ShutdownAction);
 
58
    registerAction(new ReconfigureAction);
 
59
    registerAction(new MenuAction(this));
84
60
}
85
61
 
 
62
/**
 
63
 \ingroup CacheManagerAPI
 
64
 * Registers a C-style action, which is implemented as a pointer to a function
 
65
 * taking as argument a pointer to a StoreEntry and returning void.
 
66
 * Implemented via CacheManagerActionLegacy.
 
67
 */
86
68
void
87
69
CacheManager::registerAction(char const * action, char const * desc, OBJH * handler, int pw_req_flag, int atomic)
88
70
{
89
 
    CacheManagerAction *a;
90
 
    CacheManagerAction **A;
 
71
    debugs(16, 3, "CacheManager::registerAction: registering legacy " <<  action);
 
72
    registerAction(new CacheManagerActionLegacy(action,desc,pw_req_flag,atomic,handler));
 
73
}
91
74
 
 
75
/**
 
76
 \ingroup CacheManagerAPI
 
77
 * Registers a C++-style action, via a poiner to a subclass of
 
78
 * a CacheManagerAction object, whose run() method will be invoked when
 
79
 * CacheManager identifies that the user has requested the action.
 
80
 */
 
81
void
 
82
CacheManager::registerAction(CacheManagerAction *anAction)
 
83
{
 
84
    char *action = anAction->action;
92
85
    if (findAction(action) != NULL) {
93
 
        debugs(16, 3, "CacheManager::registerAction: Duplicate '" << action << "'");
 
86
        debugs(16, 2, "CacheManager::registerAction: Duplicate '" << action << "'. Skipping.");
94
87
        return;
95
88
    }
96
89
 
97
90
    assert (strstr (" ", action) == NULL);
98
 
    a = (CacheManagerAction *)xcalloc(1, sizeof(CacheManagerAction));
99
 
    a->action = xstrdup(action);
100
 
    a->desc = xstrdup(desc);
101
 
    a->handler = handler;
102
 
    a->flags.pw_req = pw_req_flag;
103
 
    a->flags.atomic = atomic;
104
 
 
105
 
    for (A = &ActionTable; *A; A = &(*A)->next)
106
 
 
107
 
        ;
108
 
    *A = a;
 
91
 
 
92
    ActionsList += anAction;
109
93
 
110
94
    debugs(16, 3, "CacheManager::registerAction: registered " <<  action);
111
95
}
112
96
 
 
97
 
 
98
/**
 
99
 \ingroup CacheManagerInternal
 
100
 * Locates an action in the actions registry ActionsList.
 
101
\retval NULL  if Action not found
 
102
\retval CacheManagerAction* if the action was found
 
103
 */
113
104
CacheManagerAction *
114
105
CacheManager::findAction(char const * action)
115
106
{
116
 
    return cachemgrFindAction(action);
117
 
}
118
 
 
119
 
static CacheManagerAction *
120
 
cachemgrFindAction(const char *action)
121
 
{
122
 
    CacheManagerAction *a;
123
 
 
124
 
    for (a = ActionTable; a != NULL; a = a->next) {
125
 
        if (0 == strcmp(a->action, action))
126
 
            return a;
 
107
    CacheManagerActionList::iterator a;
 
108
 
 
109
    debugs(16, 5, "CacheManager::findAction: looking for action " << action);
 
110
    for ( a = ActionsList.begin(); a != ActionsList.end(); a++) {
 
111
        if (0 == strcmp((*a)->action, action)) {
 
112
            debugs(16, 6, " found");
 
113
            return *a;
 
114
        }
127
115
    }
128
116
 
 
117
    debugs(16, 6, "Action not found.");
129
118
    return NULL;
130
119
}
131
120
 
132
 
static cachemgrStateData *
133
 
cachemgrParseUrl(const char *url)
 
121
/**
 
122
 \ingroup CacheManagerInternal
 
123
 * define whether the URL is a cache-manager URL and parse the action
 
124
 * requested by the user. Checks via CacheManager::ActionProtection() that the
 
125
 * item is accessible by the user.
 
126
 \retval CacheManager::cachemgrStateData state object for the following handling
 
127
 \retval NULL if the action can't be found or can't be accessed by the user
 
128
 */
 
129
CacheManager::cachemgrStateData *
 
130
CacheManager::ParseUrl(const char *url)
134
131
{
135
132
    int t;
136
133
    LOCAL_ARRAY(char, host, MAX_URL);
152
149
        xstrncpy(request, "menu", MAX_URL);
153
150
#endif
154
151
 
155
 
    } else if ((a = cachemgrFindAction(request)) == NULL) {
156
 
        debugs(16, 1, "cachemgrParseUrl: action '" << request << "' not found");
 
152
    } else if ((a = findAction(request)) == NULL) {
 
153
        debugs(16, DBG_IMPORTANT, "CacheManager::ParseUrl: action '" << request << "' not found");
157
154
        return NULL;
158
155
    } else {
159
 
        prot = cachemgrActionProtection(a);
 
156
        prot = ActionProtection(a);
160
157
 
161
158
        if (!strcmp(prot, "disabled") || !strcmp(prot, "hidden")) {
162
 
            debugs(16, 1, "cachemgrParseUrl: action '" << request << "' is " << prot);
 
159
            debugs(16, DBG_IMPORTANT, "CacheManager::ParseUrl: action '" << request << "' is " << prot);
163
160
            return NULL;
164
161
        }
165
162
    }
176
173
    return mgr;
177
174
}
178
175
 
179
 
static void
180
 
cachemgrParseHeaders(cachemgrStateData * mgr, const HttpRequest * request)
 
176
/// \ingroup CacheManagerInternal
 
177
/*
 
178
 \ingroup CacheManagerInternal
 
179
 * Decodes the headers needed to perform user authentication and fills
 
180
 * the details into the cachemgrStateData argument
 
181
 */
 
182
void
 
183
CacheManager::ParseHeaders(cachemgrStateData * mgr, const HttpRequest * request)
181
184
{
182
185
    const char *basic_cookie;   /* base 64 _decoded_ user:passwd pair */
183
186
    const char *passwd_del;
188
191
        return;
189
192
 
190
193
    if (!(passwd_del = strchr(basic_cookie, ':'))) {
191
 
        debugs(16, 1, "cachemgrParseHeaders: unknown basic_cookie format '" << basic_cookie << "'");
 
194
        debugs(16, DBG_IMPORTANT, "CacheManager::ParseHeaders: unknown basic_cookie format '" << basic_cookie << "'");
192
195
        return;
193
196
    }
194
197
 
204
207
    mgr->passwd = xstrdup(passwd_del + 1);
205
208
 
206
209
    /* warning: this prints decoded password which maybe not what you want to do @?@ @?@ */
207
 
    debugs(16, 9, "cachemgrParseHeaders: got user: '" << mgr->user_name << "' passwd: '" << mgr->passwd << "'");
 
210
    debugs(16, 9, "CacheManager::ParseHeaders: got user: '" << mgr->user_name << "' passwd: '" << mgr->passwd << "'");
208
211
}
209
212
 
210
 
/*
211
 
 * return 0 if mgr->password is good
 
213
/**
 
214
 \ingroup CacheManagerInternal
 
215
 *
 
216
 \retval 0      if mgr->password is good or "none"
 
217
 \retval 1      if mgr->password is "disable"
 
218
 \retval !0     if mgr->password does not match configured password
212
219
 */
213
 
static int
214
 
cachemgrCheckPassword(cachemgrStateData * mgr)
 
220
int
 
221
CacheManager::CheckPassword(cachemgrStateData * mgr)
215
222
{
216
 
    char *pwd = cachemgrPasswdGet(Config.passwd_list, mgr->action);
217
 
    CacheManagerAction *a = cachemgrFindAction(mgr->action);
 
223
    char *pwd = PasswdGet(Config.passwd_list, mgr->action);
 
224
    CacheManagerAction *a = findAction(mgr->action);
 
225
 
 
226
    debugs(16, 4, "CacheManager::CheckPassword for action " << mgr->action);
218
227
    assert(a != NULL);
219
228
 
220
229
    if (pwd == NULL)
232
241
    return strcmp(pwd, mgr->passwd);
233
242
}
234
243
 
235
 
static void
236
 
cachemgrStateFree(cachemgrStateData * mgr)
 
244
/// \ingroup CacheManagerInternal
 
245
void
 
246
CacheManager::StateFree(cachemgrStateData * mgr)
237
247
{
238
248
    safe_free(mgr->action);
239
249
    safe_free(mgr->user_name);
242
252
    xfree(mgr);
243
253
}
244
254
 
 
255
/**
 
256
 \ingroup CacheManagerAPI
 
257
 * Main entry point in the Cache Manager's activity. Gets called as part
 
258
 * of the forward chain if the right URL is detected there. Initiates
 
259
 * all needed internal work and renders the response.
 
260
 */
245
261
void
246
 
cachemgrStart(int fd, HttpRequest * request, StoreEntry * entry)
 
262
CacheManager::Start(int fd, HttpRequest * request, StoreEntry * entry)
247
263
{
248
264
    cachemgrStateData *mgr = NULL;
249
265
    ErrorState *err = NULL;
250
266
    CacheManagerAction *a;
251
 
    debugs(16, 3, "objectcacheStart: '" << entry->url() << "'" );
 
267
    debugs(16, 3, "CacheManager::Start: '" << entry->url() << "'" );
252
268
 
253
 
    if ((mgr = cachemgrParseUrl(entry->url())) == NULL) {
 
269
    if ((mgr = ParseUrl(entry->url())) == NULL) {
254
270
        err = errorCon(ERR_INVALID_URL, HTTP_NOT_FOUND, request);
255
271
        err->url = xstrdup(entry->url());
256
272
        errorAppendEntry(entry, err);
260
276
 
261
277
    mgr->entry = entry;
262
278
 
263
 
    entry->lock()
264
 
 
265
 
    ;
 
279
    entry->lock();
266
280
    entry->expires = squid_curtime;
267
281
 
268
 
    debugs(16, 5, "CACHEMGR: " << fd_table[fd].ipaddr << " requesting '" << mgr->action << "'");
 
282
    debugs(16, 5, "CacheManager: " << fd_table[fd].ipaddr << " requesting '" << mgr->action << "'");
269
283
 
270
284
    /* get additional info from request headers */
271
 
    cachemgrParseHeaders(mgr, request);
 
285
    ParseHeaders(mgr, request);
272
286
 
273
287
    /* Check password */
274
288
 
275
 
    if (cachemgrCheckPassword(mgr) != 0) {
 
289
    if (CheckPassword(mgr) != 0) {
276
290
        /* build error message */
277
 
        ErrorState *err;
 
291
        ErrorState *errState;
278
292
        HttpReply *rep;
279
 
        err = errorCon(ERR_CACHE_MGR_ACCESS_DENIED, HTTP_UNAUTHORIZED, request);
 
293
        errState = errorCon(ERR_CACHE_MGR_ACCESS_DENIED, HTTP_UNAUTHORIZED, request);
280
294
        /* warn if user specified incorrect password */
281
295
 
282
296
        if (mgr->passwd)
283
 
            debugs(16, 1, "CACHEMGR: " << 
284
 
                   (mgr->user_name ? mgr->user_name : "<unknown>") << "@" << 
285
 
                   fd_table[fd].ipaddr << ": incorrect password for '" << 
 
297
            debugs(16, DBG_IMPORTANT, "CacheManager: " <<
 
298
                   (mgr->user_name ? mgr->user_name : "<unknown>") << "@" <<
 
299
                   fd_table[fd].ipaddr << ": incorrect password for '" <<
286
300
                   mgr->action << "'" );
287
301
        else
288
 
            debugs(16, 1, "CACHEMGR: " << 
289
 
                   (mgr->user_name ? mgr->user_name : "<unknown>") << "@" << 
290
 
                   fd_table[fd].ipaddr << ": password needed for '" << 
 
302
            debugs(16, DBG_IMPORTANT, "CacheManager: " <<
 
303
                   (mgr->user_name ? mgr->user_name : "<unknown>") << "@" <<
 
304
                   fd_table[fd].ipaddr << ": password needed for '" <<
291
305
                   mgr->action << "'" );
292
306
 
293
 
        rep = errorBuildReply(err);
 
307
        rep = errState->BuildHttpReply();
294
308
 
295
 
        errorStateFree(err);
 
309
        errorStateFree(errState);
296
310
 
297
311
        /*
298
312
         * add Authenticate header, use 'action' as a realm because
307
321
 
308
322
        entry->complete();
309
323
 
310
 
        cachemgrStateFree(mgr);
 
324
        StateFree(mgr);
311
325
 
312
326
        return;
313
327
    }
314
328
 
315
 
    debugs(16, 1, "CACHEMGR: " << 
316
 
           (mgr->user_name ? mgr->user_name : "<unknown>") << "@" << 
317
 
           fd_table[fd].ipaddr << " requesting '" << 
 
329
    debugs(16, 2, "CacheManager: " <<
 
330
           (mgr->user_name ? mgr->user_name : "<unknown>") << "@" <<
 
331
           fd_table[fd].ipaddr << " requesting '" <<
318
332
           mgr->action << "'" );
319
333
    /* retrieve object requested */
320
 
    a = cachemgrFindAction(mgr->action);
 
334
    a = findAction(mgr->action);
321
335
    assert(a != NULL);
322
336
 
323
337
    entry->buffer();
324
338
 
325
339
    {
326
 
        HttpVersion version(1,0);
327
340
        HttpReply *rep = new HttpReply;
328
 
        rep->setHeaders(version,
329
 
                        HTTP_OK,
330
 
                        NULL,
331
 
                        "text/plain",
332
 
                        -1,                     /* C-Len */
333
 
                        squid_curtime,  /* LMT */
334
 
                        squid_curtime);
 
341
        rep->setHeaders(HTTP_OK, NULL, "text/plain", -1, squid_curtime, squid_curtime);
335
342
        entry->replaceHttpReply(rep);
336
343
    }
337
344
 
338
 
    a->handler(entry);
 
345
    a->run(entry);
339
346
 
340
347
    entry->flush();
341
348
 
342
349
    if (a->flags.atomic)
343
350
        entry->complete();
344
351
 
345
 
    cachemgrStateFree(mgr);
 
352
    StateFree(mgr);
346
353
}
347
354
 
348
 
static void
349
 
cachemgrShutdown(StoreEntry * entryunused)
 
355
/// \ingroup CacheManagerInternal
 
356
void CacheManager::ShutdownAction::run(StoreEntry *sentry)
350
357
{
351
 
    debugs(16, 0, "Shutdown by command.");
 
358
    debugs(16, DBG_CRITICAL, "Shutdown by Cache Manager command.");
352
359
    shut_down(0);
353
360
}
 
361
/// \ingroup CacheManagerInternal
 
362
CacheManager::ShutdownAction::ShutdownAction() : CacheManagerAction("shutdown","Shut Down the Squid Process", 1, 1) { }
354
363
 
355
 
static void
356
 
cachemgrReconfigure(StoreEntry * sentry)
 
364
/// \ingroup CacheManagerInternal
 
365
void
 
366
CacheManager::ReconfigureAction::run(StoreEntry * sentry)
357
367
{
358
 
    debug(16, 0) ("Reconfigure by command.\n");
 
368
    debugs(16, DBG_IMPORTANT, "Reconfigure by Cache Manager command.");
359
369
    storeAppendPrintf(sentry, "Reconfiguring Squid Process ....");
360
370
    reconfigure(SIGHUP);
361
371
}
 
372
/// \ingroup CacheManagerInternal
 
373
CacheManager::ReconfigureAction::ReconfigureAction() : CacheManagerAction("reconfigure","Reconfigure Squid", 1, 1) { }
362
374
 
363
375
/// \ingroup CacheManagerInternal
364
 
static void
365
 
cachemgrOfflineToggle(StoreEntry * sentry)
 
376
void
 
377
CacheManager::OfflineToggleAction::run(StoreEntry * sentry)
366
378
{
367
379
    Config.onoff.offline = !Config.onoff.offline;
368
 
    debugs(16, 0, "offline_mode now " << (Config.onoff.offline ? "ON" : "OFF") << ".");
 
380
    debugs(16, DBG_IMPORTANT, "offline_mode now " << (Config.onoff.offline ? "ON" : "OFF") << " by Cache Manager request.");
369
381
 
370
382
    storeAppendPrintf(sentry, "offline_mode is now %s\n",
371
383
                      Config.onoff.offline ? "ON" : "OFF");
372
384
}
 
385
/// \ingroup CacheManagerInternal
 
386
CacheManager::OfflineToggleAction::OfflineToggleAction() : CacheManagerAction ("offline_toggle", "Toggle offline_mode setting", 1, 1) { }
373
387
 
374
 
static const char *
375
 
cachemgrActionProtection(const CacheManagerAction * at)
 
388
/*
 
389
 \ingroup CacheManagerInternal
 
390
 * Renders the protection level text for an action.
 
391
 * Also doubles as a check for the protection level.
 
392
 */
 
393
const char *
 
394
CacheManager::ActionProtection(const CacheManagerAction * at)
376
395
{
377
396
    char *pwd;
378
397
    assert(at);
379
 
    pwd = cachemgrPasswdGet(Config.passwd_list, at->action);
 
398
    pwd = PasswdGet(Config.passwd_list, at->action);
380
399
 
381
400
    if (!pwd)
382
401
        return at->flags.pw_req ? "hidden" : "public";
390
409
    return "protected";
391
410
}
392
411
 
393
 
static void
394
 
cachemgrMenu(StoreEntry * sentry)
 
412
/// \ingroup CacheManagerInternal
 
413
void
 
414
CacheManager::MenuAction::run(StoreEntry * sentry)
395
415
{
396
 
    CacheManagerAction *a;
 
416
    CacheManagerActionList::iterator a;
397
417
 
398
 
    for (a = ActionTable; a != NULL; a = a->next) {
 
418
    debugs(16, 4, "CacheManager::MenuCommand invoked");
 
419
    for (a = cmgr->ActionsList.begin(); a != cmgr->ActionsList.end(); ++a) {
 
420
        debugs(16, 5, "  showing action " << (*a)->action);
399
421
        storeAppendPrintf(sentry, " %-22s\t%-32s\t%s\n",
400
 
                          a->action, a->desc, cachemgrActionProtection(a));
 
422
                          (*a)->action, (*a)->desc, cmgr->ActionProtection(*a));
401
423
    }
402
424
}
 
425
/// \ingroup CacheManagerInternal
 
426
CacheManager::MenuAction::MenuAction(CacheManager *aMgr) : CacheManagerAction ("menu", "Cache Manager Menu", 0, 1), cmgr(aMgr) { }
403
427
 
404
 
static char *
405
 
cachemgrPasswdGet(cachemgr_passwd * a, const char *action)
 
428
/*
 
429
 \ingroup CacheManagerInternal
 
430
 * gets from the global Config the password the user would need to supply
 
431
 * for the action she queried
 
432
 */
 
433
char *
 
434
CacheManager::PasswdGet(cachemgr_passwd * a, const char *action)
406
435
{
407
436
    wordlist *w;
408
437
 
420
449
 
421
450
    return NULL;
422
451
}
 
452
 
 
453
CacheManager* CacheManager::instance=0;
 
454
 
 
455
/**
 
456
 \ingroup CacheManagerAPI
 
457
 * Singleton accessor method.
 
458
 */
 
459
CacheManager*
 
460
CacheManager::GetInstance()
 
461
{
 
462
    if (instance == 0) {
 
463
        debugs(16, 6, "CacheManager::GetInstance: starting cachemanager up");
 
464
        instance = new CacheManager;
 
465
    }
 
466
    return instance;
 
467
}
 
468
 
 
469
 
 
470
/// \ingroup CacheManagerInternal
 
471
void CacheManagerActionLegacy::run(StoreEntry *sentry)
 
472
{
 
473
    handler(sentry);
 
474
}
 
475
/// \ingroup CacheManagerInternal
 
476
CacheManagerAction::CacheManagerAction(char const *anAction, char const *aDesc, unsigned int isPwReq, unsigned int isAtomic)
 
477
{
 
478
    flags.pw_req = isPwReq;
 
479
    flags.atomic = isAtomic;
 
480
    action = xstrdup (anAction);
 
481
    desc = xstrdup (aDesc);
 
482
}
 
483
/// \ingroup CacheManagerInternal
 
484
CacheManagerAction::~CacheManagerAction()
 
485
{
 
486
    xfree(action);
 
487
    xfree(desc);
 
488
}
 
489
 
 
490
/// \ingroup CacheManagerInternal
 
491
CacheManagerActionLegacy::CacheManagerActionLegacy(char const *anAction, char const *aDesc, unsigned int isPwReq, unsigned int isAtomic, OBJH *aHandler) : CacheManagerAction(anAction, aDesc, isPwReq, isAtomic), handler(aHandler)
 
492
{
 
493
}