[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