cache_manager.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2018 The Squid Software Foundation and contributors
3  *
4  * Squid software is distributed under GPLv2+ license and includes
5  * contributions from numerous individuals and organizations.
6  * Please see the COPYING and CONTRIBUTORS files for details.
7  */
8 
9 /* DEBUG: section 16 Cache Manager Objects */
10 
11 #include "squid.h"
12 #include "base/TextException.h"
13 #include "CacheManager.h"
14 #include "comm/Connection.h"
15 #include "Debug.h"
16 #include "errorpage.h"
17 #include "fde.h"
18 #include "HttpReply.h"
19 #include "HttpRequest.h"
20 #include "mgr/Action.h"
21 #include "mgr/ActionCreator.h"
22 #include "mgr/ActionPasswordList.h"
23 #include "mgr/ActionProfile.h"
24 #include "mgr/BasicActions.h"
25 #include "mgr/Command.h"
26 #include "mgr/Forwarder.h"
27 #include "mgr/FunAction.h"
28 #include "mgr/QueryParams.h"
29 #include "protos.h"
30 #include "SquidConfig.h"
31 #include "SquidTime.h"
32 #include "Store.h"
33 #include "tools.h"
34 #include "wordlist.h"
35 
36 #include <algorithm>
37 
39 #define MGR_PASSWD_SZ 128
40 
43 {
44 public:
46 
47 public:
48  ClassActionCreator(Handler *aHandler): handler(aHandler) {}
49 
51  return handler(cmd);
52  }
53 
54 private:
56 };
57 
59 void
61 {
62  Must(profile != NULL);
63  if (!CacheManager::findAction(profile->name)) {
64  menu_.push_back(profile);
65  debugs(16, 3, HERE << "registered profile: " << *profile);
66  } else {
67  debugs(16, 2, HERE << "skipped duplicate profile: " << *profile);
68  }
69 }
70 
77 void
78 CacheManager::registerProfile(char const * action, char const * desc, OBJH * handler, int pw_req_flag, int atomic)
79 {
80  debugs(16, 3, HERE << "registering legacy " << action);
81  const Mgr::ActionProfile::Pointer profile = new Mgr::ActionProfile(action,
82  desc, pw_req_flag, atomic, new Mgr::FunActionCreator(handler));
83  registerProfile(profile);
84 }
85 
92 void
93 CacheManager::registerProfile(char const * action, char const * desc,
95  int pw_req_flag, int atomic)
96 {
98  desc, pw_req_flag, atomic, new ClassActionCreator(handler));
99  registerProfile(profile);
100 }
101 
109 CacheManager::findAction(char const * action) const
110 {
111  Must(action != NULL);
112  Menu::const_iterator a;
113 
114  debugs(16, 5, "CacheManager::findAction: looking for action " << action);
115  for (a = menu_.begin(); a != menu_.end(); ++a) {
116  if (0 == strcmp((*a)->name, action)) {
117  debugs(16, 6, " found");
118  return *a;
119  }
120  }
121 
122  debugs(16, 6, "Action not found.");
123  return Mgr::ActionProfilePointer();
124 }
125 
127 CacheManager::createNamedAction(const char *actionName)
128 {
129  Must(actionName);
130 
132  cmd->profile = findAction(actionName);
133  cmd->params.actionName = actionName;
134 
135  Must(cmd->profile != NULL);
136  return cmd->profile->creator->create(cmd);
137 }
138 
141 {
143  cmd->params = params;
144  cmd->profile = findAction(params.actionName.termedBuf());
145  Must(cmd->profile != NULL);
146  return cmd->profile->creator->create(cmd);
147 }
148 
158 CacheManager::ParseUrl(const char *url)
159 {
160  int t;
161  LOCAL_ARRAY(char, host, MAX_URL);
162  LOCAL_ARRAY(char, request, MAX_URL);
163  LOCAL_ARRAY(char, password, MAX_URL);
164  LOCAL_ARRAY(char, params, MAX_URL);
165  host[0] = 0;
166  request[0] = 0;
167  password[0] = 0;
168  params[0] = 0;
169  int pos = -1;
170  int len = strlen(url);
171  Must(len > 0);
172  t = sscanf(url, "cache_object://%[^/]/%[^@?]%n@%[^?]?%s", host, request, &pos, password, params);
173  if (t < 3) {
174  t = sscanf(url, "cache_object://%[^/]/%[^?]%n?%s", host, request, &pos, params);
175  }
176  if (t < 1) {
177  t = sscanf(url, "http://%[^/]/squid-internal-mgr/%[^?]%n?%s", host, request, &pos, params);
178  }
179  if (t < 1) {
180  t = sscanf(url, "https://%[^/]/squid-internal-mgr/%[^?]%n?%s", host, request, &pos, params);
181  }
182  if (t < 2) {
183  if (strncmp("cache_object://",url,15)==0)
184  xstrncpy(request, "menu", MAX_URL);
185  else
186  xstrncpy(request, "index", MAX_URL);
187  }
188 
189 #if _SQUID_OS2_
190  if (t == 2 && request[0] == '\0') {
191  /*
192  * emx's sscanf insists of returning 2 because it sets request
193  * to null
194  */
195  if (strncmp("cache_object://",url,15)==0)
196  xstrncpy(request, "menu", MAX_URL);
197  else
198  xstrncpy(request, "index", MAX_URL);
199  }
200 #endif
201 
202  debugs(16, 3, HERE << "MGR request: t=" << t << ", host='" << host << "', request='" << request << "', pos=" << pos <<
203  ", password='" << password << "', params='" << params << "'");
204 
205  Mgr::ActionProfile::Pointer profile = findAction(request);
206  if (!profile) {
207  debugs(16, DBG_IMPORTANT, "CacheManager::ParseUrl: action '" << request << "' not found");
208  return NULL;
209  }
210 
211  const char *prot = ActionProtection(profile);
212  if (!strcmp(prot, "disabled") || !strcmp(prot, "hidden")) {
213  debugs(16, DBG_IMPORTANT, "CacheManager::ParseUrl: action '" << request << "' is " << prot);
214  return NULL;
215  }
216 
218  if (!Mgr::QueryParams::Parse(params, cmd->params.queryParams))
219  return NULL;
220  cmd->profile = profile;
221  cmd->params.httpUri = url;
222  cmd->params.userName = String();
223  cmd->params.password = password;
224  cmd->params.actionName = request;
225  return cmd;
226 }
227 
229 /*
230  \ingroup CacheManagerInternal
231  * Decodes the headers needed to perform user authentication and fills
232  * the details into the cachemgrStateData argument
233  */
234 void
236 {
237  assert(request);
238 
239  params.httpMethod = request->method.id();
240  params.httpFlags = request->flags;
241 
242 #if HAVE_AUTH_MODULE_BASIC
243  // TODO: use the authentication system decode to retrieve these details properly.
244 
245  /* base 64 _decoded_ user:passwd pair */
246  const char *basic_cookie = request->header.getAuth(Http::HdrType::AUTHORIZATION, "Basic");
247 
248  if (!basic_cookie)
249  return;
250 
251  const char *passwd_del;
252  if (!(passwd_del = strchr(basic_cookie, ':'))) {
253  debugs(16, DBG_IMPORTANT, "CacheManager::ParseHeaders: unknown basic_cookie format '" << basic_cookie << "'");
254  return;
255  }
256 
257  /* found user:password pair, reset old values */
258  params.userName.limitInit(basic_cookie, passwd_del - basic_cookie);
259  params.password = passwd_del + 1;
260 
261  /* warning: this prints decoded password which maybe not be what you want to do @?@ @?@ */
262  debugs(16, 9, "CacheManager::ParseHeaders: got user: '" <<
263  params.userName << "' passwd: '" << params.password << "'");
264 #endif
265 }
266 
274 int
276 {
277  assert(cmd.profile != NULL);
278  const char *action = cmd.profile->name;
279  char *pwd = PasswdGet(Config.passwd_list, action);
280 
281  debugs(16, 4, "CacheManager::CheckPassword for action " << action);
282 
283  if (pwd == NULL)
284  return cmd.profile->isPwReq;
285 
286  if (strcmp(pwd, "disable") == 0)
287  return 1;
288 
289  if (strcmp(pwd, "none") == 0)
290  return 0;
291 
292  if (!cmd.params.password.size())
293  return 1;
294 
295  return cmd.params.password != pwd;
296 }
297 
304 void
306 {
307  debugs(16, 3, "CacheManager::Start: '" << entry->url() << "'" );
308 
309  Mgr::Command::Pointer cmd = ParseUrl(entry->url());
310  if (!cmd) {
312  err->url = xstrdup(entry->url());
313  errorAppendEntry(entry, err);
314  entry->expires = squid_curtime;
315  return;
316  }
317 
318  const char *actionName = cmd->profile->name;
319 
320  entry->expires = squid_curtime;
321 
322  debugs(16, 5, "CacheManager: " << client << " requesting '" << actionName << "'");
323 
324  /* get additional info from request headers */
325  ParseHeaders(request, cmd->params);
326 
327  const char *userName = cmd->params.userName.size() ?
328  cmd->params.userName.termedBuf() : "unknown";
329 
330  /* Check password */
331 
332  if (CheckPassword(*cmd) != 0) {
333  /* build error message */
335  /* warn if user specified incorrect password */
336 
337  if (cmd->params.password.size()) {
338  debugs(16, DBG_IMPORTANT, "CacheManager: " <<
339  userName << "@" <<
340  client << ": incorrect password for '" <<
341  actionName << "'" );
342  } else {
343  debugs(16, DBG_IMPORTANT, "CacheManager: " <<
344  userName << "@" <<
345  client << ": password needed for '" <<
346  actionName << "'" );
347  }
348 
349  HttpReply *rep = errState.BuildHttpReply();
350 
351 #if HAVE_AUTH_MODULE_BASIC
352  /*
353  * add Authenticate header using action name as a realm because
354  * password depends on the action
355  */
356  rep->header.putAuth("Basic", actionName);
357 #endif
358  // Allow cachemgr and other XHR scripts access to our version string
359  if (request->header.has(Http::HdrType::ORIGIN)) {
360  rep->header.putExt("Access-Control-Allow-Origin",request->header.getStr(Http::HdrType::ORIGIN));
361 #if HAVE_AUTH_MODULE_BASIC
362  rep->header.putExt("Access-Control-Allow-Credentials","true");
363 #endif
364  rep->header.putExt("Access-Control-Expose-Headers","Server");
365  }
366 
367  /* store the reply */
368  entry->replaceHttpReply(rep);
369 
370  entry->expires = squid_curtime;
371 
372  entry->complete();
373 
374  return;
375  }
376 
377  if (request->header.has(Http::HdrType::ORIGIN)) {
378  cmd->params.httpOrigin = request->header.getStr(Http::HdrType::ORIGIN);
379  }
380 
381  debugs(16, 2, "CacheManager: " <<
382  userName << "@" <<
383  client << " requesting '" <<
384  actionName << "'" );
385 
386  // special case: /squid-internal-mgr/ index page
387  if (!strcmp(cmd->profile->name, "index")) {
388  ErrorState err(MGR_INDEX, Http::scOkay, request);
389  err.url = xstrdup(entry->url());
390  HttpReply *rep = err.BuildHttpReply();
391  if (strncmp(rep->body.content(),"Internal Error:", 15) == 0)
393  // Allow cachemgr and other XHR scripts access to our version string
394  if (request->header.has(Http::HdrType::ORIGIN)) {
395  rep->header.putExt("Access-Control-Allow-Origin",request->header.getStr(Http::HdrType::ORIGIN));
396 #if HAVE_AUTH_MODULE_BASIC
397  rep->header.putExt("Access-Control-Allow-Credentials","true");
398 #endif
399  rep->header.putExt("Access-Control-Expose-Headers","Server");
400  }
401  entry->replaceHttpReply(rep);
402  entry->complete();
403  return;
404  }
405 
406  if (UsingSmp() && IamWorkerProcess()) {
407  // is client the right connection to pass here?
408  AsyncJob::Start(new Mgr::Forwarder(client, cmd->params, request, entry));
409  return;
410  }
411 
412  Mgr::Action::Pointer action = cmd->profile->creator->create(cmd);
413  Must(action != NULL);
414  action->run(entry, true);
415 }
416 
417 /*
418  \ingroup CacheManagerInternal
419  * Renders the protection level text for an action.
420  * Also doubles as a check for the protection level.
421  */
422 const char *
424 {
425  assert(profile != NULL);
426  const char *pwd = PasswdGet(Config.passwd_list, profile->name);
427 
428  if (!pwd)
429  return profile->isPwReq ? "hidden" : "public";
430 
431  if (!strcmp(pwd, "disable"))
432  return "disabled";
433 
434  if (strcmp(pwd, "none") == 0)
435  return "public";
436 
437  return "protected";
438 }
439 
440 /*
441  * \ingroup CacheManagerInternal
442  * gets from the global Config the password the user would need to supply
443  * for the action she queried
444  */
445 char *
447 {
448  while (a) {
449  for (auto &w : a->actions) {
450  if (w.cmp(action) == 0)
451  return a->passwd;
452 
453  static const SBuf allAction("all");
454  if (w == allAction)
455  return a->passwd;
456  }
457 
458  a = a->next;
459  }
460 
461  return NULL;
462 }
463 
466 {
467  static CacheManager *instance = nullptr;
468  if (!instance) {
469  debugs(16, 6, "starting cachemanager up");
470  instance = new CacheManager;
472  }
473  return instance;
474 }
475 
AnyP::ProtocolVersion ProtocolVersion(unsigned int aMajor, unsigned int aMinor)
HTTP version label information.
void limitInit(const char *str, int len)
Definition: String.cc:94
#define assert(EX)
Definition: assert.h:17
ClassActionCreator(Handler *aHandler)
const char * getAuth(Http::HdrType id, const char *auth_scheme) const
Definition: HttpHeader.cc:1327
String actionName
action name (and credentials realm)
Definition: ActionParams.h:39
void set(const AnyP::ProtocolVersion &newVersion, Http::StatusCode newStatus, const char *newReason=NULL)
Definition: StatusLine.cc:30
Definition: SBuf.h:86
HttpRequestMethod method
Definition: HttpRequest.h:106
struct _request * request(char *urlin)
Definition: tcp-banger2.c:291
#define xstrdup
void putExt(const char *name, const char *value)
Definition: HttpHeader.cc:1161
char * url
Definition: errorpage.h:148
creates FunAction using ActionCreator API
Definition: FunAction.h:44
#define Must(condition)
Like assert() but throws an exception instead of aborting the process.
Definition: TextException.h:69
String password
user password; used for acceptance check and cleared
Definition: ActionParams.h:41
void OBJH(StoreEntry *)
Definition: forward.h:44
Mgr::Action::Pointer Handler(const Mgr::Command::Pointer &cmd)
creates Action using supplied Action::Create method and command
Command
what kind of I/O the disker needs to do or have done
Definition: IpcIoFile.h:33
int CheckPassword(const Mgr::Command &cmd)
time_t expires
Definition: Store.h:202
static bool Parse(const String &aParamsStr, QueryParams &aParams)
parses the query string parameters
Definition: QueryParams.cc:102
bool IamWorkerProcess()
whether the current process handles HTTP transactions and such
Definition: stub_tools.cc:49
time_t squid_curtime
Definition: stub_time.cc:17
Cache Manager Action parameters extracted from the user request.
Definition: ActionParams.h:23
void Start(const Comm::ConnectionPointer &client, HttpRequest *request, StoreEntry *entry)
void replaceHttpReply(HttpReply *, bool andStartWriting=true)
Definition: store.cc:1782
static CacheManager * GetInstance()
void complete()
Definition: store.cc:1058
static Pointer Start(AsyncJob *job)
starts a freshly created job (i.e., makes the job asynchronous)
Definition: AsyncJob.cc:23
const char * ActionProtection(const Mgr::ActionProfilePointer &profile)
list of cachemgr password authorization definitions. Currently a POD.
hard-coded Cache Manager action configuration, including Action creator
Definition: ActionProfile.h:21
#define debugs(SECTION, LEVEL, CONTENT)
Definition: Debug.h:124
const char * url() const
Definition: store.cc:1600
#define DBG_IMPORTANT
Definition: Debug.h:46
HttpRequestMethod httpMethod
HTTP request method.
Definition: ActionParams.h:34
char * PasswdGet(Mgr::ActionPasswordList *, const char *)
virtual Mgr::Action::Pointer create(const Mgr::Command::Pointer &cmd) const
returns a pointer to the new Action object for cmd; never nil
char * xstrncpy(char *dst, const char *src, size_t n)
Definition: xstring.cc:37
Mgr::Action::Pointer createRequestedAction(const Mgr::ActionParams &)
Http::StatusLine sline
Definition: HttpReply.h:60
Http::MethodType id() const
Definition: RequestMethod.h:73
Mgr::CommandPointer ParseUrl(const char *url)
#define LOCAL_ARRAY(type, name, size)
Definition: leakcheck.h:18
char const * termedBuf() const
Definition: SquidString.h:91
int unsigned int const char *desc STUB void int len
Definition: stub_fd.cc:20
const char * getStr(Http::HdrType id) const
Definition: HttpHeader.cc:1212
bool UsingSmp()
Whether there should be more than one worker process running.
Definition: tools.cc:658
std::ostream & HERE(std::ostream &s)
Definition: Debug.h:153
Mgr::Action::Pointer createNamedAction(const char *actionName)
void ParseHeaders(const HttpRequest *request, Mgr::ActionParams &params)
bool action(int fd, size_t metasize, const char *fn, const char *url, const SquidMetaList &meta)
Definition: purge.cc:311
RefCount< ActionProfile > ActionProfilePointer
Definition: forward.h:32
combined hard-coded action profile with user-supplied action parameters
Definition: Command.h:21
HttpHeader header
Definition: Message.h:75
RequestFlags flags
Definition: HttpRequest.h:133
int has(Http::HdrType id) const
Definition: HttpHeader.cc:1011
ActionPasswordList * next
static CacheManager * instance
void registerProfile(char const *action, char const *desc, OBJH *handler, int pw_req_flag, int atomic)
void errorAppendEntry(StoreEntry *entry, ErrorState *err)
Definition: errorpage.cc:575
ActionParams params
user-supplied action arguments
Definition: Command.h:28
int a
Definition: membanger.c:50
RequestFlags httpFlags
HTTP request flags.
Definition: ActionParams.h:35
Mgr::ActionProfilePointer findAction(char const *action) const
HttpReply * BuildHttpReply(void)
Definition: errorpage.cc:1111
ActionProfilePointer profile
hard-coded action specification
Definition: Command.h:27
#define MAX_URL
Definition: defines.h:118
void RegisterBasics()
Registeres profiles for the actions above;.
String userName
user login name; currently only used for logging
Definition: ActionParams.h:40
size_type size() const
Definition: SquidString.h:72
void putAuth(const char *auth_scheme, const char *realm)
Definition: HttpHeader.cc:1081
class SquidConfig Config
Definition: SquidConfig.cc:12
Mgr::ActionPasswordList * passwd_list
Definition: SquidConfig.h:261
#define NULL
Definition: types.h:166

 

Introduction

Documentation

Support

Miscellaneous

Web Site Translations

Mirrors