Diff for /embedaddon/sudo/plugins/sudoers/pwutil.c between versions 1.1.1.3 and 1.1.1.4

version 1.1.1.3, 2012/10/09 09:29:52 version 1.1.1.4, 2013/07/22 10:46:12
Line 1 Line 1
 /*  /*
 * Copyright (c) 1996, 1998-2005, 2007-2012 * Copyright (c) 1996, 1998-2005, 2007-2013
  *      Todd C. Miller <Todd.Miller@courtesan.com>   *      Todd C. Miller <Todd.Miller@courtesan.com>
  *   *
  * Permission to use, copy, modify, and distribute this software for any   * Permission to use, copy, modify, and distribute this software for any
Line 22 Line 22
 #include <config.h>  #include <config.h>
   
 #include <sys/types.h>  #include <sys/types.h>
 #include <sys/stat.h>  
 #include <sys/param.h>  
 #include <stdio.h>  #include <stdio.h>
 #ifdef STDC_HEADERS  #ifdef STDC_HEADERS
 # include <stdlib.h>  # include <stdlib.h>
Line 48 Line 46
 #ifdef HAVE_SETAUTHDB  #ifdef HAVE_SETAUTHDB
 # include <usersec.h>  # include <usersec.h>
 #endif /* HAVE_SETAUTHDB */  #endif /* HAVE_SETAUTHDB */
 #ifdef HAVE_UTMPX_H  
 # include <utmpx.h>  
 #else  
 # include <utmp.h>  
 #endif /* HAVE_UTMPX_H */  
 #include <limits.h>  
 #include <pwd.h>  #include <pwd.h>
 #include <grp.h>  #include <grp.h>
   
 #include "sudoers.h"  #include "sudoers.h"
 #include "redblack.h"  #include "redblack.h"
   #include "pwutil.h"
   
 /*  /*
  * The passwd and group caches.   * The passwd and group caches.
Line 73  static int  cmp_grgid(const void *, const void *); Line 66  static int  cmp_grgid(const void *, const void *);
   
 #define cmp_grnam       cmp_pwnam  #define cmp_grnam       cmp_pwnam
   
 #define ptr_to_item(p) ((struct cache_item *)((char *)p - offsetof(struct cache_item_##p, p)))  
   
 /*  /*
  * Generic cache element.  
  */  
 struct cache_item {  
     unsigned int refcnt;  
     /* key */  
     union {  
         uid_t uid;  
         gid_t gid;  
         char *name;  
     } k;  
     /* datum */  
     union {  
         struct passwd *pw;  
         struct group *gr;  
         struct group_list *grlist;  
     } d;  
 };  
   
 /*  
  * Container structs to simpify size and offset calculations and guarantee  
  * proper aligment of struct passwd, group and group_list.  
  */  
 struct cache_item_pw {  
     struct cache_item cache;  
     struct passwd pw;  
 };  
   
 struct cache_item_gr {  
     struct cache_item cache;  
     struct group gr;  
 };  
   
 struct cache_item_grlist {  
     struct cache_item cache;  
     struct group_list grlist;  
     /* actually bigger */  
 };  
   
 /*  
  * Compare by uid.   * Compare by uid.
  */   */
 static int  static int
