XRootD
Loading...
Searching...
No Matches
XrdAccGroups.cc
Go to the documentation of this file.
1/******************************************************************************/
2/* */
3/* X r d A c c G r o u p 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 <unistd.h>
32#include <cctype>
33#include <cerrno>
34#include <limits.h>
35#include <netdb.h>
36#include <pwd.h>
37#include <cstring>
38#include <strings.h>
39#include <sys/param.h>
40#include <sys/types.h>
41
44#include "XrdSys/XrdSysPwd.hh"
47#include "XrdAcc/XrdAccPrivs.hh"
48
49#ifdef MUSL
50int innetgr(const char *netgroup, const char *host, const char *user,
51 const char *domain)
52{
53 return 0;
54}
55#endif
56
57// Additionally, this routine does not support a user in more than
58// NGROUPS_MAX groups. This is a standard unix limit defined in limits.h.
59
60/******************************************************************************/
61/* G l o b a l G r o u p s O b j e c t */
62/******************************************************************************/
63
64// There is only one Groups object that handles group memberships. Others
65// needing access to this object should declare an extern to this object.
66//
68
69/******************************************************************************/
70/* G r o u p C o n s t r u c t i o n A r g u m e n t s */
71/******************************************************************************/
72
73struct XrdAccGroupArgs {const char *user;
74 const char *host;
75 int gtabi;
76 const char *Gtab[NGROUPS_MAX];
77 };
78
79/******************************************************************************/
80/* C o n s t r u c t o r */
81/******************************************************************************/
82
84{
85
86// Do standard initialization
87//
88 retrancnt = 0;
89 HaveGroups = 0;
90 HaveNetGroups = 0;
91 options = No_Group_Opt;
92 domain = 0;
93 LifeTime = 60*60*12;
94}
95
96/******************************************************************************/
97/* A d d N a m e */
98/******************************************************************************/
99
100char *XrdAccGroups::AddName(const XrdAccGroupType gtype, const char *name)
101{
102 char *np;
104
105// Prepare to add a group name
106//
107 if (gtype == XrdAccNetGroup) {hp = &NetGroup_Names; HaveNetGroups = 1;}
108 else {hp = &Group_Names; HaveGroups = 1;}
109
110// Lock the Name hash table
111//
112 Group_Name_Context.Lock();
113
114// Add a name into the name hash table. We need to only keep a single
115// read/only copy of the group name to speed multi-threading.
116//
117 if (!(np = hp->Find(name)))
118 {hp->Add(name, 0, 0, Hash_data_is_key);
119 if (!(np = hp->Find(name)))
120 std::cerr <<"XrdAccGroups: Unable to add group " <<name <<std::endl;
121 }
122
123// All done.
124//
125 Group_Name_Context.UnLock();
126 return np;
127}
128
129/******************************************************************************/
130/* F i n d N a m e */
131/******************************************************************************/
132
133char *XrdAccGroups::FindName(const XrdAccGroupType gtype, const char *name)
134{
135 char *np;
136
137// Lock the Name hash table
138//
139 Group_Name_Context.Lock();
140
141// Lookup the actual name in the hash table
142//
143 if (gtype == XrdAccNetGroup) np = NetGroup_Names.Find(name);
144 else np = Group_Names.Find(name);
145
146// All done.
147//
148 Group_Name_Context.UnLock();
149 return np;
150}
151
152/******************************************************************************/
153/* */
154/* G r o u p s ( u s e r ) */
155/* */
156/******************************************************************************/
157
159{
160struct group *gr;
161struct passwd *pw;
162char **cp;
163XrdAccGroupList *glist;
164int gtabi;
165char *Gtab[NGROUPS_MAX];
166
167// Check if we have any referenced groups
168//
169 if (!HaveGroups) return (XrdAccGroupList *)0;
170
171
172// Check if we already have this user in the group cache. Since we may be
173// modifying the cache, we need to have exclusive control over it. We must
174// copy the group cache because the original may be deleted at any time.
175//
176 Group_Cache_Context.Lock();
177 if ((glist = Group_Cache.Find(user)))
178 {if (glist->First()) glist = new XrdAccGroupList(*glist);
179 else glist = 0;
180 Group_Cache_Context.UnLock();
181 return glist;
182 }
183 Group_Cache_Context.UnLock();
184
185// If the user has no password file entry, then we have no groups for user.
186// All code that tries to construct a group list is protected by the
187// Group_Build_Context mutex, obtained after we get the pwd entry.
188//
189 XrdSysPwd thePwd(user, &pw);
190 if (pw == NULL) return (XrdAccGroupList *)0;
191
192// Build first entry for the primary group. We will ignore the primary group
193// listing later. We do this to ensure that the user has at least one group
194// regardless of what the groups file actually says.
195//
196 Group_Build_Context.Lock();
197 gtabi = addGroup(user, pw->pw_gid, 0, Gtab, 0);
198
199// Now run through all of the group entries getting the list of user's groups
200// Do this only when Primary_Only is not turned on (i.e., SVR5 semantics)
201//
202 if (!(options & Primary_Only))
203 {
204 setgrent() ;
205 while ((gr = getgrent()))
206 {
207 if (pw->pw_gid == gr->gr_gid) continue; /*Already have this one.*/
208 for (cp = gr->gr_mem; cp && *cp; cp++)
209 if (strcmp(*cp, user) == 0)
210 gtabi = addGroup(user, gr->gr_gid,
211 Dotran(gr->gr_gid,gr->gr_name),
212 Gtab, gtabi);
213 }
214 endgrent();
215 }
216
217// All done with non mt-safe routines
218//
219 Group_Build_Context.UnLock();
220
221// Allocate a new GroupList object
222//
223 glist = new XrdAccGroupList(gtabi, (const char **)Gtab);
224
225// Add this user to the group cache to speed things up the next time
226//
227 Group_Cache_Context.Lock();
228 Group_Cache.Add(user, glist, LifeTime);
229 Group_Cache_Context.UnLock();
230
231// Return a copy of the group list since the original may be deleted
232//
233 if (!gtabi) return (XrdAccGroupList *)0;
234 return new XrdAccGroupList(gtabi, (const char **)Gtab);
235}
236
237/******************************************************************************/
238/* N e t G r o u p s ( u s e r , h o s t ) */
239/******************************************************************************/
240
241XrdAccGroupList *XrdAccGroups::NetGroups(const char *user, const char *host)
242{
243XrdAccGroupList *glist;
244int i, j;
245char uh_key[MAXHOSTNAMELEN+96];
246struct XrdAccGroupArgs GroupTab;
247int XrdAccCheckNetGroup(const char *netgroup, char *key, void *Arg);
248
249// Check if we have any Netgroups
250//
251 if (!HaveNetGroups) return (XrdAccGroupList *)0;
252
253// Construct the key for this user
254//
255 i = strlen(user); j = strlen(host);
256 if (i+j+2 > (int)sizeof(uh_key)) return (XrdAccGroupList *)0;
257 strcpy(uh_key, user);
258 uh_key[i] = '@';
259 strcpy(&uh_key[i+1], host);
260
261// Check if we already have this user in the group cache. Since we may be
262// modifying the cache, we need to have exclusive control over it. We must
263// copy the group cache entry because the original may be deleted at any time.
264//
265 NetGroup_Cache_Context.Lock();
266 if ((glist = NetGroup_Cache.Find(uh_key)))
267 {if (glist->First()) glist = new XrdAccGroupList(*glist);
268 else glist = 0;
269 NetGroup_Cache_Context.UnLock();
270 return glist;
271 }
272 NetGroup_Cache_Context.UnLock();
273
274// For each known netgroup, check to see if the user is in the netgroup.
275//
276 GroupTab.user = user;
277 GroupTab.host = host;
278 GroupTab.gtabi = 0;
279 Group_Name_Context.Lock();
280 NetGroup_Names.Apply(XrdAccCheckNetGroup, (void *)&GroupTab);
281 Group_Name_Context.UnLock();
282
283// Allocate a new GroupList object
284//
285 glist = new XrdAccGroupList(GroupTab.gtabi,
286 (const char **)GroupTab.Gtab);
287
288// Add this user to the group cache to speed things up the next time
289//
290 NetGroup_Cache_Context.Lock();
291 NetGroup_Cache.Add((const char *)uh_key, glist, LifeTime);
292 NetGroup_Cache_Context.UnLock();
293
294// Return a copy of the group list
295//
296 if (!GroupTab.gtabi) return (XrdAccGroupList *)0;
297 return new XrdAccGroupList(GroupTab.gtabi,
298 (const char **)GroupTab.Gtab);
299}
300
301/******************************************************************************/
302/* P u r g e C a c h e */
303/******************************************************************************/
304
306{
307
308// Purge the group cache
309//
310 Group_Cache_Context.Lock();
311 Group_Cache.Purge();
312 Group_Cache_Context.UnLock();
313
314// Purge the netgroup cache
315//
316 NetGroup_Cache_Context.Lock();
317 NetGroup_Cache.Purge();
318 NetGroup_Cache_Context.UnLock();
319}
320
321/******************************************************************************/
322/* R e t r a n */
323/******************************************************************************/
324
325int XrdAccGroups::Retran(const gid_t gid)
326{
327 if ((int)gid < 0) retrancnt = 0;
328 else {if (retrancnt > (int)(sizeof(retrangid)/sizeof(gid_t))) return -1;
329 retrangid[retrancnt++] = gid;
330 }
331 return 0;
332}
333
334/******************************************************************************/
335/* P r i v a t e M e t h o d s */
336/******************************************************************************/
337
338/******************************************************************************/
339/* a d d G r o u p */
340/******************************************************************************/
341
342int XrdAccGroups::addGroup(const char *user, const gid_t gid, char *gname,
343 char **Gtab, int gtabi)
344{
345 char *gp;
346
347// Check if we have room to add another group. We can squeek by such errors
348// because all it means is that the user normally has fewer privs (which is
349// not always true, sigh).
350//
351 if (gtabi >= NGROUPS_MAX)
352 {if (gtabi == NGROUPS_MAX)
353 std::cerr <<"XrdAccGroups: More than " <<gtabi <<"groups for " <<user <<std::endl;
354 return gtabi;
355 }
356
357// See if we should lookup the group name. The caller had better be holding the
358// Group_Build_Context mutex.
359//
360if (!gname || !gname[0])
361 {struct group *gp;
362 if ((gp = getgrgid(gid)) == NULL) return gtabi;
363 else gname = gp->gr_name;
364 }
365
366// Check if we have this group registered. Only a handful of groups are
367// actually relevant. Ignore the unreferenced groups. If registered, we
368// need the persistent name because of multi-threading issues.
369//
370 if (!(gp = Group_Names.Find(gname)) ) return gtabi;
371
372// Add the groupname to the table of groups for the user
373//
374 Gtab[gtabi++] = gp;
375 return gtabi;
376}
377
378/******************************************************************************/
379/* D o t r a n */
380/******************************************************************************/
381
382char *XrdAccGroups::Dotran(const gid_t gid, char *gname)
383{
384 int i;
385
386 // See if the groupname needs to be retranslated. This is necessary
387 // When multiple groups share the same gid due to NIS constraints.
388 //
389 for (i = 0; i < retrancnt; i++) if (retrangid[i] == gid) return (char *)0;
390 return gname;
391}
392
393/******************************************************************************/
394/* E x t e r n a l F u n c t i o n s */
395/******************************************************************************/
396
397/******************************************************************************/
398/* o o a c c _ C h e c k N e t G r o u p */
399/******************************************************************************/
400
401int XrdAccCheckNetGroup(const char *netgroup, char *key, void *Arg)
402{
403 struct XrdAccGroupArgs *grp = static_cast<struct XrdAccGroupArgs *>(Arg);
404
405 // Check if this netgroup, user, host, domain combination exists.
406 //
407 if (innetgr(netgroup, (const char *)grp->host, (const char *)grp->user,
408 XrdAccGroupMaster.Domain()))
409 {if (grp->gtabi >= NGROUPS_MAX)
410 {if (grp->gtabi == NGROUPS_MAX)
411 std::cerr <<"XrdAccGroups: More than " <<grp->gtabi <<"netgroups for " <<grp->user <<std::endl;
412 return 1;
413 }
414
415 // Add the groupname into the groupname hash table. We have already
416 // been passed the read/only copy of the name.
417 //
418 grp->Gtab[grp->gtabi] = netgroup; grp->gtabi++;
419 }
420 return 0;
421}
const char * user
int XrdAccCheckNetGroup(const char *netgroup, char *key, void *Arg)
XrdAccGroups XrdAccGroupMaster
const char * Gtab[NGROUPS_MAX]
const char * host
XrdAccGroupType
@ XrdAccNetGroup
@ No_Group_Opt
@ Primary_Only
@ Hash_data_is_key
Definition XrdOucHash.hh:52
const char * First()
char * AddName(const XrdAccGroupType gtype, const char *name)
int Retran(const gid_t gid)
XrdAccGroupList * Groups(const char *user)
XrdAccGroupList * NetGroups(const char *user, const char *host)
char * FindName(const XrdAccGroupType gtype, const char *name)
T * Add(const char *KeyVal, T *KeyData, const int LifeTime=0, XrdOucHash_Options opt=Hash_default)
T * Find(const char *KeyVal, time_t *KeyTime=0)