XRootD
XrdAccAccess.cc
Go to the documentation of this file.
1 /******************************************************************************/
2 /* */
3 /* X r d A c c A c c e s s . c c */
4 /* */
5 /* (c) 2003 by the Board of Trustees of the Leland Stanford, Jr., University */
6 /* All Rights Reserved */
7 /* Produced by Andrew Hanushevsky for Stanford University under contract */
8 /* DE-AC02-76-SFO0515 with the Department of Energy */
9 /* */
10 /* This file is part of the XRootD software suite. */
11 /* */
12 /* XRootD is free software: you can redistribute it and/or modify it under */
13 /* the terms of the GNU Lesser General Public License as published by the */
14 /* Free Software Foundation, either version 3 of the License, or (at your */
15 /* option) any later version. */
16 /* */
17 /* XRootD is distributed in the hope that it will be useful, but WITHOUT */
18 /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */
19 /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */
20 /* License for more details. */
21 /* */
22 /* You should have received a copy of the GNU Lesser General Public License */
23 /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */
24 /* COPYING (GPL license). If not, see <http://www.gnu.org/licenses/>. */
25 /* */
26 /* The copyright holder's institutional names and contributor's names may not */
27 /* be used to endorse or promote products derived from this software without */
28 /* specific prior written permission of the institution or contributor. */
29 /******************************************************************************/
30 
31 #include <cctype>
32 #include <cstdio>
33 #include <ctime>
34 #include <sys/param.h>
35 
36 #include "XrdVersion.hh"
37 
38 #include "XrdAcc/XrdAccAccess.hh"
39 #include "XrdAcc/XrdAccEntity.hh"
41 #include "XrdAcc/XrdAccConfig.hh"
42 #include "XrdAcc/XrdAccGroups.hh"
43 #include "XrdNet/XrdNetAddrInfo.hh"
44 #include "XrdOuc/XrdOucUtils.hh"
46 #include "XrdSys/XrdSysPlugin.hh"
47 
48 /******************************************************************************/
49 /* E x t e r n a l R e f e r e n c e s */
50 /******************************************************************************/
51 
52 extern unsigned long XrdOucHashVal2(const char *KeyVal, int KeyLen);
53 
54 /******************************************************************************/
55 /* G l o b a l C o n f i g u r a t i o n O b j e c t */
56 /******************************************************************************/
57 
59 
60 /******************************************************************************/
61 /* Autorization Object Creation via XrdAccDefaultAuthorizeObject */
62 /******************************************************************************/
63 
65  const char *cfn,
66  const char *parm,
67  XrdVersionInfo &urVer)
68 {
69  static XrdVERSIONINFODEF(myVer, XrdAcc, XrdVNUMBER, XrdVERSION);
70  static XrdSysError Eroute(lp, "acc_");
71 
72 // Verify version compatibility
73 //
74  if (urVer.vNum != myVer.vNum && !XrdSysPlugin::VerCmp(urVer,myVer))
75  return 0;
76 
77 // Configure the authorization system
78 //
79  if (XrdAccConfiguration.Configure(Eroute, cfn)) return (XrdAccAuthorize *)0;
80 
81 // Set error object pointer
82 //
83  XrdAccEntity::setError(&Eroute);
84 
85 // All is well, return the actual pointer to the object
86 //
88 }
89 
90 /******************************************************************************/
91 /* C o n s t r u c t o r */
92 /******************************************************************************/
93 
95 {
96 // Get the audit option that we should use
97 //
98  Auditor = XrdAccAuditObject(erp);
99 }
100 
101 /******************************************************************************/
102 /* A c c e s s */
103 /******************************************************************************/
104 
106  const char *path,
107  const Access_Operation oper,
108  XrdOucEnv *Env)
109 {
110  XrdAccGroupList *glp;
111  XrdAccPrivCaps caps;
112  XrdAccCapability *cp;
113  XrdAccEntity *aeP;
114  XrdAccEntityInfo eInfo;
115  int plen = strlen(path);
116  long phash = XrdOucHashVal2(path, plen);
117  bool isuser;
118 
119 // Obtain an authorization entity (it will be released upon return).
120 //
121  XrdAccEntityInit accEntity(Entity, aeP);
122  if (!aeP) return Access(caps, Entity, path, oper);
123 
124 // Setup the id (we don't need a lock for that)
125 //
126  std::string username;
127  auto got_token = Entity->eaAPI->Get("request.name", username);
128  if (got_token && !username.empty())
129  {eInfo.name = username.c_str();
130  isuser = true;
131  }
132  else if (Entity->name)
133  {eInfo.name = Entity->name;
134  isuser = (*eInfo.name != 0);
135  } else {
136  eInfo.name = "*";
137  isuser = false;
138  }
139 
140 // Get a shared context for these potentially long running routines
141 //
142  Access_Context.Lock(xs_Shared);
143 
144 // Setup the host entry in the eInfo structure (it may need to be resolved)
145 //
146  eInfo.host = (hostRefX ? Resolve(Entity) : "?");
147 
148 // Run through the exclusive list first as only one rule will apply
149 //
150  if (Atab.SXList)
151  {XrdAccAccess_ID *xlP = Atab.SXList;
152  do {int aSeq = 0;
153  while(aeP->Next(aSeq, eInfo))
154  {if (xlP->Applies(eInfo))
155  {xlP->caps->Privs(caps, path, plen, phash);
156  Access_Context.UnLock(xs_Shared);
157  return Access(caps, Entity, path, oper);
158  }
159  }
160  xlP = xlP->next;
161  } while(xlP);
162  }
163 
164 // Check if we really need to resolve the host name
165 //
166 //??? if (Atab.D_List || Atab.H_Hash || Atab.N_Hash) host = Resolve(Entity);
167  if (!hostRefX && hostRefY) eInfo.host = Resolve(Entity);
168 
169 // Establish default privileges
170 //
171  if (Atab.Z_List) Atab.Z_List->Privs(caps, path, plen, phash);
172 
173 // Next add in the host domain privileges
174 //
175  if (Atab.D_List && (cp = Atab.D_List->Find(eInfo.host)))
176  cp->Privs(caps, path, plen, phash);
177 
178 // Next add in the host-specific privileges
179 //
180  if (Atab.H_Hash && (cp = Atab.H_Hash->Find(eInfo.host)))
181  cp->Privs(caps, path, plen, phash);
182 
183 // Now add in the netgroup privileges
184 //
185  if (Atab.N_Hash && *eInfo.host != '?' &&
186  (glp = XrdAccConfiguration.GroupMaster.NetGroups(eInfo.name,eInfo.host)))
187  {char *gname;
188  while((gname = (char *)glp->Next()))
189  if ((cp = Atab.N_Hash->Find((const char *)gname)))
190  cp->Privs(caps, path, plen, phash);
191  delete glp;
192  }
193 
194 // Check for user fungible privileges
195 //
196  if (isuser && Atab.X_List)
197  Atab.X_List->Privs(caps, path, plen, phash, eInfo.name);
198 
199 // Add in specific user privileges
200 //
201  if (isuser && Atab.U_Hash && (cp = Atab.U_Hash->Find(eInfo.name)))
202  cp->Privs(caps, path, plen, phash);
203 
204 // The following privileges are based on multiple attributes. Orgs and roles
205 // may be repeated but groups generally will not be.
206 //
207  const char *vorgPrev = 0, *rolePrev = 0;
208  int aSeq = 0;
209 
210  while(aeP->Next(aSeq, eInfo))
211  {
212  // Add in the group privileges.
213  //
214  if (Atab.G_Hash && eInfo.grup && (cp = Atab.G_Hash->Find(eInfo.grup)))
215  cp->Privs(caps, path, plen, phash);
216 
217  // Add in the org-specific privileges
218  //
219  if (Atab.O_Hash && eInfo.vorg && eInfo.vorg != vorgPrev)
220  {vorgPrev = eInfo.vorg;
221  if ((cp = Atab.O_Hash->Find(eInfo.vorg)))
222  cp->Privs(caps, path, plen, phash);
223  }
224 
225  // Add in the role-specific privileges
226  //
227  if (Atab.R_Hash && eInfo.role && eInfo.role != rolePrev)
228  {rolePrev = eInfo.role;
229  if ((cp = Atab.R_Hash->Find(eInfo.role)))
230  cp->Privs(caps, path, plen, phash);
231  }
232 
233  // Finally run through the inclusive list and apply all relevant rules
234  //
235  XrdAccAccess_ID *ylP = Atab.SYList;
236  while (ylP)
237  {if (ylP->Applies(eInfo))
238  ylP->caps->Privs(caps, path, plen, phash);
239  ylP = ylP->next;
240  }
241  }
242 
243 // We are now done with looking at changeable data
244 //
245  Access_Context.UnLock(xs_Shared);
246 
247 // Return the privileges as needed
248 //
249  return Access(caps, Entity, path, oper);
250 }
251 
252 /******************************************************************************/
253 
255  const XrdSecEntity *Entity,
256  const char *path,
257  const Access_Operation oper
258  )
259 {
260  XrdAccPrivs myprivs;
261  XrdAccAudit_Options audits = (XrdAccAudit_Options)Auditor->Auditing();
262  int accok;
263 
264 // Compute composite privileges and see if privs need to be returned
265 //
266  myprivs = (XrdAccPrivs)(caps.pprivs & ~caps.nprivs);
267  if (!oper) return (XrdAccPrivs)myprivs;
268 
269 // Check if auditing is enabled or whether we can do a fastaroo test
270 //
271  if (!audits) return (XrdAccPrivs)Test(myprivs, oper);
272  if ((accok = Test(myprivs, oper)) && !(audits & audit_grant))
273  return (XrdAccPrivs)accok;
274 
275 // Call the auditing routine and exit
276 //
277  return (XrdAccPrivs)Audit(accok, Entity, path, oper);
278 }
279 
280 /******************************************************************************/
281 /* A u d i t */
282 /******************************************************************************/
283 
284 int XrdAccAccess::Audit(const int accok,
285  const XrdSecEntity *Entity,
286  const char *path,
287  const Access_Operation oper,
288  XrdOucEnv *Env)
289 {
290 // Warning! This table must be in 1-to-1 correspondence with Access_Operation
291 //
292  static const char *Opername[] = {"any", // 0
293  "chmod", // 1
294  "chown", // 2
295  "create", // 3
296  "delete", // 4
297  "insert", // 5
298  "lock", // 6
299  "mkdir", // 7
300  "read", // 8
301  "readdir", // 9
302  "rename", // 10
303  "stat", // 11
304  "update", // 12
305  "excl_create", // 13
306  "excl_insert" // 14
307  };
308  const char *opname = (oper > AOP_LastOp ? "???" : Opername[oper]);
309  std::string username;
310  const char *id = "*";
311  auto got_token = Entity->eaAPI->Get("request.name", username);
312  if (got_token && !username.empty()) {
313  id = username.c_str();
314  } else if (Entity->name) id = Entity->name;
315  const char *host = (Entity->host ? (const char *)Entity->host : "?");
316  char atype[XrdSecPROTOIDSIZE+1];
317 
318 // Get the protocol type in a printable format
319 //
320  strncpy(atype, Entity->prot, XrdSecPROTOIDSIZE);
321  atype[XrdSecPROTOIDSIZE] = '\0';
322 
323 // Route the message appropriately
324 //
325  if (accok) Auditor->Grant(opname, Entity->tident, atype, id, host, path);
326  else Auditor->Deny( opname, Entity->tident, atype, id, host, path);
327 
328 // All done, finally
329 //
330  return accok;
331 }
332 
333 /******************************************************************************/
334 /* R e s o l v e */
335 /******************************************************************************/
336 
337 const char *XrdAccAccess::Resolve(const XrdSecEntity *Entity)
338 {
339 // Make a quick test for IPv6 (as that's the future) and a minimal one for ipV4
340 // to see if we have to do a DNS lookup.
341 //
342  if (Entity->host == 0 || *(Entity->host) == '[' || isdigit(*(Entity->host)))
343  return Entity->addrInfo->Name("?");
344  return Entity->host;
345 }
346 
347 /******************************************************************************/
348 /* S w a p T a b s */
349 /******************************************************************************/
350 
351 #define XrdAccSWAP(x) oldtab.x = Atab.x; Atab.x = newtab.x; \
352  newtab.x = oldtab.x; oldtab.x = 0;
353 
355 {
356  struct XrdAccAccess_Tables oldtab;
357  bool hRefX = false, hRefY = false;
358 
359 // Determine if we need to resolve the host name early
360 //
361  XrdAccAccess_ID *xlP = newtab.SXList;
362  while(xlP)
363  {if (xlP->host) {hRefX = true; break;}
364  xlP = xlP->next;
365  }
366 
367 // Determine if we need to resolve the hostname at all.
368 //
369  if (!hRefX)
370  {if (newtab.D_List || newtab.H_Hash || newtab.N_Hash) hRefY = true;
371  else {XrdAccAccess_ID *ylP = newtab.SYList;
372  while (ylP)
373  {if (ylP->host) {hRefY = true; break;}
374  ylP = ylP->next;
375  }
376  }
377  }
378 
379 // Get an exclusive context to change the table pointers
380 //
381  Access_Context.Lock(xs_Exclusive);
382 
383 // Save the old pointer while replacing it with the new pointer
384 //
399  hostRefX = hRefX;
400  hostRefY = hRefY;
401 
402 // When we set new access tables, we should purge the group cache
403 //
405 
406 // We can now let loose new table searchers
407 //
408  Access_Context.UnLock(xs_Exclusive);
409 }
410 
411 /******************************************************************************/
412 /* T e s t */
413 /******************************************************************************/
414 
416 {
417 
418 // Warning! This table must be in 1-to-1 correspondence with Access_Operation
419 //
420  static XrdAccPrivs need[] = {XrdAccPriv_None, // 0
421  XrdAccPriv_Chmod, // 1
422  XrdAccPriv_Chown, // 2
423  XrdAccPriv_Create, // 3
424  XrdAccPriv_Delete, // 4
425  XrdAccPriv_Insert, // 5
426  XrdAccPriv_Lock, // 6
427  XrdAccPriv_Mkdir, // 7
428  XrdAccPriv_Read, // 8
429  XrdAccPriv_Readdir, // 9
430  XrdAccPriv_Rename, // 10
431  XrdAccPriv_Lookup, // 11
432  XrdAccPriv_Update, // 12
433  (XrdAccPrivs)0xffff, // 13
434  (XrdAccPrivs)0xffff // 14
435  };
436  // Note AOP_Excl* does not have a corresponding XrdAccPrivs; this is on
437  // purpose as the Excl* privilege is not modelled within the AuditDB framework.
438  if (oper < 0 || oper > AOP_LastOp) return 0;
439  return (int)(need[oper] & priv) == need[oper];
440 }
441 
442 /******************************************************************************/
443 /* X r d A c c A c c e s s _ I D : : A p p l i e s */
444 /******************************************************************************/
445 
447 {
448 
449 // Check single value items in the most probable use order
450 //
451  if (org && (!Entity.vorg || strcmp(org, Entity.vorg))) return false;
452  if (role && (!Entity.role || strcmp(role, Entity.role))) return false;
453  if (grp && (!Entity.grup || strcmp(grp, Entity.grup))) return false;
454  if (user && (!Entity.name || strcmp(user, Entity.name))) return false;
455 
456 // The check is more complicated as the host field may be a domain.
457 //
458  if (host)
459  {const char *hName;
460  if (*host == '.')
461  {int eLen = strlen(Entity.host);
462  if (eLen <= hlen) return false;
463  hName = Entity.host + eLen - hlen;
464  } else hName = Entity.host;
465  if (strcmp(host, hName)) return false;
466  }
467 
468 // All done, this rules applies!
469 //
470  return true;
471 }
unsigned long XrdOucHashVal2(const char *KeyVal, int KeyLen)
#define XrdAccSWAP(x)
XrdAccConfig XrdAccConfiguration
Definition: XrdAccConfig.cc:61
XrdAccAuthorize * XrdAccDefaultAuthorizeObject(XrdSysLogger *lp, const char *cfn, const char *parm, XrdVersionInfo &urVer)
Definition: XrdAccAccess.cc:64
XrdAccAudit * XrdAccAuditObject(XrdSysError *erp)
Definition: XrdAccAudit.cc:92
XrdAccAudit_Options
Definition: XrdAccAudit.hh:37
@ audit_grant
Definition: XrdAccAudit.hh:39
Access_Operation
The following are supported operations.
@ AOP_LastOp
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_Update
Definition: XrdAccPrivs.hh:52
@ XrdAccPriv_Read
Definition: XrdAccPrivs.hh:49
@ XrdAccPriv_Lock
Definition: XrdAccPrivs.hh:45
@ XrdAccPriv_None
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
#define XrdSecPROTOIDSIZE
Definition: XrdSecEntity.hh:47
@ xs_Exclusive
Definition: XrdSysXSLock.hh:38
@ xs_Shared
Definition: XrdSysXSLock.hh:38
int Test(const XrdAccPrivs priv, const Access_Operation oper)
int Audit(const int accok, const XrdSecEntity *Entity, const char *path, const Access_Operation oper, XrdOucEnv *Env=0)
static const char * Resolve(const XrdSecEntity *Entity)
XrdAccPrivs Access(const XrdSecEntity *Entity, const char *path, const Access_Operation oper, XrdOucEnv *Env=0)
XrdAccAccess(XrdSysError *erp)
Definition: XrdAccAccess.cc:94
void SwapTabs(struct XrdAccAccess_Tables &newtab)
int Auditing(const XrdAccAudit_Options ops=audit_all)
Definition: XrdAccAudit.hh:69
virtual void Deny(const char *opname, const char *tident, const char *atype, const char *id, const char *host, const char *path)
Definition: XrdAccAudit.cc:54
virtual void Grant(const char *opname, const char *tident, const char *atype, const char *id, const char *host, const char *path)
Definition: XrdAccAudit.cc:73
XrdAccCapability * Find(const char *name)
int Privs(XrdAccPrivCaps &pathpriv, const char *pathname, const int pathlen, const unsigned long pathhash, const char *pathsub=0)
int Configure(XrdSysError &Eroute, const char *cfn)
XrdAccAccess * Authorization
Definition: XrdAccConfig.hh:78
XrdAccGroups GroupMaster
Definition: XrdAccConfig.hh:79
static void setError(XrdSysError *errP)
bool Next(int &seq, XrdAccEntityInfo &info)
Definition: XrdAccEntity.hh:71
const char * Next()
Definition: XrdAccGroups.hh:49
void PurgeCache()
XrdAccGroupList * NetGroups(const char *user, const char *host)
const char * Name(const char *eName=0, const char **eText=0)
T * Find(const char *KeyVal, time_t *KeyTime=0)
Definition: XrdOucHash.icc:160
XrdSecAttr * Get(const void *sigkey)
XrdNetAddrInfo * addrInfo
Entity's connection details.
Definition: XrdSecEntity.hh:80
XrdSecEntityAttr * eaAPI
non-const API to attributes
Definition: XrdSecEntity.hh:92
const char * tident
Trace identifier always preset.
Definition: XrdSecEntity.hh:81
char prot[XrdSecPROTOIDSIZE]
Auth protocol used (e.g. krb5)
Definition: XrdSecEntity.hh:67
char * name
Entity's name.
Definition: XrdSecEntity.hh:69
char * host
Entity's host name dnr dependent.
Definition: XrdSecEntity.hh:70
static bool VerCmp(XrdVersionInfo &vInf1, XrdVersionInfo &vInf2, bool noMsg=false)
void Lock(const XrdSysXS_Type usage)
Definition: XrdSysXSLock.cc:55
void UnLock(const XrdSysXS_Type usage=xs_None)
Definition: XrdSysXSLock.cc:95
XrdVERSIONINFODEF(myVersion, cmsclient, XrdVNUMBER, XrdVERSION)
bool Applies(const XrdAccEntityInfo &Entity)
XrdAccCapability * caps
Definition: XrdAccAccess.hh:54
XrdAccAccess_ID * next
Definition: XrdAccAccess.hh:55
XrdOucHash< XrdAccCapability > * U_Hash
Definition: XrdAccAccess.hh:93
XrdOucHash< XrdAccCapability > * G_Hash
Definition: XrdAccAccess.hh:86
XrdAccCapName * E_List
Definition: XrdAccAccess.hh:95
XrdOucHash< XrdAccCapability > * N_Hash
Definition: XrdAccAccess.hh:88
XrdAccCapability * X_List
Definition: XrdAccAccess.hh:96
XrdAccAccess_ID * SXList
Definition: XrdAccAccess.hh:98
XrdAccCapability * Z_List
Definition: XrdAccAccess.hh:97
XrdOucHash< XrdAccCapability > * T_Hash
Definition: XrdAccAccess.hh:92
XrdOucHash< XrdAccCapability > * O_Hash
Definition: XrdAccAccess.hh:89
XrdAccCapName * D_List
Definition: XrdAccAccess.hh:94
XrdOucHash< XrdAccCapability > * H_Hash
Definition: XrdAccAccess.hh:87
XrdOucHash< XrdAccAccess_ID > * S_Hash
Definition: XrdAccAccess.hh:91
XrdOucHash< XrdAccCapability > * R_Hash
Definition: XrdAccAccess.hh:90
XrdAccAccess_ID * SYList
Definition: XrdAccAccess.hh:99
const char * vorg
Definition: XrdAccEntity.hh:44
const char * role
Definition: XrdAccEntity.hh:45
const char * name
Definition: XrdAccEntity.hh:42
const char * host
Definition: XrdAccEntity.hh:43
const char * grup
Definition: XrdAccEntity.hh:46
XrdAccPrivs nprivs
Definition: XrdAccPrivs.hh:78
XrdAccPrivs pprivs
Definition: XrdAccPrivs.hh:77