Line 136  cmp_pwnam(const void *v1, const void *v2) Line 88  cmp_pwnam(const void *v1, const void *v2)
     return strcmp(ci1->k.name, ci2->k.name);      return strcmp(ci1->k.name, ci2->k.name);
 }  }
   
 #define FIELD_SIZE(src, name, size)                     \  
 do {                                                    \  
         if (src->name) {                                \  
                 size = strlen(src->name) + 1;           \  
                 total += size;                          \  
         }                                               \  
 } while (0)  
   
 #define FIELD_COPY(src, dst, name, size)                \  
 do {                                                    \  
         if (src->name) {                                \  
                 memcpy(cp, src->name, size);            \  
                 dst->name = cp;                         \  
                 cp += size;                             \  
         }                                               \  
 } while (0)  
   
 /*  
  * Dynamically allocate space for a struct item plus the key and data  
  * elements.  If name is non-NULL it is used as the key, else the  
  * uid is the key.  Fills in datum from struct password.  
  */  
 static struct cache_item *  
 make_pwitem(const struct passwd *pw, const char *name)  
 {  
     char *cp;  
     const char *pw_shell;  
     size_t nsize, psize, csize, gsize, dsize, ssize, total;  
     struct cache_item_pw *pwitem;  
     struct passwd *newpw;  
     debug_decl(make_pwitem, SUDO_DEBUG_NSS)  
   
     /* If shell field is empty, expand to _PATH_BSHELL. */  
     pw_shell = (pw->pw_shell == NULL || pw->pw_shell[0] == '\0')  
         ? _PATH_BSHELL : pw->pw_shell;  
   
     /* Allocate in one big chunk for easy freeing. */  
     nsize = psize = csize = gsize = dsize = ssize = 0;  
     total = sizeof(*pwitem);  
     FIELD_SIZE(pw, pw_name, nsize);  
     FIELD_SIZE(pw, pw_passwd, psize);  
 #ifdef HAVE_LOGIN_CAP_H  
     FIELD_SIZE(pw, pw_class, csize);  
 #endif  
     FIELD_SIZE(pw, pw_gecos, gsize);  
     FIELD_SIZE(pw, pw_dir, dsize);  
     /* Treat shell specially since we expand "" -> _PATH_BSHELL */  
     ssize = strlen(pw_shell) + 1;  
     total += ssize;  
     if (name != NULL)  
         total += strlen(name) + 1;  
   
     /* Allocate space for struct item, struct passwd and the strings. */  
     pwitem = ecalloc(1, total);  
     newpw = &pwitem->pw;  
   
     /*  
      * Copy in passwd contents and make strings relative to space  
      * at the end of the struct.  
      */  
     memcpy(newpw, pw, sizeof(*pw));  
     cp = (char *)(pwitem + 1);  
     FIELD_COPY(pw, newpw, pw_name, nsize);  
     FIELD_COPY(pw, newpw, pw_passwd, psize);  
 #ifdef HAVE_LOGIN_CAP_H  
     FIELD_COPY(pw, newpw, pw_class, csize);  
 #endif  
     FIELD_COPY(pw, newpw, pw_gecos, gsize);  
     FIELD_COPY(pw, newpw, pw_dir, dsize);  
     /* Treat shell specially since we expand "" -> _PATH_BSHELL */  
     memcpy(cp, pw_shell, ssize);  
     newpw->pw_shell = cp;  
     cp += ssize;  
   
     /* Set key and datum. */  
     if (name != NULL) {  
         memcpy(cp, name, strlen(name) + 1);  
         pwitem->cache.k.name = cp;  
     } else {  
         pwitem->cache.k.uid = pw->pw_uid;  
     }  
     pwitem->cache.d.pw = newpw;  
     pwitem->cache.refcnt = 1;  
   
     debug_return_ptr(&pwitem->cache);  
 }  
   
 void  void
 sudo_pw_addref(struct passwd *pw)  sudo_pw_addref(struct passwd *pw)
 {  {
Line 272  sudo_getpwuid(uid_t uid) Line 137  sudo_getpwuid(uid_t uid)
 #ifdef HAVE_SETAUTHDB  #ifdef HAVE_SETAUTHDB
     aix_setauthdb(IDtouser(uid));      aix_setauthdb(IDtouser(uid));
 #endif  #endif
    if ((key.d.pw = getpwuid(uid)) != NULL) {    item = sudo_make_pwitem(uid, NULL);
        item = make_pwitem(key.d.pw, NULL);    if (item == NULL) {
        if (rbinsert(pwcache_byuid, item) != NULL) 
            errorx(1, _("unable to cache uid %u (%s), already exists"), 
                (unsigned int) uid, item->d.pw->pw_name); 
    } else { 
         item = ecalloc(1, sizeof(*item));          item = ecalloc(1, sizeof(*item));
         item->refcnt = 1;          item->refcnt = 1;
         item->k.uid = uid;          item->k.uid = uid;
         /* item->d.pw = NULL; */          /* item->d.pw = NULL; */
         if (rbinsert(pwcache_byuid, item) != NULL)  
             errorx(1, _("unable to cache uid %u, already exists"),  
                 (unsigned int) uid);  
     }      }
       if (rbinsert(pwcache_byuid, item) != NULL)
           fatalx(_("unable to cache uid %u, already exists"),
               (unsigned int) uid);
 #ifdef HAVE_SETAUTHDB  #ifdef HAVE_SETAUTHDB
     aix_restoreauthdb();      aix_restoreauthdb();
 #endif  #endif
Line 316  sudo_getpwnam(const char *name) Line 177  sudo_getpwnam(const char *name)
 #ifdef HAVE_SETAUTHDB  #ifdef HAVE_SETAUTHDB
     aix_setauthdb((char *) name);      aix_setauthdb((char *) name);
 #endif  #endif
    if ((key.d.pw = getpwnam(name)) != NULL) {    item = sudo_make_pwitem((uid_t)-1, name);
        item = make_pwitem(key.d.pw, name);    if (item == NULL) {
        if (rbinsert(pwcache_byname, item) != NULL) 
            errorx(1, _("unable to cache user %s, already exists"), name); 
    } else { 
         len = strlen(name) + 1;          len = strlen(name) + 1;
         item = ecalloc(1, sizeof(*item) + len);          item = ecalloc(1, sizeof(*item) + len);
         item->refcnt = 1;          item->refcnt = 1;
         item->k.name = (char *) item + sizeof(*item);          item->k.name = (char *) item + sizeof(*item);
         memcpy(item->k.name, name, len);          memcpy(item->k.name, name, len);
         /* item->d.pw = NULL; */          /* item->d.pw = NULL; */
         if (rbinsert(pwcache_byname, item) != NULL)  
             errorx(1, _("unable to cache user %s, already exists"), name);  
     }      }
       if (rbinsert(pwcache_byname, item) != NULL)
           fatalx(_("unable to cache user %s, already exists"), name);
 #ifdef HAVE_SETAUTHDB  #ifdef HAVE_SETAUTHDB
     aix_restoreauthdb();      aix_restoreauthdb();
 #endif  #endif
Line 339  done: Line 197  done:
 }  }
   
 /*  /*
 * Take a user, uid and gid and return a faked up passwd struct. * Take a user, uid, gid, home and shell and return a faked up passwd struct.
  * If home or shell are NULL default values will be used.
  */   */
 struct passwd *  struct passwd *
