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//
87 return (XrdAccAuthorize *)XrdAccConfiguration.Authorization;
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 Access2(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 Access2(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 Access2(caps, Entity, path, oper);
250}
251
252/******************************************************************************/
253
254XrdAccPrivs XrdAccAccess::Access2( XrdAccPrivCaps &caps,
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 "stage", // 15
308 "poll" // 16
309 };
310 const char *opname = (oper > AOP_LastOp ? "???" : Opername[oper]);
311 std::string username;
312 const char *id = "*";
313 auto got_token = Entity->eaAPI->Get("request.name", username);
314 if (got_token && !username.empty()) {
315 id = username.c_str();
316 } else if (Entity->name) id = Entity->name;
317 const char *host = (Entity->host ? (const char *)Entity->host : "?");
318 char atype[XrdSecPROTOIDSIZE+1];
319
320// Get the protocol type in a printable format
321//
322 strncpy(atype, Entity->prot, XrdSecPROTOIDSIZE);
323 atype[XrdSecPROTOIDSIZE] = '\0';
324
325// Route the message appropriately
326//
327 if (accok) Auditor->Grant(opname, Entity->tident, atype, id, host, path);
328 else Auditor->Deny( opname, Entity->tident, atype, id, host, path);
329
330// All done, finally
331//
332 return accok;
333}
334
335/******************************************************************************/
336/* R e s o l v e */
337/******************************************************************************/
338
339const char *XrdAccAccess::Resolve(const XrdSecEntity *Entity)
340{
341// Make a quick test for IPv6 (as that's the future) and a minimal one for ipV4
342// to see if we have to do a DNS lookup.
343//
344 if (Entity->host == 0 || *(Entity->host) == '[' || isdigit(*(Entity->host)))
345 return Entity->addrInfo->Name("?");
346 return Entity->host;
347}
348
349/******************************************************************************/
350/* S w a p T a b s */
351/******************************************************************************/
352
353#define XrdAccSWAP(x) oldtab.x = Atab.x; Atab.x = newtab.x; \
354 newtab.x = oldtab.x; oldtab.x = 0;
355
357{
358 struct XrdAccAccess_Tables oldtab;
359 bool hRefX = false, hRefY = false;
360
361// Determine if we need to resolve the host name early
362//
363 XrdAccAccess_ID *xlP = newtab.SXList;
364 while(xlP)
365 {if (xlP->host) {hRefX = true; break;}
366 xlP = xlP->next;
367 }
368
369// Determine if we need to resolve the hostname at all.
370//
371 if (!hRefX)
372 {if (newtab.D_List || newtab.H_Hash || newtab.N_Hash) hRefY = true;
373 else {XrdAccAccess_ID *ylP = newtab.SYList;
374 while (ylP)
375 {if (ylP->host) {hRefY = true; break;}
376 ylP = ylP->next;
377 }
378 }
379 }
380
381// Get an exclusive context to change the table pointers
382//
383 Access_Context.Lock(xs_Exclusive);
384
385// Save the old pointer while replacing it with the new pointer
386//
387 XrdAccSWAP(D_List);
388 XrdAccSWAP(E_List);
389 XrdAccSWAP(G_Hash);
390 XrdAccSWAP(H_Hash);
391 XrdAccSWAP(N_Hash);
392 XrdAccSWAP(O_Hash);
393 XrdAccSWAP(R_Hash);
394 XrdAccSWAP(S_Hash);
395 XrdAccSWAP(T_Hash);
396 XrdAccSWAP(U_Hash);
397 XrdAccSWAP(X_List);
398 XrdAccSWAP(Z_List);
399 XrdAccSWAP(SXList);
400 XrdAccSWAP(SYList);
401 hostRefX = hRefX;
402 hostRefY = hRefY;
403
404// When we set new access tables, we should purge the group cache
405//
406 XrdAccConfiguration.GroupMaster.PurgeCache();
407
408// We can now let loose new table searchers
409//
410 Access_Context.UnLock(xs_Exclusive);
411}
412
413/******************************************************************************/
414/* T e s t */
415/******************************************************************************/
416
418{
419
420// Warning! This table must be in 1-to-1 correspondence with Access_Operation
421//
422 static XrdAccPrivs need[] = {XrdAccPriv_None, // 0
423 XrdAccPriv_Chmod, // 1
424 XrdAccPriv_Chown, // 2
428 XrdAccPriv_Lock, // 6
429 XrdAccPriv_Mkdir, // 7
430 XrdAccPriv_Read, // 8
432 XrdAccPriv_Rename, // 10
433 XrdAccPriv_Lookup, // 11
434 XrdAccPriv_Update, // 12
435 (XrdAccPrivs)0xffff, // 13
436 (XrdAccPrivs)0xffff // 14
437 };
438 // Note AOP_Excl* does not have a corresponding XrdAccPrivs; this is on
439 // purpose as the Excl* privilege is not modelled within the AuditDB framework.
440 if (oper < 0 || oper > AOP_LastOp) return 0;
441 return (int)(need[oper] & priv) == need[oper];
442}
443
444/******************************************************************************/
445/* X r d A c c A c c e s s _ I D : : A p p l i e s */
446/******************************************************************************/
447
449{
450
451// Check single value items in the most probable use order
452//
453 if (org && (!Entity.vorg || strcmp(org, Entity.vorg))) return false;
454 if (role && (!Entity.role || strcmp(role, Entity.role))) return false;
455 if (grp && (!Entity.grup || strcmp(grp, Entity.grup))) return false;
456 if (user && (!Entity.name || strcmp(user, Entity.name))) return false;
457
458// The check is more complicated as the host field may be a domain.
459//
460 if (host)
461 {const char *hName;
462 if (*host == '.')
463 {int eLen = strlen(Entity.host);
464 if (eLen <= hlen) return false;
465 hName = Entity.host + eLen - hlen;
466 } else hName = Entity.host;
467 if (strcmp(host, hName)) return false;
468 }
469
470// All done, this rules applies!
471//
472 return true;
473}
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)
int Privs(XrdAccPrivCaps &pathpriv, const char *pathname, const int pathlen, const unsigned long pathhash, const char *pathsub=0)
static void setError(XrdSysError *errP)
bool Next(int &seq, XrdAccEntityInfo &info)
const char * Next()
const char * Name(const char *eName=0, const char **eText=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)
bool Applies(const XrdAccEntityInfo &Entity)
XrdAccCapability * caps
XrdAccAccess_ID * next
XrdOucHash< XrdAccCapability > * N_Hash
XrdAccAccess_ID * SXList
XrdAccCapName * D_List
XrdOucHash< XrdAccCapability > * H_Hash
XrdAccAccess_ID * SYList
const char * vorg
const char * role
const char * name
const char * host
const char * grup
XrdAccPrivs nprivs
XrdAccPrivs pprivs