XRootD
XrdMacaroonsAuthz.cc
Go to the documentation of this file.
1 #include "XrdMacaroonsAuthz.hh"
2 #include "XrdMacaroonsHandler.hh"
3 
4 #include "XrdOuc/XrdOucEnv.hh"
6 #include "XrdOuc/XrdOucUtils.hh"
7 #include "XrdSec/XrdSecEntity.hh"
9 
10 #include <ctime>
11 #include <sstream>
12 #include <stdexcept>
13 
14 #include <macaroons.h>
15 
16 using namespace Macaroons;
17 
18 namespace {
19 
20 class AuthzCheck
21 {
22 public:
23  AuthzCheck(const char *req_path, const Access_Operation req_oper, ssize_t max_duration, XrdSysError &log);
24 
25  const std::string &GetSecName() const {return m_sec_name;}
26  const std::string &GetErrorMessage() const {return m_emsg;}
27 
28  static int verify_before_s(void *authz_ptr,
29  const unsigned char *pred,
30  size_t pred_sz);
31 
32  static int verify_activity_s(void *authz_ptr,
33  const unsigned char *pred,
34  size_t pred_sz);
35 
36  static int verify_path_s(void *authz_ptr,
37  const unsigned char *pred,
38  size_t pred_sz);
39 
40  static int verify_name_s(void *authz_ptr,
41  const unsigned char *pred,
42  size_t pred_sz);
43 
44 private:
45  int verify_before(const unsigned char *pred, size_t pred_sz);
46  int verify_activity(const unsigned char *pred, size_t pred_sz);
47  int verify_path(const unsigned char *pred, size_t pred_sz);
48  int verify_name(const unsigned char *pred, size_t pred_sz);
49 
50  ssize_t m_max_duration;
51  XrdSysError &m_log;
52  std::string m_emsg;
53  const std::string m_path;
54  std::string m_desired_activity;
55  std::string m_sec_name;
56  Access_Operation m_oper;
57  time_t m_now;
58 };
59 
60 static XrdAccPrivs AddPriv(Access_Operation op, XrdAccPrivs privs)
61 {
62  int new_privs = privs;
63  switch (op) {
64  case AOP_Any:
65  break;
66  case AOP_Chmod:
67  new_privs |= static_cast<int>(XrdAccPriv_Chmod);
68  break;
69  case AOP_Chown:
70  new_privs |= static_cast<int>(XrdAccPriv_Chown);
71  break;
72  case AOP_Excl_Create: // fallthrough
73  case AOP_Create:
74  new_privs |= static_cast<int>(XrdAccPriv_Create);
75  break;
76  case AOP_Delete:
77  new_privs |= static_cast<int>(XrdAccPriv_Delete);
78  break;
79  case AOP_Excl_Insert: // fallthrough
80  case AOP_Insert:
81  new_privs |= static_cast<int>(XrdAccPriv_Insert);
82  break;
83  case AOP_Lock:
84  new_privs |= static_cast<int>(XrdAccPriv_Lock);
85  break;
86  case AOP_Mkdir:
87  new_privs |= static_cast<int>(XrdAccPriv_Mkdir);
88  break;
89  case AOP_Read:
90  new_privs |= static_cast<int>(XrdAccPriv_Read);
91  break;
92  case AOP_Readdir:
93  new_privs |= static_cast<int>(XrdAccPriv_Readdir);
94  break;
95  case AOP_Rename:
96  new_privs |= static_cast<int>(XrdAccPriv_Rename);
97  break;
98  case AOP_Stat:
99  new_privs |= static_cast<int>(XrdAccPriv_Lookup);
100  break;
101  case AOP_Update:
102  new_privs |= static_cast<int>(XrdAccPriv_Update);
103  break;
104  case AOP_Stage:
105  new_privs |= static_cast<int>(XrdAccPriv_Stage);
106  break;
107  case AOP_Poll:
108  new_privs |= static_cast<int>(XrdAccPriv_Poll);
109  break;
110  };
111  return static_cast<XrdAccPrivs>(new_privs);
112 }
113 
114 // Accept any value of the path, name, or activity caveats
115 int validate_verify_empty(void *emsg_ptr,
116  const unsigned char *pred,
117  size_t pred_sz)
118 {
119  if ((pred_sz >= 5) && (!memcmp(reinterpret_cast<const char *>(pred), "path:", 5) ||
120  !memcmp(reinterpret_cast<const char *>(pred), "name:", 5)))
121  {
122  return 0;
123  }
124  if ((pred_sz >= 9) && (!memcmp(reinterpret_cast<const char *>(pred), "activity:", 9)))
125  {
126  return 0;
127  }
128  return 1;
129 }
130 
131 } // unnamed namespace
132 
133 Authz::Authz(XrdSysLogger *log, char const *config, XrdAccAuthorize *chain)
134  : m_max_duration(86400),
135  m_chain(chain),
136  m_log(log, "macarons_"),
137  m_authz_behavior(static_cast<int>(Handler::AuthzBehavior::PASSTHROUGH))
138 {
139  Handler::AuthzBehavior behavior(Handler::AuthzBehavior::PASSTHROUGH);
140  XrdOucEnv env;
141  if (!Handler::Config(config, &env, &m_log, m_location, m_secret, m_max_duration, behavior))
142  {
143  throw std::runtime_error("Macaroon authorization config failed.");
144  }
145  m_authz_behavior = static_cast<int>(behavior);
146 }
147 
149 Authz::OnMissing(const XrdSecEntity *Entity, const char *path,
150  const Access_Operation oper, XrdOucEnv *env)
151 {
152  switch (m_authz_behavior) {
153  case Handler::AuthzBehavior::PASSTHROUGH:
154  return m_chain ? m_chain->Access(Entity, path, oper, env) : XrdAccPriv_None;
155  case Handler::AuthzBehavior::ALLOW:
156  return AddPriv(oper, XrdAccPriv_None);;
157  case Handler::AuthzBehavior::DENY:
158  return XrdAccPriv_None;
159  }
160  // Code should be unreachable.
161  return XrdAccPriv_None;
162 }
163 
165 Authz::Access(const XrdSecEntity *Entity, const char *path,
166  const Access_Operation oper, XrdOucEnv *env)
167 {
168  // We don't allow any testing to occur in this authz module, preventing
169  // a macaroon to be used to receive further macaroons.
170  if (oper == AOP_Any)
171  {
172  return m_chain ? m_chain->Access(Entity, path, oper, env) : XrdAccPriv_None;
173  }
174 
175  const char *authz = env ? env->Get("authz") : nullptr;
176  if (authz && !strncmp(authz, "Bearer%20", 9))
177  {
178  authz += 9;
179  }
180  else if (!authz && (authz = env ? env->Get("access_token") : nullptr) && !strncmp(authz, "Bearer%20", 9))
181  {
182  authz += 9;
183  }
184 
185  // If there's no request-specific token, check for a ZTN session token
186  if (!authz && Entity && !strcmp("ztn", Entity->prot) && Entity->creds &&
187  Entity->credslen && Entity->creds[Entity->credslen] == '\0')
188  {
189  authz = Entity->creds;
190  }
191 
192  if (!authz) {
193  return OnMissing(Entity, path, oper, env);
194  }
195 
196  macaroon_returncode mac_err = MACAROON_SUCCESS;
197  struct macaroon* macaroon = macaroon_deserialize(
198  authz,
199  &mac_err);
200  if (!macaroon)
201  {
202  // Do not log - might be other token type!
203  //m_log.Emsg("Access", "Failed to parse the macaroon");
204  return OnMissing(Entity, path, oper, env);
205  }
206 
207  struct macaroon_verifier *verifier = macaroon_verifier_create();
208  if (!verifier)
209  {
210  m_log.Emsg("Access", "Failed to create a new macaroon verifier");
211  return XrdAccPriv_None;
212  }
213  if (!path)
214  {
215  m_log.Emsg("Access", "Request with no provided path.");
216  macaroon_verifier_destroy(verifier);
217  return XrdAccPriv_None;
218  }
219 
220  AuthzCheck check_helper(path, oper, m_max_duration, m_log);
221 
222  if (macaroon_verifier_satisfy_general(verifier, AuthzCheck::verify_before_s, &check_helper, &mac_err) ||
223  macaroon_verifier_satisfy_general(verifier, AuthzCheck::verify_activity_s, &check_helper, &mac_err) ||
224  macaroon_verifier_satisfy_general(verifier, AuthzCheck::verify_name_s, &check_helper, &mac_err) ||
225  macaroon_verifier_satisfy_general(verifier, AuthzCheck::verify_path_s, &check_helper, &mac_err))
226  {
227  m_log.Emsg("Access", "Failed to configure caveat verifier:");
228  macaroon_verifier_destroy(verifier);
229  return XrdAccPriv_None;
230  }
231 
232  const unsigned char *macaroon_loc;
233  size_t location_sz;
234  macaroon_location(macaroon, &macaroon_loc, &location_sz);
235  if (strncmp(reinterpret_cast<const char *>(macaroon_loc), m_location.c_str(), location_sz))
236  {
237  std::string location_str(reinterpret_cast<const char *>(macaroon_loc), location_sz);
238  m_log.Emsg("Access", "Macaroon is for incorrect location", location_str.c_str());
239  macaroon_verifier_destroy(verifier);
240  macaroon_destroy(macaroon);
241  return m_chain ? m_chain->Access(Entity, path, oper, env) : XrdAccPriv_None;
242  }
243 
244  if (macaroon_verify(verifier, macaroon,
245  reinterpret_cast<const unsigned char *>(m_secret.c_str()),
246  m_secret.size(),
247  nullptr, 0, // discharge macaroons
248  &mac_err))
249  {
250  m_log.Log(LogMask::Debug, "Access", "Macaroon verification failed");
251  macaroon_verifier_destroy(verifier);
252  macaroon_destroy(macaroon);
253  // This token is from our server (location matched) but caveats or HMAC
254  // failed. Falling through to the chain would let a path-restricted
255  // macaroon bypass its own restrictions. Deny unconditionally.
256  return XrdAccPriv_None;
257  }
258  macaroon_verifier_destroy(verifier);
259 
260  const unsigned char *macaroon_id;
261  size_t id_sz;
262  macaroon_identifier(macaroon, &macaroon_id, &id_sz);
263 
264  std::string macaroon_id_str(reinterpret_cast<const char *>(macaroon_id), id_sz);
265  m_log.Log(LogMask::Info, "Access", "Macaroon verification successful; ID", macaroon_id_str.c_str());
266  macaroon_destroy(macaroon);
267 
268  // Copy the name, if present into the macaroon, into the credential object.
269  if (Entity && check_helper.GetSecName().size()) {
270  const std::string &username = check_helper.GetSecName();
271  m_log.Log(LogMask::Debug, "Access", "Setting the request name to", username.c_str());
272  Entity->eaAPI->Add("request.name", username,true);
273  }
274 
275  // We passed verification - give the correct privilege.
276  return AddPriv(oper, XrdAccPriv_None);
277 }
278 
279 bool Authz::Validate(const char *token,
280  std::string &emsg,
281  long long *expT,
282  XrdSecEntity *entP)
283 {
284  macaroon_returncode mac_err = MACAROON_SUCCESS;
285  std::unique_ptr<struct macaroon, decltype(&macaroon_destroy)> macaroon(
286  macaroon_deserialize(token, &mac_err),
287  &macaroon_destroy);
288 
289  if (!macaroon)
290  {
291  emsg = "Failed to deserialize the token as a macaroon";
292  // Purposely log at debug level in case if this validation is ever
293  // chained so we don't have overly-chatty logs.
294  m_log.Log(LogMask::Debug, "Validate", emsg.c_str());
295  return false;
296  }
297 
298  std::unique_ptr<struct macaroon_verifier, decltype(&macaroon_verifier_destroy)> verifier(
299  macaroon_verifier_create(), &macaroon_verifier_destroy);
300  if (!verifier)
301  {
302  emsg = "Internal error: failed to create a verifier.";
303  m_log.Log(LogMask::Error, "Validate", emsg.c_str());
304  return false;
305  }
306 
307  // Note the path and operation here are ignored as we won't use those validators
308  AuthzCheck check_helper("/", AOP_Read, m_max_duration, m_log);
309 
310  if (macaroon_verifier_satisfy_general(verifier.get(), AuthzCheck::verify_before_s, &check_helper, &mac_err) ||
311  macaroon_verifier_satisfy_general(verifier.get(), validate_verify_empty, nullptr, &mac_err))
312  {
313  emsg = "Failed to configure the verifier";
314  m_log.Log(LogMask::Error, "Validate", emsg.c_str());
315  return false;
316  }
317 
318  const unsigned char *macaroon_loc;
319  size_t location_sz;
320  macaroon_location(macaroon.get(), &macaroon_loc, &location_sz);
321  if (strncmp(reinterpret_cast<const char *>(macaroon_loc), m_location.c_str(), location_sz))
322  {
323  emsg = "Macaroon contains incorrect location: " +
324  std::string(reinterpret_cast<const char *>(macaroon_loc), location_sz);
325  m_log.Log(LogMask::Warning, "Validate", emsg.c_str(), ("all.sitename is " + m_location).c_str());
326  return false;
327  }
328 
329  if (macaroon_verify(verifier.get(), macaroon.get(),
330  reinterpret_cast<const unsigned char *>(m_secret.c_str()),
331  m_secret.size(),
332  nullptr, 0,
333  &mac_err))
334  {
335  emsg = "Macaroon verification error" + (check_helper.GetErrorMessage().size() ?
336  (", " + check_helper.GetErrorMessage()) : "");
337  m_log.Log(LogMask::Warning, "Validate", emsg.c_str());
338  return false;
339  }
340 
341  const unsigned char *macaroon_id;
342  size_t id_sz;
343  macaroon_identifier(macaroon.get(), &macaroon_id, &id_sz);
344  m_log.Log(LogMask::Info, "Validate", ("Macaroon verification successful; ID " +
345  std::string(reinterpret_cast<const char *>(macaroon_id), id_sz)).c_str());
346 
347  return true;
348 }
349 
350 AuthzCheck::AuthzCheck(const char *req_path, const Access_Operation req_oper, ssize_t max_duration, XrdSysError &log)
351  : m_max_duration(max_duration),
352  m_log(log),
353  m_path(XrdOucUtils::NormalizePath(req_path)),
354  m_oper(req_oper),
355  m_now(time(nullptr))
356 {
357  switch (m_oper)
358  {
359  case AOP_Any:
360  break;
361  case AOP_Chmod:
362  case AOP_Chown:
363  m_desired_activity = "UPDATE_METADATA";
364  break;
365  case AOP_Insert:
366  case AOP_Lock:
367  case AOP_Mkdir:
368  case AOP_Update:
369  case AOP_Create:
370  m_desired_activity = "MANAGE";
371  break;
372  case AOP_Rename:
373  case AOP_Excl_Create:
374  case AOP_Excl_Insert:
375  m_desired_activity = "UPLOAD";
376  break;
377  case AOP_Delete:
378  m_desired_activity = "DELETE";
379  break;
380  case AOP_Read:
381  m_desired_activity = "DOWNLOAD";
382  break;
383  case AOP_Readdir:
384  m_desired_activity = "LIST";
385  break;
386  case AOP_Stat:
387  m_desired_activity = "READ_METADATA";
388  break;
389  case AOP_Stage:
390  case AOP_Poll:
391  break;
392  };
393 }
394 
395 int
396 AuthzCheck::verify_before_s(void *authz_ptr,
397  const unsigned char *pred,
398  size_t pred_sz)
399 {
400  return static_cast<AuthzCheck*>(authz_ptr)->verify_before(pred, pred_sz);
401 }
402 
403 int
404 AuthzCheck::verify_activity_s(void *authz_ptr,
405  const unsigned char *pred,
406  size_t pred_sz)
407 {
408  return static_cast<AuthzCheck*>(authz_ptr)->verify_activity(pred, pred_sz);
409 }
410 
411 int
412 AuthzCheck::verify_path_s(void *authz_ptr,
413  const unsigned char *pred,
414  size_t pred_sz)
415 {
416  return static_cast<AuthzCheck*>(authz_ptr)->verify_path(pred, pred_sz);
417 }
418 
419 int
420 AuthzCheck::verify_name_s(void *authz_ptr,
421  const unsigned char *pred,
422  size_t pred_sz)
423 {
424  return static_cast<AuthzCheck*>(authz_ptr)->verify_name(pred, pred_sz);
425 }
426 
427 int
428 AuthzCheck::verify_before(const unsigned char * pred, size_t pred_sz)
429 {
430  std::string pred_str(reinterpret_cast<const char *>(pred), pred_sz);
431  if (strncmp("before:", pred_str.c_str(), 7))
432  {
433  return 1;
434  }
435  m_log.Log(LogMask::Debug, "AuthzCheck", "Checking macaroon for expiration; caveat:", pred_str.c_str());
436 
437  struct tm caveat_tm;
438  if (strptime(&pred_str[7], "%Y-%m-%dT%H:%M:%SZ", &caveat_tm) == nullptr)
439  {
440  m_emsg = "Failed to parse time string: " + pred_str.substr(7);
441  m_log.Log(LogMask::Warning, "AuthzCheck", m_emsg.c_str());
442  return 1;
443  }
444  caveat_tm.tm_isdst = -1;
445 
446  time_t caveat_time = timegm(&caveat_tm);
447  if (-1 == caveat_time)
448  {
449  m_emsg = "Failed to generate unix time: " + pred_str.substr(7);
450  m_log.Log(LogMask::Warning, "AuthzCheck", m_emsg.c_str());
451  return 1;
452  }
453  if ((m_max_duration > 0) && (caveat_time > m_now + m_max_duration))
454  {
455  m_emsg = "Max token age is greater than configured max duration; rejecting";
456  m_log.Log(LogMask::Warning, "AuthzCheck", m_emsg.c_str());
457  return 1;
458  }
459 
460  int result = (m_now >= caveat_time);
461  if (!result)
462  {
463  m_log.Log(LogMask::Debug, "AuthzCheck", "Macaroon has not expired.");
464  }
465  else
466  {
467  m_emsg = "Macaroon expired at " + pred_str.substr(7);
468  m_log.Log(LogMask::Debug, "AuthzCheck", m_emsg.c_str());
469  }
470  return result;
471 }
472 
473 int
474 AuthzCheck::verify_activity(const unsigned char * pred, size_t pred_sz)
475 {
476  if (!m_desired_activity.size()) {return 1;}
477  std::string pred_str(reinterpret_cast<const char *>(pred), pred_sz);
478  if (strncmp("activity:", pred_str.c_str(), 9)) {return 1;}
479  m_log.Log(LogMask::Debug, "AuthzCheck", "running verify activity", pred_str.c_str());
480 
481  std::stringstream ss(pred_str.substr(9));
482  for (std::string activity; std::getline(ss, activity, ','); )
483  {
484  // Any allowed activity also implies "READ_METADATA"
485  if (m_desired_activity == "READ_METADATA") {return 0;}
486  if ((activity == m_desired_activity) || ((m_desired_activity == "UPLOAD") && (activity == "MANAGE")))
487  {
488  m_log.Log(LogMask::Debug, "AuthzCheck", "macaroon has desired activity", activity.c_str());
489  return 0;
490  }
491  }
492  m_log.Log(LogMask::Info, "AuthzCheck", "macaroon does NOT have desired activity", m_desired_activity.c_str());
493  return 1;
494 }
495 
496 int
497 AuthzCheck::verify_path(const unsigned char * pred, size_t pred_sz)
498 {
499  std::string pred_str_raw(reinterpret_cast<const char *>(pred), pred_sz);
500  if (strncmp("path:", pred_str_raw.c_str(), 5)) {return 1;}
501  std::string pred_str = XrdOucUtils::NormalizePath(pred_str_raw.substr(5));
502  m_log.Log(LogMask::Debug, "AuthzCheck", "running verify path", pred_str.c_str());
503 
504  if ((m_path.find("/./") != std::string::npos) ||
505  (m_path.find("/../") != std::string::npos))
506  {
507  m_log.Log(LogMask::Info, "AuthzCheck", "invalid requested path", m_path.c_str());
508  return 1;
509  }
510 
511  // Allow operations under subdirectories and not substrings
512  // For e.g. pred_str = "/data/sudir/mydir"
513  // Allows m_path = /data/subdir/mydir/newdir
514  // But rejects, m_path = /data/subdir/mydirmycoolname/newdir
515  int is_subdir = is_subdirectory(pred_str, m_path);
516  if (is_subdir)
517  {
518  m_log.Log(LogMask::Debug, "AuthzCheck", "path request verified for", m_path.c_str());
519  }
520 
521  // READ_METADATA (i.e AOP_Stat) permission for /foo/bar automatically implies permission
522  // to READ_METADATA for /foo.
523  // Similarly, MKDIR Pemissions for a parent path is implied.
524  else if (m_oper == AOP_Stat || m_oper == AOP_Mkdir)
525  {
526  is_subdir = is_subdirectory(m_path, pred_str);
527  const char *opName = (m_oper == AOP_Stat) ? "READ_METADATA" : "MKDIR";
528  m_log.Log(LogMask::Debug, "AuthzCheck",
529  (std::string(opName) + (is_subdir? " Path request verified for" : " Path request NOT allowed for")).c_str(),
530  m_path.c_str());
531  }
532  else
533  {
534  m_log.Log(LogMask::Debug, "AuthzCheck", "path request NOT allowed", m_path.c_str());
535  }
536 
537  return !is_subdir;
538 }
539 
540 int
541 AuthzCheck::verify_name(const unsigned char * pred, size_t pred_sz)
542 {
543  std::string pred_str(reinterpret_cast<const char *>(pred), pred_sz);
544  if (strncmp("name:", pred_str.c_str(), 5)) {return 1;}
545  if (pred_str.size() < 6) {return 1;}
546  m_log.Log(LogMask::Debug, "AuthzCheck", "Verifying macaroon with", pred_str.c_str());
547 
548  // Make a copy of the name for the XrdSecEntity; this will be used later.
549  m_sec_name = pred_str.substr(5);
550 
551  return 0;
552 }
Access_Operation
The following are supported operations.
@ AOP_Delete
rm() or rmdir()
@ AOP_Mkdir
mkdir()
@ AOP_Update
open() r/w or append
@ AOP_Create
open() with create
@ AOP_Readdir
opendir()
@ AOP_Chmod
chmod()
@ AOP_Any
Special for getting privs.
@ AOP_Stat
exists(), stat()
@ AOP_Poll
stage polling operations
@ AOP_Rename
mv() for source
@ AOP_Read
open() r/o, prepare()
@ AOP_Excl_Create
open() with O_EXCL|O_CREAT
@ AOP_Insert
mv() for target
@ AOP_Lock
n/a
@ AOP_Chown
chown()
@ AOP_Stage
stage and or read data, plus related operations
@ AOP_Excl_Insert
mv() where destination doesn't exist.
XrdAccPrivs
Definition: XrdAccPrivs.hh:39
@ XrdAccPriv_Mkdir
Definition: XrdAccPrivs.hh:46
@ XrdAccPriv_Chown
Definition: XrdAccPrivs.hh:41
@ XrdAccPriv_Insert
Definition: XrdAccPrivs.hh:44
@ XrdAccPriv_Lookup
Definition: XrdAccPrivs.hh:47
@ XrdAccPriv_Rename
Definition: XrdAccPrivs.hh:48
@ XrdAccPriv_Poll
Definition: XrdAccPrivs.hh:54
@ XrdAccPriv_Update
Definition: XrdAccPrivs.hh:52
@ XrdAccPriv_Read
Definition: XrdAccPrivs.hh:49
@ XrdAccPriv_Lock
Definition: XrdAccPrivs.hh:45
@ XrdAccPriv_None
Definition: XrdAccPrivs.hh:55
@ XrdAccPriv_Stage
Definition: XrdAccPrivs.hh:53
@ XrdAccPriv_Delete
Definition: XrdAccPrivs.hh:43
@ XrdAccPriv_Create
Definition: XrdAccPrivs.hh:42
@ XrdAccPriv_Readdir
Definition: XrdAccPrivs.hh:50
@ XrdAccPriv_Chmod
Definition: XrdAccPrivs.hh:40
static bool is_subdirectory(const std::string_view dir, const std::string_view subdir)
bool Debug
void getline(uchar *buff, int blen)
int emsg(int rc, char *msg)
@ Error
virtual bool Validate(const char *token, std::string &emsg, long long *expT, XrdSecEntity *entP) override
Authz(XrdSysLogger *lp, const char *parms, XrdAccAuthorize *chain)
virtual XrdAccPrivs Access(const XrdSecEntity *Entity, const char *path, const Access_Operation oper, XrdOucEnv *env) override
static bool Config(const char *config, XrdOucEnv *env, XrdSysError *log, std::string &location, std::string &secret, ssize_t &max_duration, AuthzBehavior &behavior)
virtual XrdAccPrivs Access(const XrdSecEntity *Entity, const char *path, const Access_Operation oper, XrdOucEnv *Env=0)=0
char * Get(const char *varname)
Definition: XrdOucEnv.hh:69
static std::string NormalizePath(const std::string &path)
bool Add(XrdSecAttr &attr)
int credslen
Length of the 'creds' data.
Definition: XrdSecEntity.hh:78
XrdSecEntityAttr * eaAPI
non-const API to attributes
Definition: XrdSecEntity.hh:92
char prot[XrdSecPROTOIDSIZE]
Auth protocol used (e.g. krb5)
Definition: XrdSecEntity.hh:67
char * creds
Raw entity credentials or cert.
Definition: XrdSecEntity.hh:77
int Emsg(const char *esfx, int ecode, const char *text1, const char *text2=0)
Definition: XrdSysError.cc:116
void Log(int mask, const char *esfx, const char *text1, const char *text2=0, const char *text3=0)
Definition: XrdSysError.hh:167
@ Warning