/******************************************************************************/ /* */ /* X r d A c c G r o u p s . c c */ /* */ /* (c) 2003 by the Board of Trustees of the Leland Stanford, Jr., University */ /* All Rights Reserved */ /* Produced by Andrew Hanushevsky for Stanford University under contract */ /* DE-AC02-76-SFO0515 with the Department of Energy */ /* */ /* This file is part of the XRootD software suite. */ /* */ /* XRootD is free software: you can redistribute it and/or modify it under */ /* the terms of the GNU Lesser General Public License as published by the */ /* Free Software Foundation, either version 3 of the License, or (at your */ /* option) any later version. */ /* */ /* XRootD is distributed in the hope that it will be useful, but WITHOUT */ /* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or */ /* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public */ /* License for more details. */ /* */ /* You should have received a copy of the GNU Lesser General Public License */ /* along with XRootD in a file called COPYING.LESSER (LGPL license) and file */ /* COPYING (GPL license). If not, see . */ /* */ /* The copyright holder's institutional names and contributor's names may not */ /* be used to endorse or promote products derived from this software without */ /* specific prior written permission of the institution or contributor. */ /******************************************************************************/ #include #include #include #include #include #include #include #include #include #include #include "XrdSys/XrdSysHeaders.hh" #include "XrdSys/XrdSysPwd.hh" #include "XrdAcc/XrdAccCapability.hh" #include "XrdAcc/XrdAccGroups.hh" #include "XrdAcc/XrdAccPrivs.hh" // Additionally, this routine does not support a user in more than // NGROUPS_MAX groups. This is a standard unix limit defined in limits.h. /******************************************************************************/ /* G l o b a l G r o u p s O b j e c t */ /******************************************************************************/ // There is only one Groups object that handles group memberships. Others // needing access to this object should declare an extern to this object. // XrdAccGroups XrdAccGroupMaster; /******************************************************************************/ /* 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 */ /******************************************************************************/ struct XrdAccGroupArgs {const char *user; const char *host; int gtabi; const char *Gtab[NGROUPS_MAX]; }; /******************************************************************************/ /* C o n s t r u c t o r */ /******************************************************************************/ XrdAccGroups::XrdAccGroups() { // Do standard initialization // retrancnt = 0; HaveGroups = 0; HaveNetGroups = 0; options = No_Group_Opt; domain = 0; LifeTime = 60*60*12; } /******************************************************************************/ /* A d d N a m e */ /******************************************************************************/ char *XrdAccGroups::AddName(const XrdAccGroupType gtype, const char *name) { char *np; XrdOucHash *hp; // Prepare to add a group name // if (gtype == XrdAccNetGroup) {hp = &NetGroup_Names; HaveNetGroups = 1;} else {hp = &Group_Names; HaveGroups = 1;} // Lock the Name hash table // Group_Name_Context.Lock(); // Add a name into the name hash table. We need to only keep a single // read/only copy of the group name to speed multi-threading. // if (!(np = hp->Find(name))) {hp->Add(name, 0, 0, Hash_data_is_key); if (!(np = hp->Find(name))) cerr <<"XrdAccGroups: Unable to add group " <First()) glist = new XrdAccGroupList(*glist); else glist = 0; Group_Cache_Context.UnLock(); return glist; } Group_Cache_Context.UnLock(); // If the user has no password file entry, then we have no groups for user. // All code that tries to construct a group list is protected by the // Group_Build_Context mutex, obtained after we get the pwd entry. // XrdSysPwd thePwd(user, &pw); if (pw == NULL) return (XrdAccGroupList *)0; // Build first entry for the primary group. We will ignore the primary group // listing later. We do this to ensure that the user has at least one group // regardless of what the groups file actually says. // Group_Build_Context.Lock(); gtabi = addGroup(user, pw->pw_gid, 0, Gtab, 0); // Now run through all of the group entries getting the list of user's groups // Do this only when Primary_Only is not turned on (i.e., SVR5 semantics) // if (!(options & Primary_Only)) { setgrent() ; while ((gr = getgrent())) { if (pw->pw_gid == gr->gr_gid) continue; /*Already have this one.*/ for (cp = gr->gr_mem; cp && *cp; cp++) if (strcmp(*cp, user) == 0) gtabi = addGroup(user, gr->gr_gid, Dotran(gr->gr_gid,gr->gr_name), Gtab, gtabi); } endgrent(); } // All done with non mt-safe routines // Group_Build_Context.UnLock(); // Allocate a new GroupList object // glist = new XrdAccGroupList(gtabi, (const char **)Gtab); // Add this user to the group cache to speed things up the next time // Group_Cache_Context.Lock(); Group_Cache.Add(user, glist, LifeTime); Group_Cache_Context.UnLock(); // Return a copy of the group list since the original may be deleted // if (!gtabi) return (XrdAccGroupList *)0; return new XrdAccGroupList(gtabi, (const char **)Gtab); } /******************************************************************************/ /* N e t G r o u p s ( u s e r , h o s t ) */ /******************************************************************************/ XrdAccGroupList *XrdAccGroups::NetGroups(const char *user, const char *host) { XrdAccGroupList *glist; int i, j; char uh_key[MAXHOSTNAMELEN+96]; struct XrdAccGroupArgs GroupTab; int XrdAccCheckNetGroup(const char *netgroup, char *key, void *Arg); // Check if we have any Netgroups // if (!HaveNetGroups) return (XrdAccGroupList *)0; // Construct the key for this user // i = strlen(user); j = strlen(host); if (i+j+2 > (int)sizeof(uh_key)) return (XrdAccGroupList *)0; strcpy(uh_key, user); uh_key[i] = '@'; strcpy(&uh_key[i+1], host); // Check if we already have this user in the group cache. Since we may be // modifying the cache, we need to have exclusive control over it. We must // copy the group cache entry because the original may be deleted at any time. // NetGroup_Cache_Context.Lock(); if ((glist = NetGroup_Cache.Find(uh_key))) {if (glist->First()) glist = new XrdAccGroupList(*glist); else glist = 0; NetGroup_Cache_Context.UnLock(); return glist; } NetGroup_Cache_Context.UnLock(); // For each known netgroup, check to see if the user is in the netgroup. // GroupTab.user = user; GroupTab.host = host; GroupTab.gtabi = 0; Group_Name_Context.Lock(); NetGroup_Names.Apply(XrdAccCheckNetGroup, (void *)&GroupTab); Group_Name_Context.UnLock(); // Allocate a new GroupList object // glist = new XrdAccGroupList(GroupTab.gtabi, (const char **)GroupTab.Gtab); // Add this user to the group cache to speed things up the next time // NetGroup_Cache_Context.Lock(); NetGroup_Cache.Add((const char *)uh_key, glist, LifeTime); NetGroup_Cache_Context.UnLock(); // Return a copy of the group list // if (!GroupTab.gtabi) return (XrdAccGroupList *)0; return new XrdAccGroupList(GroupTab.gtabi, (const char **)GroupTab.Gtab); } /******************************************************************************/ /* P u r g e C a c h e */ /******************************************************************************/ void XrdAccGroups::PurgeCache() { // Purge the group cache // Group_Cache_Context.Lock(); Group_Cache.Purge(); Group_Cache_Context.UnLock(); // Purge the netgroup cache // NetGroup_Cache_Context.Lock(); NetGroup_Cache.Purge(); NetGroup_Cache_Context.UnLock(); } /******************************************************************************/ /* R e t r a n */ /******************************************************************************/ int XrdAccGroups::Retran(const gid_t gid) { if ((int)gid < 0) retrancnt = 0; else {if (retrancnt > (int)(sizeof(retrangid)/sizeof(gid_t))) return -1; retrangid[retrancnt++] = gid; } return 0; } /******************************************************************************/ /* P r i v a t e M e t h o d s */ /******************************************************************************/ /******************************************************************************/ /* a d d G r o u p */ /******************************************************************************/ int XrdAccGroups::addGroup(const char *user, const gid_t gid, char *gname, char **Gtab, int gtabi) { char *gp; // Check if we have room to add another group. We can squeek by such errors // because all it means is that the user normally has fewer privs (which is // not always true, sigh). // if (gtabi >= NGROUPS_MAX) {if (gtabi == NGROUPS_MAX) cerr <<"XrdAccGroups: More than " <gr_name; } // Check if we have this group registered. Only a handful of groups are // actually relevant. Ignore the unreferenced groups. If registered, we // need the persistent name because of multi-threading issues. // if (!(gp = Group_Names.Find(gname)) ) return gtabi; // Add the groupname to the table of groups for the user // Gtab[gtabi++] = gp; return gtabi; } /******************************************************************************/ /* D o t r a n */ /******************************************************************************/ char *XrdAccGroups::Dotran(const gid_t gid, char *gname) { int i; // See if the groupname needs to be retranslated. This is necessary // When multiple groups share the same gid due to NIS constraints. // for (i = 0; i < retrancnt; i++) if (retrangid[i] == gid) return (char *)0; return gname; } /******************************************************************************/ /* E x t e r n a l F u n c t i o n s */ /******************************************************************************/ /******************************************************************************/ /* o o a c c _ C h e c k N e t G r o u p */ /******************************************************************************/ int XrdAccCheckNetGroup(const char *netgroup, char *key, void *Arg) { struct XrdAccGroupArgs *grp = static_cast(Arg); // Check if this netgroup, user, host, domain combination exists. // if (innetgr(netgroup, (const char *)grp->host, (const char *)grp->user, XrdAccGroupMaster.Domain())) {if (grp->gtabi >= NGROUPS_MAX) {if (grp->gtabi == NGROUPS_MAX) cerr <<"XrdAccGroups: More than " <gtabi <<"netgroups for " <user <Gtab[grp->gtabi] = netgroup; grp->gtabi++; } return 0; }