[sudo-workers] Multi-stanza NIS group support (patch enclosed).

Nesius, Robert robert.nesius at intel.com
Thu Feb 22 20:20:05 EST 2007


Hello, 

Please find enclosed a patch to sudo to enable proper support of 
multi-stanza NIS group-maps.  We verified this works but then settled
on using a different work around (net groups).  But in case this can
still 
be of use, here you go.  

Note: I didn't audit this for secure programming.  Someone with 
the appropriate skills may wish to double-check the code.  I just 
wanted to pass this along to the community so that some good may 
come of it.  

Thanks,
-Rob

*** ../sudo-1.6.8p12/parse.c    Sun Jun 19 13:03:24 2005
--- parse.c     Mon Dec 18 16:45:25 2006
***************
*** 442,447 ****
--- 442,580 ----
      return(strcmp(sudoers_user, user) == 0);
  }
  
+ /* problem: Unix groups *may* span multiple entries in the
+  *          group map e.g.:
+  *
+  *          groupname:*:123:user1,user2,user3,...
+  *          groupname:*:123:user243
+  *        
+  *        Large groups in NIS *must* do this due to old
+  *          limitation of udp packet size.  Large sites
+  *        with many users cannot use unix groups in
+  *          sudoers rules unless more complex logic
+  *          is applied to search the duplicate entries.
+  *          Thus the functions below to supplement
+  *          the original simplistic getgrnam() test
+  *          using cached copy of the full group map.
+  *          
+  *          This should also make more efficient the
+  *          entire parsing process of a sudoers file
+  *          having many group definitions, avoiding
+  *          redundant lookups.
+  *
+  * Author: Steve Dempsey <steve.az.dempsey at intel.com>
+  * Date: 18-dec-2006
+  */
+ 
+ static int grps_cached=0;
+ void cache_all_groups();
+ 
+ /* simple dynamic linked list structure to hold the cache */
+ static struct grpcache {
+       struct group *grpdata;
+       struct grpcache *next;
+ } *grpcache=NULL;
+ 
+ /* linear search, sorry - at least it is in memory vs. NIS lookups */
+ struct group *cache_getgrnam(group)
+     char *group;
+ {
+     struct grpcache *gc;
+ 
+     /* fill the cache once as needed */
+     if (!grps_cached)
+        cache_all_groups();
+ 
+     for(gc=grpcache; gc!=NULL; gc=gc->next) {
+         if (strcmp(group,gc->grpdata->gr_name)==0) {
+             return(gc->grpdata);
+         }
+     }
+     return((struct group *)NULL);
+ }
+ 
+ void
+ cache_all_groups(){
+         struct group *g,*ng,*citem;
+       struct grpcache *gc;
+       int nmems;
+         char **cur,**ncur;
+ 
+       /* read the entire map */
+       setgrent();
+         while ((g=getgrent()) != NULL) {
+ 
+         /* test already in cache */
+           if ((citem=cache_getgrnam(g->gr_name)) == NULL) {
+ 
+           /* not in cache, add */
+           ng=emalloc(sizeof(struct group));
+           ng->gr_name=strdup(g->gr_name);
+           ng->gr_passwd=strdup(g->gr_passwd);
+           ng->gr_gid=g->gr_gid;
+ 
+           /* count members */
+           for(nmems=0,cur=g->gr_mem; *cur; cur++) {
+               nmems++;
+           }
+ 
+           /* clone members */
+           ng->gr_mem=(char **)emalloc((nmems+1)*sizeof(char *));
+           for(cur=g->gr_mem,ncur=ng->gr_mem; *cur; cur++,ncur++) {
+               *ncur=strdup(*cur);
+           }
+           *ncur=NULL;
+ 
+           /* prepend on link list is simplest insert */
+           gc = (struct grpcache *) emalloc(sizeof(struct grpcache));
+           gc->next=grpcache;
+           gc->grpdata=ng;
+           grpcache=gc;
+ 
+           } else {
+ 
+           /* have to update existing cache entry with new data */
+           char **merge_mems;
+ 
+           /* count old members */
+           for(nmems=0,cur=citem->gr_mem; *cur; cur++) {
+               nmems++;
+           }
+ 
+           /* count new members */
+           for(cur=g->gr_mem; *cur; cur++) {
+               nmems++;
+           }
+ 
+           /* allocate memory */
+           merge_mems=(char **) emalloc((nmems+1)*sizeof(char *));
+ 
+           /* copy old */
+             for(ncur=merge_mems,cur=citem->gr_mem; *cur; cur++,ncur++)
{
+             *ncur=strdup(*cur);
+           }
+ 
+           /* copy new */
+             for(cur=g->gr_mem; *cur; cur++,ncur++) {
+             *ncur=strdup(*cur);
+           }
+ 
+           /* terminate list */
+           *ncur=NULL;
+ 
+           /* release memory for old */
+           for(cur=citem->gr_mem; *cur; cur++) {
+             free(*cur);
+           }
+           free(citem->gr_mem);
+ 
+           /* replace with new list, keep rest of grp structure */
+           citem->gr_mem = merge_mems;
+           }
+       }
+       grps_cached=1;
+ }
+ 
  /*
   *  Returns TRUE if the given user belongs to the named group,
   *  else returns FALSE.
***************
*** 466,472 ****
        return(FALSE);
      pw_gid = pw->pw_gid;
  
!     if ((grp = getgrnam(group)) == NULL)
        return(FALSE);
  
      /* check against user's primary (passwd file) gid */
--- 599,605 ----
        return(FALSE);
      pw_gid = pw->pw_gid;
  
!     if ((grp = cache_getgrnam(group)) == NULL)
        return(FALSE);
  
      /* check against user's primary (passwd file) gid */



More information about the sudo-workers mailing list