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