XrdAccGroups.cc

Go to the documentation of this file.
00001 /******************************************************************************/
00002 /*                                                                            */
00003 /*                       X r d A c c G r o u p s . c c                        */
00004 /*                                                                            */
00005 /* (c) 2003 by the Board of Trustees of the Leland Stanford, Jr., University  */
00006 /*                            All Rights Reserved                             */
00007 /*   Produced by Andrew Hanushevsky for Stanford University under contract    */
00008 /*              DE-AC03-76-SFO0515 with the Department of Energy              */
00009 /******************************************************************************/
00010 
00011 //         $Id: XrdAccGroups.cc 38011 2011-02-08 18:35:57Z ganis $
00012 
00013 const char *XrdAccGroupsCVSID = "$Id: XrdAccGroups.cc 38011 2011-02-08 18:35:57Z ganis $";
00014 
00015 #include <unistd.h>
00016 #include <ctype.h>
00017 #include <errno.h>
00018 #include <limits.h>
00019 #include <netdb.h>
00020 #include <pwd.h>
00021 #include <string.h>
00022 #include <strings.h>
00023 #include <sys/param.h>
00024 #include <sys/types.h>
00025 
00026 #include "XrdSys/XrdSysHeaders.hh"
00027 #include "XrdAcc/XrdAccCapability.hh"
00028 #include "XrdAcc/XrdAccGroups.hh"
00029 #include "XrdAcc/XrdAccPrivs.hh"
00030 
00031 // This routine uses non mt-safe routines such as getpwnam, getgrent, etc.
00032 // We do so because we are the only ones using these routines and thet are
00033 // protected by the Group_Build_Context mutex. Anyway, the re-enterant
00034 // version of the same routines are not mt-safe in any case, sigh.
00035 
00036 // Additionally, this routine does not support a user in more than
00037 // NGROUPS_MAX groups. This is a standard unix limit defined in limits.h.
00038   
00039 /******************************************************************************/
00040 /*                  G l o b a l   G r o u p s   O b j e c t                   */
00041 /******************************************************************************/
00042 
00043 // There is only one Groups object that handles group memberships. Others
00044 // needing access to this object should declare an extern to this object.
00045 //
00046 XrdAccGroups XrdAccGroupMaster;
00047   
00048 /******************************************************************************/
00049 /*          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           */
00050 /******************************************************************************/
00051   
00052 struct XrdAccGroupArgs {const char   *user;
00053                         const char   *host;
00054                         int           gtabi;
00055                         const char   *Gtab[NGROUPS_MAX];
00056                        };
00057 
00058 /******************************************************************************/
00059 /*                           C o n s t r u c t o r                            */
00060 /******************************************************************************/
00061   
00062 XrdAccGroups::XrdAccGroups()
00063 {
00064 
00065 // Do standard initialization
00066 //
00067    retrancnt = 0; 
00068    HaveGroups = 0;
00069    HaveNetGroups = 0;
00070    options = No_Group_Opt;
00071    domain = 0;
00072    LifeTime = 60*60*12;
00073 }
00074 
00075 /******************************************************************************/
00076 /*                               A d d N a m e                                */
00077 /******************************************************************************/
00078   
00079 char *XrdAccGroups::AddName(const XrdAccGroupType gtype, const char *name)
00080 {
00081    char *np;
00082    XrdOucHash<char> *hp;
00083 
00084 // Prepare to add a group name
00085 //
00086    if (gtype == XrdAccNetGroup) {hp = &NetGroup_Names; HaveNetGroups = 1;}
00087       else {hp = &Group_Names; HaveGroups = 1;}
00088 
00089 // Lock the Name hash table
00090 //
00091    Group_Name_Context.Lock();
00092 
00093 // Add a name into the name hash table. We need to only keep a single
00094 // read/only copy of the group name to speed multi-threading.
00095 //
00096    if (!(np = hp->Find(name)))
00097       {hp->Add(name, 0, 0, Hash_data_is_key);
00098        if (!(np = hp->Find(name)))
00099            cerr <<"XrdAccGroups: Unable to add group " <<name <<endl;
00100       }
00101 
00102 // All done.
00103 //
00104    Group_Name_Context.UnLock();
00105    return np;
00106 }
00107 
00108 /******************************************************************************/
00109 /*                              F i n d N a m e                               */
00110 /******************************************************************************/
00111   
00112 char *XrdAccGroups::FindName(const XrdAccGroupType gtype, const char *name)
00113 {
00114    char *np;
00115 
00116 // Lock the Name hash table
00117 //
00118    Group_Name_Context.Lock();
00119 
00120 // Lookup the actual name in the hash table
00121 //
00122    if (gtype == XrdAccNetGroup) np = NetGroup_Names.Find(name);
00123       else np = Group_Names.Find(name);
00124 
00125 // All done.
00126 //
00127    Group_Name_Context.UnLock();
00128    return np;
00129 }
00130   
00131 /******************************************************************************/
00132 /*                                                                            */
00133 /*                          G r o u p s ( u s e r )                           */
00134 /*                                                                            */
00135 /******************************************************************************/
00136   
00137 XrdAccGroupList *XrdAccGroups::Groups(const char *user)
00138 {
00139 struct group  *gr;
00140 struct passwd *pw;
00141 char **cp;
00142 XrdAccGroupList *glist;
00143 int   gtabi;
00144 char *Gtab[NGROUPS_MAX];
00145 
00146 // Check if we have any referenced groups
00147 //
00148    if (!HaveGroups) return (XrdAccGroupList *)0;
00149 
00150 
00151 // Check if we already have this user in the group cache. Since we may be
00152 // modifying the cache, we need to have exclusive control over it. We must
00153 // copy the group cache because the original may be deleted at any time.
00154 //
00155    Group_Cache_Context.Lock();
00156    if ((glist = Group_Cache.Find(user)))
00157       {if (glist->First()) glist = new XrdAccGroupList(*glist);
00158           else glist = 0;
00159        Group_Cache_Context.UnLock();
00160        return glist;
00161       }
00162    Group_Cache_Context.UnLock();
00163 
00164 // If the user has no password file entry, then we have no groups for user.
00165 // All code that tries to construct a group list is protected by the
00166 // Group_Build_Context mutex.
00167 //
00168    Group_Build_Context.Lock();
00169    if ( (pw = getpwnam(user)) == NULL)
00170       {Group_Build_Context.UnLock();
00171        return (XrdAccGroupList *)0;
00172       }
00173 
00174 // Build first entry for the primary group. We will ignore the primary group
00175 // listing later. We do this to ensure that the user has at least one group
00176 // regardless of what the groups file actually says.
00177 //
00178    gtabi = addGroup(user, pw->pw_gid, 0, Gtab, 0);
00179 
00180 // Now run through all of the group entries getting the list of user's groups
00181 // Do this only when Primary_Only is not turned on (i.e., SVR5 semantics)
00182 //
00183    if (!(options & Primary_Only))
00184       {
00185        setgrent() ;
00186        while ((gr = getgrent()))
00187             {
00188              if (pw->pw_gid == gr->gr_gid) continue; /*Already have this one.*/
00189              for (cp = gr->gr_mem; cp && *cp; cp++)
00190                  if (strcmp(*cp, user) == 0)
00191                     gtabi = addGroup(user, gr->gr_gid,
00192                                Dotran(gr->gr_gid,gr->gr_name),
00193                                      Gtab, gtabi);
00194             }
00195        endgrent();
00196       }
00197 
00198 // All done with non mt-safe routines
00199 //
00200    Group_Build_Context.UnLock();
00201 
00202 // Allocate a new GroupList object
00203 //
00204    glist = new XrdAccGroupList(gtabi, (const char **)Gtab);
00205 
00206 // Add this user to the group cache to speed things up the next time
00207 //
00208    Group_Cache_Context.Lock();
00209    Group_Cache.Add(user, glist, LifeTime);
00210    Group_Cache_Context.UnLock();
00211 
00212 // Return a copy of the group list since the original may be deleted
00213 //
00214    if (!gtabi) return (XrdAccGroupList *)0;
00215    return new XrdAccGroupList(gtabi, (const char **)Gtab);
00216 }
00217  
00218 /******************************************************************************/
00219 /*                 N e t G r o u p s ( u s e r ,   h o s t )                  */
00220 /******************************************************************************/
00221   
00222 XrdAccGroupList *XrdAccGroups::NetGroups(const char *user, const char *host)
00223 {
00224 XrdAccGroupList *glist;
00225 int   i, j;
00226 char uh_key[MAXHOSTNAMELEN+96];
00227 struct XrdAccGroupArgs GroupTab;
00228 int XrdAccCheckNetGroup(const char *netgroup, char *key, void *Arg);
00229 
00230 // Check if we have any Netgroups
00231 //
00232    if (!HaveNetGroups) return (XrdAccGroupList *)0;
00233 
00234 // Construct the key for this user
00235 //
00236    i = strlen(user); j = strlen(host);
00237    if (i+j+2 > (int)sizeof(uh_key)) return (XrdAccGroupList *)0;
00238    strcpy(uh_key, user);
00239    uh_key[i] = '@';
00240    strcpy(&uh_key[i+1], host);
00241 
00242 // Check if we already have this user in the group cache. Since we may be
00243 // modifying the cache, we need to have exclusive control over it. We must
00244 // copy the group cache entry because the original may be deleted at any time.
00245 //
00246    NetGroup_Cache_Context.Lock();
00247    if ((glist = NetGroup_Cache.Find(uh_key)))
00248       {if (glist->First()) glist = new XrdAccGroupList(*glist);
00249           else glist = 0;
00250        NetGroup_Cache_Context.UnLock();
00251        return glist;
00252       }
00253    NetGroup_Cache_Context.UnLock();
00254 
00255 // For each known netgroup, check to see if the user is in the netgroup.
00256 //
00257    GroupTab.user  = user;
00258    GroupTab.host  = host;
00259    GroupTab.gtabi = 0;
00260    Group_Name_Context.Lock();
00261    NetGroup_Names.Apply(XrdAccCheckNetGroup, (void *)&GroupTab);
00262    Group_Name_Context.UnLock();
00263 
00264 // Allocate a new GroupList object
00265 //
00266    glist = new XrdAccGroupList(GroupTab.gtabi,
00267                            (const char **)GroupTab.Gtab);
00268 
00269 // Add this user to the group cache to speed things up the next time
00270 //
00271    NetGroup_Cache_Context.Lock();
00272    NetGroup_Cache.Add((const char *)uh_key, glist, LifeTime);
00273    NetGroup_Cache_Context.UnLock();
00274 
00275 // Return a copy of the group list
00276 //
00277    if (!GroupTab.gtabi) return (XrdAccGroupList *)0;
00278    return new XrdAccGroupList(GroupTab.gtabi,
00279                           (const char **)GroupTab.Gtab);
00280 }
00281 
00282 /******************************************************************************/
00283 /*                            P u r g e C a c h e                             */
00284 /******************************************************************************/
00285 
00286 void XrdAccGroups::PurgeCache()
00287 {
00288 
00289 // Purge the group cache
00290 //
00291    Group_Cache_Context.Lock();
00292    Group_Cache.Purge();
00293    Group_Cache_Context.UnLock();
00294 
00295 // Purge the netgroup cache
00296 //
00297    NetGroup_Cache_Context.Lock();
00298    NetGroup_Cache.Purge();
00299    NetGroup_Cache_Context.UnLock();
00300 }
00301   
00302 /******************************************************************************/
00303 /*                                R e t r a n                                 */
00304 /******************************************************************************/
00305   
00306 int XrdAccGroups::Retran(const gid_t gid)
00307 {
00308     if ((int)gid < 0) retrancnt = 0;
00309        else {if (retrancnt > (int)(sizeof(retrangid)/sizeof(gid_t))) return -1;
00310              retrangid[retrancnt++] = gid;
00311             }
00312     return 0;
00313 }
00314 
00315 /******************************************************************************/
00316 /*                       P r i v a t e   M e t h o d s                        */
00317 /******************************************************************************/
00318   
00319 /******************************************************************************/
00320 /*                              a d d G r o u p                               */
00321 /******************************************************************************/
00322   
00323 int XrdAccGroups::addGroup(const char *user, const gid_t gid, char *gname,
00324                            char **Gtab, int gtabi)
00325 {
00326    char *gp;
00327 
00328 // Check if we have room to add another group. We can squeek by such errors
00329 // because all it means is that the user normally has fewer privs (which is
00330 // not always true, sigh).
00331 //
00332    if (gtabi >= NGROUPS_MAX)
00333       {if (gtabi == NGROUPS_MAX)
00334           cerr <<"XrdAccGroups: More than " <<gtabi <<"groups for " <<user <<endl;
00335        return gtabi;
00336       }
00337 
00338 // See if we should lookup the group name. The caller had better be holding the
00339 // Group_Build_Context mutex.
00340 //
00341 if (!gname || !gname[0])
00342    {struct group *gp;
00343     if ((gp = getgrgid(gid)) == NULL) return gtabi;
00344              else gname = gp->gr_name;
00345    }
00346 
00347 // Check if we have this group registered. Only a handful of groups are
00348 // actually relevant. Ignore the unreferenced groups. If registered, we
00349 // need the persistent name because of multi-threading issues.
00350 //
00351    if (!(gp = Group_Names.Find(gname)) ) return gtabi;
00352 
00353 // Add the groupname to the table of groups for the user
00354 //
00355    Gtab[gtabi++] = gp;
00356    return gtabi;
00357 }
00358 
00359 /******************************************************************************/
00360 /*                                D o t r a n                                 */
00361 /******************************************************************************/
00362   
00363 char *XrdAccGroups::Dotran(const gid_t gid, char *gname)
00364 {
00365      int i;
00366 
00367     // See if the groupname needs to be retranslated. This is necessary
00368     // When multiple groups share the same gid due to NIS constraints.
00369     //
00370     for (i = 0; i < retrancnt; i++) if (retrangid[i] == gid) return (char *)0;
00371     return gname;
00372 }
00373 
00374 /******************************************************************************/
00375 /*                    E x t e r n a l   F u n c t i o n s                     */
00376 /******************************************************************************/
00377 
00378 /******************************************************************************/
00379 /*                   o o a c c _ C h e c k N e t G r o u p                    */
00380 /******************************************************************************/
00381   
00382 int XrdAccCheckNetGroup(const char *netgroup, char *key, void *Arg)
00383 {
00384     struct XrdAccGroupArgs *grp = static_cast<struct XrdAccGroupArgs *>(Arg);
00385 
00386     // Check if this netgroup, user, host, domain combination exists.
00387     //
00388     if (innetgr(netgroup, (const char *)grp->host, (const char *)grp->user,
00389                 XrdAccGroupMaster.Domain()))
00390        {if (grp->gtabi >= NGROUPS_MAX) 
00391            {if (grp->gtabi == NGROUPS_MAX)
00392                cerr <<"XrdAccGroups: More than " <<grp->gtabi <<"netgroups for " <<grp->user <<endl;
00393             return 1;
00394            }
00395 
00396         // Add the groupname into the groupname hash table. We have already
00397         // been passed the read/only copy of the name.
00398         //
00399         grp->Gtab[grp->gtabi] = netgroup; grp->gtabi++;
00400        }
00401     return 0;
00402 }

Generated on Tue Jul 5 14:46:15 2011 for ROOT_528-00b_version by  doxygen 1.5.1