XRootD
Loading...
Searching...
No Matches
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
44#include "XrdOuc/XrdOucUtils.hh"
47
48/******************************************************************************/
49/* E x t e r n a l R e f e r e n c e s */
50/******************************************************************************/
51
52extern 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//
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;
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 != '?' &&
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;
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
284int 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
337const 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//
385 XrdAccSWAP(D_List);
386 XrdAccSWAP(E_List);
387 XrdAccSWAP(G_Hash);
388 XrdAccSWAP(H_Hash);
389 XrdAccSWAP(N_Hash);
390 XrdAccSWAP(O_Hash);
391 XrdAccSWAP(R_Hash);
392 XrdAccSWAP(S_Hash);
393 XrdAccSWAP(T_Hash);
394 XrdAccSWAP(U_Hash);
395 XrdAccSWAP(X_List);
396 XrdAccSWAP(Z_List);
397 XrdAccSWAP(SXList);
398 XrdAccSWAP(SYList);
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
426 XrdAccPriv_Lock, // 6
427 XrdAccPriv_Mkdir, // 7
428 XrdAccPriv_Read, // 8
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}
XrdAccAuthorize * XrdAccDefaultAuthorizeObject(XrdSysLogger *lp, const char *cfn, const char *parm, XrdVersionInfo &urVer)
unsigned long XrdOucHashVal2(const char *KeyVal, int KeyLen)
#define XrdAccSWAP(x)
XrdAccConfig XrdAccConfiguration
XrdAccAudit * XrdAccAuditObject(XrdSysError *erp)
XrdAccAudit_Options
@ audit_grant
Access_Operation
The following are supported operations.
@ AOP_LastOp
XrdAccPrivs
@ XrdAccPriv_Mkdir
@ XrdAccPriv_Chown
@ XrdAccPriv_Insert
@ XrdAccPriv_Lookup
@ XrdAccPriv_Rename
@ XrdAccPriv_Update
@ XrdAccPriv_Read
@ XrdAccPriv_Lock
@ XrdAccPriv_None
@ XrdAccPriv_Delete
@ XrdAccPriv_Create
@ XrdAccPriv_Readdir
@ XrdAccPriv_Chmod
static XrdVERSIONINFODEF(compiledVer, XrdHttpProtocolTest, XrdVNUMBER, XrdVERSION)
#define XrdSecPROTOIDSIZE
@ xs_Exclusive
@ xs_Shared
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)
void SwapTabs(struct XrdAccAccess_Tables &newtab)
int Auditing(const XrdAccAudit_Options ops=audit_all)
virtual void Deny(const char *opname, const char *tident, const char *atype, const char *id, const char *host, const char *path)
virtual void Grant(const char *opname, const char *tident, const char *atype, const char *id, const char *host, const char *path)
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
XrdAccGroups GroupMaster
static void setError(XrdSysError *errP)
bool Next(int &seq, XrdAccEntityInfo &info)
const char * Next()
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)
XrdSecAttr * Get(const void *sigkey)
XrdNetAddrInfo * addrInfo
Entity's connection details.
XrdSecEntityAttr * eaAPI
non-const API to attributes
const char * tident
Trace identifier always preset.
char prot[XrdSecPROTOIDSIZE]
Auth protocol used (e.g. krb5)
char * name
Entity's name.
char * host
Entity's host name dnr dependent.
static bool VerCmp(XrdVersionInfo &vInf1, XrdVersionInfo &vInf2, bool noMsg=false)
void Lock(const XrdSysXS_Type usage)
void UnLock(const XrdSysXS_Type usage=xs_None)
bool Applies(const XrdAccEntityInfo &Entity)
XrdAccCapability * caps
XrdAccAccess_ID * next
XrdOucHash< XrdAccCapability > * U_Hash
XrdOucHash< XrdAccCapability > * G_Hash
XrdOucHash< XrdAccCapability > * N_Hash
XrdAccCapability * X_List
XrdAccAccess_ID * SXList
XrdAccCapability * Z_List
XrdOucHash< XrdAccCapability > * O_Hash
XrdAccCapName * D_List
XrdOucHash< XrdAccCapability > * H_Hash
XrdOucHash< XrdAccCapability > * R_Hash
XrdAccAccess_ID * SYList
const char * vorg
const char * role
const char * name
const char * host
const char * grup
XrdAccPrivs nprivs
XrdAccPrivs pprivs