sudo_fakepwnamid(const char *user, uid_t uid, gid_t gid)sudo_mkpwent(const char *user, uid_t uid, gid_t gid, const char *home,
     const char *shell)
 {  {
     struct cache_item_pw *pwitem;      struct cache_item_pw *pwitem;
     struct passwd *pw;      struct passwd *pw;
     struct rbnode *node;      struct rbnode *node;
    size_t len, namelen;    size_t len, name_len, home_len, shell_len;
     int i;      int i;
    debug_decl(sudo_fakepwnam, SUDO_DEBUG_NSS)    debug_decl(sudo_mkpwent, SUDO_DEBUG_NSS)
   
    namelen = strlen(user);    /* Optional arguments. */
    len = sizeof(*pwitem) + namelen + 1 /* pw_name */ +    if (home == NULL)
         home = "/";
     if (shell == NULL)
         shell = _PATH_BSHELL;
 
     name_len = strlen(user);
     home_len = strlen(home);
     shell_len = strlen(shell);
     len = sizeof(*pwitem) + name_len + 1 /* pw_name */ +
         sizeof("*") /* pw_passwd */ + sizeof("") /* pw_gecos */ +          sizeof("*") /* pw_passwd */ + sizeof("") /* pw_gecos */ +
        sizeof("/") /* pw_dir */ + sizeof(_PATH_BSHELL);        home_len + 1 /* pw_dir */ + shell_len + 1 /* pw_shell */;
   
     for (i = 0; i < 2; i++) {      for (i = 0; i < 2; i++) {
         pwitem = ecalloc(1, len);          pwitem = ecalloc(1, len);
Line 362  sudo_fakepwnamid(const char *user, uid_t uid, gid_t gi Line 230  sudo_fakepwnamid(const char *user, uid_t uid, gid_t gi
         pw->pw_uid = uid;          pw->pw_uid = uid;
         pw->pw_gid = gid;          pw->pw_gid = gid;
         pw->pw_name = (char *)(pwitem + 1);          pw->pw_name = (char *)(pwitem + 1);
        memcpy(pw->pw_name, user, namelen + 1);        memcpy(pw->pw_name, user, name_len + 1);
        pw->pw_passwd = pw->pw_name + namelen + 1;        pw->pw_passwd = pw->pw_name + name_len + 1;
         memcpy(pw->pw_passwd, "*", 2);          memcpy(pw->pw_passwd, "*", 2);
         pw->pw_gecos = pw->pw_passwd + 2;          pw->pw_gecos = pw->pw_passwd + 2;
         pw->pw_gecos[0] = '\0';          pw->pw_gecos[0] = '\0';
         pw->pw_dir = pw->pw_gecos + 1;          pw->pw_dir = pw->pw_gecos + 1;
        memcpy(pw->pw_dir, "/", 2);        memcpy(pw->pw_dir, home, home_len + 1);
        pw->pw_shell = pw->pw_dir + 2;        pw->pw_shell = pw->pw_dir + home_len + 1;
        memcpy(pw->pw_shell, _PATH_BSHELL, sizeof(_PATH_BSHELL));        memcpy(pw->pw_shell, shell, shell_len + 1);
   
         pwitem->cache.refcnt = 1;          pwitem->cache.refcnt = 1;
         pwitem->cache.d.pw = pw;          pwitem->cache.d.pw = pw;
         if (i == 0) {          if (i == 0) {
            /* Store by uid, overwriting cached version. */            /* Store by uid if it doesn't already exist. */
             pwitem->cache.k.uid = pw->pw_uid;              pwitem->cache.k.uid = pw->pw_uid;
             if ((node = rbinsert(pwcache_byuid, &pwitem->cache)) != NULL) {              if ((node = rbinsert(pwcache_byuid, &pwitem->cache)) != NULL) {
                sudo_pw_delref_item(node->data);                /* Already exists, free the item we created. */
                node->data = &pwitem->cache;                efree(pwitem);
                 pwitem = (struct cache_item_pw *) node->data;
             }              }
         } else {          } else {
            /* Store by name, overwriting cached version. */            /* Store by name if it doesn't already exist. */
             pwitem->cache.k.name = pw->pw_name;              pwitem->cache.k.name = pw->pw_name;
             if ((node = rbinsert(pwcache_byname, &pwitem->cache)) != NULL) {              if ((node = rbinsert(pwcache_byname, &pwitem->cache)) != NULL) {
                sudo_pw_delref_item(node->data);                /* Already exists, free the item we created. */
                node->data = &pwitem->cache;                efree(pwitem);
                 pwitem = (struct cache_item_pw *) node->data;
             }              }
         }          }
     }      }
     pwitem->cache.refcnt++;      pwitem->cache.refcnt++;
    debug_return_ptr(pw);    debug_return_ptr(&pwitem->pw);
 }  }
   
 /*  /*
Line 403  sudo_fakepwnam(const char *user, gid_t gid) Line 273  sudo_fakepwnam(const char *user, gid_t gid)
     uid_t uid;      uid_t uid;
   
     uid = (uid_t) atoi(user + 1);      uid = (uid_t) atoi(user + 1);
    return sudo_fakepwnamid(user, uid, gid);    return sudo_mkpwent(user, uid, gid, NULL, NULL);
 }  }
   
 void  void
Line 459  cmp_grgid(const void *v1, const void *v2) Line 329  cmp_grgid(const void *v1, const void *v2)
     return ci1->k.gid - ci2->k.gid;      return ci1->k.gid - ci2->k.gid;
 }  }
   
 /*  
  * Dynamically allocate space for a struct item plus the key and data  
  * elements.  If name is non-NULL it is used as the key, else the  
  * gid is the key.  Fills in datum from struct group.  
  */  
 static struct cache_item *  
 make_gritem(const struct group *gr, const char *name)  
 {  
     char *cp;  
     size_t nsize, psize, nmem, total, len;  
     struct cache_item_gr *gritem;  
     struct group *newgr;  
     debug_decl(make_gritem, SUDO_DEBUG_NSS)  
   
     /* Allocate in one big chunk for easy freeing. */  
     nsize = psize = nmem = 0;  
     total = sizeof(*gritem);  
     FIELD_SIZE(gr, gr_name, nsize);  
     FIELD_SIZE(gr, gr_passwd, psize);  
     if (gr->gr_mem) {  
         for (nmem = 0; gr->gr_mem[nmem] != NULL; nmem++)  
             total += strlen(gr->gr_mem[nmem]) + 1;  
         nmem++;  
         total += sizeof(char *) * nmem;  
     }  
     if (name != NULL)  
         total += strlen(name) + 1;  
   
     gritem = ecalloc(1, total);  
   
     /*  
      * Copy in group contents and make strings relative to space  
      * at the end of the buffer.  Note that gr_mem must come  
      * immediately after struct group to guarantee proper alignment.  
      */  
     newgr = &gritem->gr;  
     memcpy(newgr, gr, sizeof(*gr));  
     cp = (char *)(gritem + 1);  
     if (gr->gr_mem) {  
         newgr->gr_mem = (char **)cp;  
         cp += sizeof(char *) * nmem;  
         for (nmem = 0; gr->gr_mem[nmem] != NULL; nmem++) {  
             len = strlen(gr->gr_mem[nmem]) + 1;  
             memcpy(cp, gr->gr_mem[nmem], len);  
             newgr->gr_mem[nmem] = cp;  
             cp += len;  
         }  
         newgr->gr_mem[nmem] = NULL;  
     }  
     FIELD_COPY(gr, newgr, gr_passwd, psize);  
     FIELD_COPY(gr, newgr, gr_name, nsize);  
   
     /* Set key and datum. */  
     if (name != NULL) {  
         memcpy(cp, name, strlen(name) + 1);  
         gritem->cache.k.name = cp;  
     } else {  
         gritem->cache.k.gid = gr->gr_gid;  
     }  
     gritem->cache.d.gr = newgr;  
     gritem->cache.refcnt = 1;  
   
     debug_return_ptr(&gritem->cache);  
 }  
   
 #ifdef HAVE_UTMPX_H  
 # define GROUPNAME_LEN  (sizeof((struct utmpx *)0)->ut_user + 1)  
 #else  
 # ifdef HAVE_STRUCT_UTMP_UT_USER  
 #  define GROUPNAME_LEN (sizeof((struct utmp *)0)->ut_user + 1)  
 # else  
 #  define GROUPNAME_LEN (sizeof((struct utmp *)0)->ut_name + 1)  
 # endif  
 #endif /* HAVE_UTMPX_H */  
   
 /*  
  * Dynamically allocate space for a struct item plus the key and data  
  * elements.  Fills in datum from the groups and gids arrays.  
  */  
 static struct cache_item *  
 make_grlist_item(const char *user, GETGROUPS_T *gids, int ngids)  
 {  
     char *cp;  
     size_t i, nsize, ngroups, total, len;  
     struct cache_item_grlist *grlitem;  
     struct group_list *grlist;  
     struct group *grp;  
     debug_decl(make_grlist_item, SUDO_DEBUG_NSS)  
   
 #ifdef HAVE_SETAUTHDB  
     aix_setauthdb((char *) user);  
 #endif  
   
     /* Allocate in one big chunk for easy freeing. */  
     nsize = strlen(user) + 1;  
     total = sizeof(*grlitem) + nsize;  
     total += sizeof(char *) * ngids;  
     total += sizeof(gid_t *) * ngids;  
     total += GROUPNAME_LEN * ngids;  
   
 again:  
     grlitem = ecalloc(1, total);  
   
     /*  
      * Copy in group list and make pointers relative to space  
      * at the end of the buffer.  Note that the groups array must come  
      * immediately after struct group to guarantee proper alignment.  
      */  
     grlist = &grlitem->grlist;  
     cp = (char *)(grlitem + 1);  
     grlist->groups = (char **)cp;  
     cp += sizeof(char *) * ngids;  
     grlist->gids = (gid_t *)cp;  
     cp += sizeof(gid_t) * ngids;  
   
     /* Set key and datum. */  
     memcpy(cp, user, nsize);  
     grlitem->cache.k.name = cp;  
     grlitem->cache.d.grlist = grlist;  
     grlitem->cache.refcnt = 1;  
     cp += nsize;  
   
     /*  
      * Store group IDs.  
      */  
     for (i = 0; i < ngids; i++)  
         grlist->gids[i] = gids[i];  
     grlist->ngids = ngids;  
   
     /*  
      * Resolve and store group names by ID.  
      */  
     ngroups = 0;  
     for (i = 0; i < ngids; i++) {  
         if ((grp = sudo_getgrgid(gids[i])) != NULL) {  
             len = strlen(grp->gr_name) + 1;  
             if (cp - (char *)grlitem + len > total) {  
                 total += len + GROUPNAME_LEN;  
                 efree(grlitem);  
                 sudo_gr_delref(grp);  
                 goto again;  
             }  
             memcpy(cp, grp->gr_name, len);  
             grlist->groups[ngroups++] = cp;  
             cp += len;  
             sudo_gr_delref(grp);  
         }  
     }  
     grlist->ngroups = ngroups;  
   
 #ifdef HAVE_SETAUTHDB  
     aix_restoreauthdb();  
 #endif  
   
     debug_return_ptr(&grlitem->cache);  
 }  
   
 void  void
 sudo_gr_addref(struct group *gr)  sudo_gr_addref(struct group *gr)
 {  {
Line 662  sudo_getgrgid(gid_t gid) Line 375  sudo_getgrgid(gid_t gid)
     /*      /*
      * Cache group db entry if it exists or a negative response if not.       * Cache group db entry if it exists or a negative response if not.
      */       */
    if ((key.d.gr = getgrgid(gid)) != NULL) {    item = sudo_make_gritem(gid, NULL);
        item = make_gritem(key.d.gr, NULL);    if (item == NULL) {
        if (rbinsert(grcache_bygid, item) != NULL) 
            errorx(1, _("unable to cache gid %u (%s), already exists"), 
                (unsigned int) gid, key.d.gr->gr_name); 
    } else { 
         item = ecalloc(1, sizeof(*item));          item = ecalloc(1, sizeof(*item));
         item->refcnt = 1;          item->refcnt = 1;
         item->k.gid = gid;          item->k.gid = gid;
         /* item->d.gr = NULL; */          /* item->d.gr = NULL; */
         if (rbinsert(grcache_bygid, item) != NULL)  
             errorx(1, _("unable to cache gid %u, already exists"),  
                 (unsigned int) gid);  
     }      }
       if (rbinsert(grcache_bygid, item) != NULL)
           fatalx(_("unable to cache gid %u, already exists"),
               (unsigned int) gid);
 done:  done:
     item->refcnt++;      item->refcnt++;
     debug_return_ptr(item->d.gr);      debug_return_ptr(item->d.gr);
Line 700  sudo_getgrnam(const char *name) Line 409  sudo_getgrnam(const char *name)
     /*      /*
      * Cache group db entry if it exists or a negative response if not.       * Cache group db entry if it exists or a negative response if not.
      */       */
    if ((key.d.gr = getgrnam(name)) != NULL) {    item = sudo_make_gritem((gid_t)-1, name);
        item = make_gritem(key.d.gr, name);    if (item == NULL) {
        if (rbinsert(grcache_byname, item) != NULL) 
            errorx(1, _("unable to cache group %s, already exists"), name); 
    } else { 
         len = strlen(name) + 1;          len = strlen(name) + 1;
         item = ecalloc(1, sizeof(*item) + len);          item = ecalloc(1, sizeof(*item) + len);
         item->refcnt = 1;          item->refcnt = 1;
         item->k.name = (char *) item + sizeof(*item);          item->k.name = (char *) item + sizeof(*item);
         memcpy(item->k.name, name, len);          memcpy(item->k.name, name, len);
         /* item->d.gr = NULL; */          /* item->d.gr = NULL; */
         if (rbinsert(grcache_byname, item) != NULL)  
             errorx(1, _("unable to cache group %s, already exists"), name);  
     }      }
       if (rbinsert(grcache_byname, item) != NULL)
           fatalx(_("unable to cache group %s, already exists"), name);
 done:  done:
     item->refcnt++;      item->refcnt++;
     debug_return_ptr(item->d.gr);      debug_return_ptr(item->d.gr);
Line 728  sudo_fakegrnam(const char *group) Line 434  sudo_fakegrnam(const char *group)
     struct cache_item_gr *gritem;      struct cache_item_gr *gritem;
     struct group *gr;      struct group *gr;
     struct rbnode *node;      struct rbnode *node;
    size_t len, namelen;    size_t len, name_len;
     int i;      int i;
     debug_decl(sudo_fakegrnam, SUDO_DEBUG_NSS)      debug_decl(sudo_fakegrnam, SUDO_DEBUG_NSS)
   
    namelen = strlen(group);    name_len = strlen(group);
    len = sizeof(*gritem) + namelen + 1;    len = sizeof(*gritem) + name_len + 1;
   
     for (i = 0; i < 2; i++) {      for (i = 0; i < 2; i++) {
         gritem = ecalloc(1, len);          gritem = ecalloc(1, len);
         gr = &gritem->gr;          gr = &gritem->gr;
         gr->gr_gid = (gid_t) atoi(group + 1);          gr->gr_gid = (gid_t) atoi(group + 1);
         gr->gr_name = (char *)(gritem + 1);          gr->gr_name = (char *)(gritem + 1);
        memcpy(gr->gr_name, group, namelen + 1);        memcpy(gr->gr_name, group, name_len + 1);
   
         gritem->cache.refcnt = 1;          gritem->cache.refcnt = 1;
         gritem->cache.d.gr = gr;          gritem->cache.d.gr = gr;
         if (i == 0) {          if (i == 0) {
            /* Store by gid, overwriting cached version. */            /* Store by gid if it doesn't already exist. */
             gritem->cache.k.gid = gr->gr_gid;              gritem->cache.k.gid = gr->gr_gid;
             if ((node = rbinsert(grcache_bygid, &gritem->cache)) != NULL) {              if ((node = rbinsert(grcache_bygid, &gritem->cache)) != NULL) {
                sudo_gr_delref_item(node->data);                /* Already exists, free the item we created. */
                node->data = &gritem->cache;                efree(gritem);
                 gritem = (struct cache_item_gr *) node->data;
             }              }
         } else {          } else {
             /* Store by name, overwriting cached version. */              /* Store by name, overwriting cached version. */
             gritem->cache.k.name = gr->gr_name;              gritem->cache.k.name = gr->gr_name;
             if ((node = rbinsert(grcache_byname, &gritem->cache)) != NULL) {              if ((node = rbinsert(grcache_byname, &gritem->cache)) != NULL) {
                sudo_gr_delref_item(node->data);                /* Already exists, free the item we created. */
                node->data = &gritem->cache;                efree(gritem);
                 gritem = (struct cache_item_gr *) node->data;
             }              }
         }          }
     }      }
     gritem->cache.refcnt++;      gritem->cache.refcnt++;
    debug_return_ptr(gr);    debug_return_ptr(&gritem->gr);
 }  }
   
 void  void
Line 846  sudo_get_grlist(struct passwd *pw) Line 554  sudo_get_grlist(struct passwd *pw)
     struct cache_item key, *item;      struct cache_item key, *item;
     struct rbnode *node;      struct rbnode *node;
     size_t len;      size_t len;
     GETGROUPS_T *gids;  
     int ngids;  
     debug_decl(sudo_get_grlist, SUDO_DEBUG_NSS)      debug_decl(sudo_get_grlist, SUDO_DEBUG_NSS)
   
     key.k.name = pw->pw_name;      key.k.name = pw->pw_name;
Line 857  sudo_get_grlist(struct passwd *pw) Line 563  sudo_get_grlist(struct passwd *pw)
     }      }
     /*      /*
      * Cache group db entry if it exists or a negative response if not.       * Cache group db entry if it exists or a negative response if not.
      * Use gids list from front-end if possible, otherwise getgrouplist().  
      */       */
    if (pw == sudo_user.pw && sudo_user.gids != NULL) {    item = sudo_make_grlist_item(pw, NULL, NULL);
        gids = user_gids;    if (item == NULL) {
        ngids = user_ngids; 
        user_gids = NULL; 
        user_ngids = 0; 
    } else { 
#if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX) 
        ngids = (int)sysconf(_SC_NGROUPS_MAX) * 2; 
        if (ngids < 0) 
#endif 
            ngids = NGROUPS_MAX * 2; 
        gids = emalloc2(ngids, sizeof(GETGROUPS_T)); 
        if (getgrouplist(pw->pw_name, pw->pw_gid, gids, &ngids) == -1) { 
            efree(gids); 
            gids = emalloc2(ngids, sizeof(GETGROUPS_T)); 
            if (getgrouplist(pw->pw_name, pw->pw_gid, gids, &ngids) == -1) { 
                efree(gids); 
                debug_return_ptr(NULL); 
            } 
        } 
    } 
    if (ngids > 0) { 
        if ((item = make_grlist_item(pw->pw_name, gids, ngids)) == NULL) 
            errorx(1, "unable to parse group list for %s", pw->pw_name); 
        efree(gids); 
        if (rbinsert(grlist_cache, item) != NULL) 
            errorx(1, "unable to cache group list for %s, already exists", 
                pw->pw_name); 
    } else { 
         /* Should not happen. */          /* Should not happen. */
         len = strlen(pw->pw_name) + 1;          len = strlen(pw->pw_name) + 1;
         item = ecalloc(1, sizeof(*item) + len);          item = ecalloc(1, sizeof(*item) + len);
Line 895  sudo_get_grlist(struct passwd *pw) Line 573  sudo_get_grlist(struct passwd *pw)
         item->k.name = (char *) item + sizeof(*item);          item->k.name = (char *) item + sizeof(*item);
         memcpy(item->k.name, pw->pw_name, len);          memcpy(item->k.name, pw->pw_name, len);
         /* item->d.grlist = NULL; */          /* item->d.grlist = NULL; */
         if (rbinsert(grlist_cache, item) != NULL)  
             errorx(1, "unable to cache group list for %s, already exists",  
                 pw->pw_name);  
     }      }
       if (rbinsert(grlist_cache, item) != NULL)
           fatalx(_("unable to cache group list for %s, already exists"),
               pw->pw_name);
 done:  done:
     item->refcnt++;      item->refcnt++;
     debug_return_ptr(item->d.grlist);      debug_return_ptr(item->d.grlist);
   }
   
   void
   sudo_set_grlist(struct passwd *pw, char * const *groups, char * const *gids)
   {
       struct cache_item key, *item;
       struct rbnode *node;
       debug_decl(sudo_set_grlist, SUDO_DEBUG_NSS)
   
       /*
        * Cache group db entry if it doesn't already exist
        */
       key.k.name = pw->pw_name;
       if ((node = rbfind(grlist_cache, &key)) == NULL) {
           if ((item = sudo_make_grlist_item(pw, groups, gids)) == NULL)
               fatalx(_("unable to parse groups for %s"), pw->pw_name);
           if (rbinsert(grlist_cache, item) != NULL)
               fatalx(_("unable to cache group list for %s, already exists"),
                   pw->pw_name);
       }
       debug_return;
 }  }
   
 bool  bool

Removed from v.1.1.1.3  
changed lines
  Added in v.1.1.1.4


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>