cache_manager.cc
Go to the documentation of this file.
1 /*
2  * Copyright (C) 1996-2019 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 "AccessLogEntry.h"
13 #include "base/TextException.h"
14 #include "CacheManager.h"
15 #include "comm/Connection.h"
16 #include "Debug.h"
17 #include "errorpage.h"
18 #include "fde.h"
19 #include "HttpReply.h"
20 #include "HttpRequest.h"
21 #include "mgr/Action.h"
22 #include "mgr/ActionCreator.h"
23 #include "mgr/ActionPasswordList.h"
24 #include "mgr/ActionProfile.h"
25 #include "mgr/BasicActions.h"
26 #include "mgr/Command.h"
27 #include "mgr/Forwarder.h"
28 #include "mgr/FunAction.h"
29 #include "mgr/QueryParams.h"
30 #include "protos.h"
31 #include "sbuf/StringConvert.h"
32 #include "SquidConfig.h"
33 #include "SquidTime.h"
34 #include "Store.h"
35 #include "tools.h"
36 #include "wordlist.h"
37 
38 #include <algorithm>
39 
41 #define MGR_PASSWD_SZ 128
42 
45 {
46 public:
48 
49 public:
50  ClassActionCreator(Handler *aHandler): handler(aHandler) {}
51 
53  return handler(cmd);
54  }
55 
56 private:
58 };
59 
61 void
63 {
64  Must(profile != NULL);
65  if (!CacheManager::findAction(profile->name)) {
66  menu_.push_back(profile);
67  debugs(16, 3, HERE << "registered profile: " << *profile);
68  } else {
69  debugs(16, 2, HERE << "skipped duplicate profile: " << *profile);
70  }
71 }
72 
79 void
80 CacheManager::registerProfile(char const * action, char const * desc, OBJH * handler, int pw_req_flag, int atomic)
81 {
82  debugs(16, 3, HERE << "registering legacy " << action);
83  const Mgr::ActionProfile::Pointer profile = new Mgr::ActionProfile(action,
84  desc, pw_req_flag, atomic, new Mgr::FunActionCreator(handler));
85  registerProfile(profile);
86 }
87 
94 void
95 CacheManager::registerProfile(char const * action, char const * desc,
97  int pw_req_flag, int atomic)
98 {
100  desc, pw_req_flag, atomic, new ClassActionCreator(handler));
101  registerProfile(profile);
102 }
103 
111 CacheManager::findAction(char const * action) const
112 {
113  Must(action != NULL);
114  Menu::const_iterator a;
115 
116  debugs(16, 5, "CacheManager::findAction: looking for action " << action);
117  for (a = menu_.begin(); a != menu_.end(); ++a) {
118  if (0 == strcmp((*a)->name, action)) {
119  debugs(16, 6, " found");
120  return *a;
121  }
122  }
123 
124  debugs(16, 6, "Action not found.");
125  return Mgr::ActionProfilePointer();
126 }
127 
129 CacheManager::createNamedAction(const char *actionName)
130 {
131  Must(actionName);
132 
134  cmd->profile = findAction(actionName);
135  cmd->params.actionName = actionName;
136 
137  Must(cmd->profile != NULL);
138  return cmd->profile->creator->create(cmd);
139 }
140 
143 {
145  cmd->params = params;
146  cmd->profile = findAction(params.actionName.termedBuf());
147  Must(cmd->profile != NULL);
148  return cmd->profile->creator->create(cmd);
149 }
150 
160 CacheManager::ParseUrl(const char *url)
161 {
162  int t;
163  LOCAL_ARRAY(char, host, MAX_URL);
164  LOCAL_ARRAY(char, request, MAX_URL);
165  LOCAL_ARRAY(char, password, MAX_URL);
166  LOCAL_ARRAY(char, params, MAX_URL);
167  host[0] = 0;
168  request[0] = 0;
169  password[0] = 0;
170  params[0] = 0;
171  int pos = -1;
172  int len = strlen(url);
173  Must(len > 0);
174  t = sscanf(url, "cache_object://%[^/]/%[^@?]%n@%[^?]?%s", host, request, &pos, password, params);
175  if (t < 3) {
176  t = sscanf(url, "cache_object://%[^/]/%[^?]%n?%s", host, request, &pos, params);
177  }
178  if (t < 1) {
179  t = sscanf(url, "http://%[^/]/squid-internal-mgr/%[^?]%n?%s", host, request, &pos, params);
180  }
181  if (t < 1) {
182  t = sscanf(url, "https://%[^/]/squid-internal-mgr/%[^?]%n?%s", host, request, &pos, params);
183  }
184  if (t < 2) {
185  if (strncmp("cache_object://",url,15)==0)
186  xstrncpy(request, "menu", MAX_URL);
187  else
188  xstrncpy(request, "index", MAX_URL);
189  }
190 
191 #if _SQUID_OS2_
192  if (t == 2 && request[0] == '\0') {
193  /*
194  * emx's sscanf insists of returning 2 because it sets request
195  * to null
196  */
197  if (strncmp("cache_object://",url,15)==0)
198  xstrncpy(request, "menu", MAX_URL);
199  else
200  xstrncpy(request, "index", MAX_URL);
201  }
202 #endif
203 
204  debugs(16, 3, HERE << "MGR request: t=" << t << ", host='" << host << "', request='" << request << "', pos=" << pos <<
205  ", password='" << password << "', params='" << params << "'");
206 
207  Mgr::ActionProfile::Pointer profile = findAction(request);
208  if (!profile) {
209  debugs(16, DBG_IMPORTANT, "CacheManager::ParseUrl: action '" << request << "' not found");
210  return NULL;
211  }
212 
213  const char *prot = ActionProtection(profile);
214  if (!strcmp(prot, "disabled") || !strcmp(prot, "hidden")) {
215  debugs(16, DBG_IMPORTANT, "CacheManager::ParseUrl: action '" << request << "' is " << prot);
216  return NULL;
217  }
218 
220  if (!Mgr::QueryParams::Parse(params, cmd->params.queryParams))
221  return NULL;
222  cmd->profile = profile;
223  cmd->params.httpUri = url;
224  cmd->params.userName = String();
225  cmd->params.password = password;
226  cmd->params.actionName = request;
227  return cmd;
228 }
229 
231 /*
232  \ingroup CacheManagerInternal
233  * Decodes the headers needed to perform user authentication and fills
234  * the details into the cachemgrStateData argument
235  */
236 void
238 {
239  assert(request);
240 
241  params.httpMethod = request->method.id();
242  params.httpFlags = request->flags;
243 
244 #if HAVE_AUTH_MODULE_BASIC
245  // TODO: use the authentication system decode to retrieve these details properly.
246 
247  /* base 64 _decoded_ user:passwd pair */
248  const auto basic_cookie(request->header.getAuthToken(Http::HdrType::AUTHORIZATION, "Basic"));
249 
250  if (basic_cookie.isEmpty())
251  return;
252 
253  const auto colonPos = basic_cookie.find(':');
254  if (colonPos == SBuf::npos) {
255  debugs(16, DBG_IMPORTANT, "CacheManager::ParseHeaders: unknown basic_cookie format '" << basic_cookie << "'");
256  return;
257  }
258 
259  /* found user:password pair, reset old values */
260  params.userName = SBufToString(basic_cookie.substr(0, colonPos));
261  params.password = SBufToString(basic_cookie.substr(colonPos+1));
262 
263  /* warning: this prints decoded password which maybe not be what you want to do @?@ @?@ */
264  debugs(16, 9, "CacheManager::ParseHeaders: got user: '" <<
265  params.userName << "' passwd: '" << params.password << "'");
266 #endif
267 }
268 
276 int
278 {
279  assert(cmd.profile != NULL);
280  const char *action = cmd.profile->name;
281  char *pwd = PasswdGet(Config.passwd_list, action);
282 
283  debugs(16, 4, "CacheManager::CheckPassword for action " << action);
284 
285  if (pwd == NULL)
286  return cmd.profile->isPwReq;
287 
288  if (strcmp(pwd, "disable") == 0)
289  return 1;
290 
291  if (strcmp(pwd, "none") == 0)
292  return 0;
293 
294  if (!cmd.params.password.size())
295  return 1;
296 
297  return cmd.params.password != pwd;
298 }
299 
306 void
308 {
309  debugs(16, 3, "CacheManager::Start: '" << entry->url() << "'" );
310 
311  Mgr::Command::Pointer cmd = ParseUrl(entry->url());
312  if (!cmd) {
313  const auto err = new ErrorState(ERR_INVALID_URL, Http::scNotFound, request, ale);
314  err->url = xstrdup(entry->url());
315  errorAppendEntry(entry, err);
316  entry->expires = squid_curtime;
317  return;
318  }
319 
320  const char *actionName = cmd->profile->name;
321 
322  entry->expires = squid_curtime;
323 
324  debugs(16, 5, "CacheManager: " << client << " requesting '" << actionName << "'");
325 
326  /* get additional info from request headers */
327  ParseHeaders(request, cmd->params);
328 
329  const char *userName = cmd->params.userName.size() ?
330  cmd->params.userName.termedBuf() : "unknown";
331 
332  /* Check password */
333 
334  if (CheckPassword(*cmd) != 0) {
335  /* build error message */
337  /* warn if user specified incorrect password */
338 
339  if (cmd->params.password.size()) {
340  debugs(16, DBG_IMPORTANT, "CacheManager: " <<
341  userName << "@" <<
342  client << ": incorrect password for '" <<
343  actionName << "'" );
344  } else {
345  debugs(16, DBG_IMPORTANT, "CacheManager: " <<
346  userName << "@" <<
347  client << ": password needed for '" <<
348  actionName << "'" );
349  }
350 
351  HttpReply *rep = errState.BuildHttpReply();
352 
353 #if HAVE_AUTH_MODULE_BASIC
354  /*
355  * add Authenticate header using action name as a realm because
356  * password depends on the action
357  */
358  rep->header.putAuth("Basic", actionName);
359 #endif
360  // Allow cachemgr and other XHR scripts access to our version string
361  if (request->header.has(Http::HdrType::ORIGIN)) {
362  rep->header.putExt("Access-Control-Allow-Origin",request->header.getStr(Http::HdrType::ORIGIN));
363 #if HAVE_AUTH_MODULE_BASIC
364  rep->header.putExt("Access-Control-Allow-Credentials","true");
365 #endif
366  rep->header.putExt("Access-Control-Expose-Headers","Server");
367  }
368 
369  /* store the reply */
370  entry->replaceHttpReply(rep);
371 
372  entry->expires = squid_curtime;
373 
374  entry->complete();
375 
376  return;
377  }
378 
379  if (request->header.has(Http::HdrType::ORIGIN)) {
380  cmd->params.httpOrigin = request->header.getStr(Http::HdrType::ORIGIN);
381  }
382 
383  debugs(16, 2, "CacheManager: " <<
384  userName << "@" <<
385  client << " requesting '" <<
386  actionName << "'" );
387 
388  // special case: /squid-internal-mgr/ index page
389  if (!strcmp(cmd->profile->name, "index")) {
390  ErrorState err(MGR_INDEX, Http::scOkay, request, ale);
391  err.url = xstrdup(entry->url());
392  HttpReply *rep = err.BuildHttpReply();
393  if (strncmp(rep->body.content(),"Internal Error:", 15) == 0)
395  // Allow cachemgr and other XHR scripts access to our version string
396  if (request->header.has(Http::HdrType::ORIGIN)) {
397  rep->header.putExt("Access-Control-Allow-Origin",request->header.getStr(Http::HdrType::ORIGIN));
398 #if HAVE_AUTH_MODULE_BASIC
399  rep->header.putExt("Access-Control-Allow-Credentials","true");
400 #endif
401  rep->header.putExt("Access-Control-Expose-Headers","Server");
402  }
403  entry->replaceHttpReply(rep);
404  entry->complete();
405  return;
406  }
407 
408  if (UsingSmp() && IamWorkerProcess()) {
409  // is client the right connection to pass here?
410  AsyncJob::Start(new Mgr::Forwarder(client, cmd->params, request, entry, ale));
411  return;
412  }
413 
414  Mgr::Action::Pointer action = cmd->profile->creator->create(cmd);
415  Must(action != NULL);
416  action->run(entry, true);
417 }
418 
419 /*
420  \ingroup CacheManagerInternal
421  * Renders the protection level text for an action.
422  * Also doubles as a check for the protection level.
423  */
424 const char *
426 {
427  assert(profile != NULL);
428  const char *pwd = PasswdGet(Config.passwd_list, profile->name);
429 
430  if (!pwd)
431  return profile->isPwReq ? "hidden" : "public";
432 
433  if (!strcmp(pwd, "disable"))
434  return "disabled";
435 
436  if (strcmp(pwd, "none") == 0)
437  return "public";
438 
439  return "protected";
440 }
441 
442 /*
443  * \ingroup CacheManagerInternal
444  * gets from the global Config the password the user would need to supply
445  * for the action she queried
446  */
447 char *
449 {
450  while (a) {
451  for (auto &w : a->actions) {
452  if (w.cmp(action) == 0)
453  return a->passwd;
454 
455  static const SBuf allAction("all");
456  if (w == allAction)
457  return a->passwd;
458  }
459 
460  a = a->next;
461  }
462 
463  return NULL;
464 }
465 
468 {
469  static CacheManager *instance = nullptr;
470  if (!instance) {
471  debugs(16, 6, "starting cachemanager up");
472  instance = new CacheManager;
474  }
475  return instance;
476 }
477 
AnyP::ProtocolVersion ProtocolVersion(unsigned int aMajor, unsigned int aMinor)
HTTP version label information.
#define assert(EX)
Definition: assert.h:17
ClassActionCreator(Handler *aHandler)
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:114
struct _request * request(char *urlin)
Definition: tcp-banger2.c:291
#define xstrdup
void putExt(const char *name, const char *value)
Definition: HttpHeader.cc:1127
char * url
Definition: errorpage.h:179
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:204
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 replaceHttpReply(HttpReply *, bool andStartWriting=true)
Definition: store.cc:1788
static CacheManager * GetInstance()
void complete()
Definition: store.cc:1064
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
String SBufToString(const SBuf &s)
Definition: StringConvert.h:26
const char * url() const
Definition: store.cc:1606
#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
void start(const Comm::ConnectionPointer &client, HttpRequest *request, StoreEntry *entry, const AccessLogEntryPointer &ale)
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:1178
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:141
int has(Http::HdrType id) const
Definition: HttpHeader.cc:977
ActionPasswordList * next
static CacheManager * instance
static const size_type npos
Definition: SBuf.h:92
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:711
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:1281
ActionProfilePointer profile
hard-coded action specification
Definition: Command.h:27
#define MAX_URL
Definition: defines.h:118
SBuf getAuthToken(Http::HdrType id, const char *auth_scheme) const
Definition: HttpHeader.cc:1293
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:1047
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