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

version 1.1, 2012/02/21 16:23:02 version 1.1.1.3, 2012/10/09 09:29:52
Line 1 Line 1
 /*  /*
 * Copyright (c) 1996, 1998-2005, 2007-2011 * Copyright (c) 1996, 1998-2005, 2007-2012
  *      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 73  static int  cmp_grgid(const void *, const void *); Line 73  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) - sizeof(struct cache_item)))#define ptr_to_item(p) ((struct cache_item *)((char *)p - offsetof(struct cache_item_##p, p)))
   
   /*
    * Generic cache element.
    */
 struct cache_item {  struct cache_item {
     unsigned int refcnt;      unsigned int refcnt;
     /* key */      /* key */
Line 92  struct cache_item { Line 95  struct cache_item {
 };  };
   
 /*  /*
    * 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 134  do {       \ Line 157  do {       \
  * Dynamically allocate space for a struct item plus the key and data   * 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   * elements.  If name is non-NULL it is used as the key, else the
  * uid is the key.  Fills in datum from struct password.   * uid is the key.  Fills in datum from struct password.
  *  
  * We would like to fill in the encrypted password too but the  
  * call to the shadow function could overwrite the pw buffer (NIS).  
  */   */
 static struct cache_item *  static struct cache_item *
 make_pwitem(const struct passwd *pw, const char *name)  make_pwitem(const struct passwd *pw, const char *name)
Line 144  make_pwitem(const struct passwd *pw, const char *name) Line 164  make_pwitem(const struct passwd *pw, const char *name)
     char *cp;      char *cp;
     const char *pw_shell;      const char *pw_shell;
     size_t nsize, psize, csize, gsize, dsize, ssize, total;      size_t nsize, psize, csize, gsize, dsize, ssize, total;
    struct cache_item *item;    struct cache_item_pw *pwitem;
     struct passwd *newpw;      struct passwd *newpw;
       debug_decl(make_pwitem, SUDO_DEBUG_NSS)
   
     /* If shell field is empty, expand to _PATH_BSHELL. */      /* If shell field is empty, expand to _PATH_BSHELL. */
     pw_shell = (pw->pw_shell == NULL || pw->pw_shell[0] == '\0')      pw_shell = (pw->pw_shell == NULL || pw->pw_shell[0] == '\0')
Line 153  make_pwitem(const struct passwd *pw, const char *name) Line 174  make_pwitem(const struct passwd *pw, const char *name)
   
     /* Allocate in one big chunk for easy freeing. */      /* Allocate in one big chunk for easy freeing. */
     nsize = psize = csize = gsize = dsize = ssize = 0;      nsize = psize = csize = gsize = dsize = ssize = 0;
    total = sizeof(struct cache_item) + sizeof(struct passwd);    total = sizeof(*pwitem);
     FIELD_SIZE(pw, pw_name, nsize);      FIELD_SIZE(pw, pw_name, nsize);
     FIELD_SIZE(pw, pw_passwd, psize);      FIELD_SIZE(pw, pw_passwd, psize);
 #ifdef HAVE_LOGIN_CAP_H  #ifdef HAVE_LOGIN_CAP_H
Line 168  make_pwitem(const struct passwd *pw, const char *name) Line 189  make_pwitem(const struct passwd *pw, const char *name)
         total += strlen(name) + 1;          total += strlen(name) + 1;
   
     /* Allocate space for struct item, struct passwd and the strings. */      /* Allocate space for struct item, struct passwd and the strings. */
    item = emalloc(total);    pwitem = ecalloc(1, total);
    cp = (char *) item + sizeof(struct cache_item);    newpw = &pwitem->pw;
   
     /*      /*
      * Copy in passwd contents and make strings relative to space       * Copy in passwd contents and make strings relative to space
     * at the end of the buffer.     * at the end of the struct.
      */       */
    newpw = (struct passwd *) cp;    memcpy(newpw, pw, sizeof(*pw));
    memcpy(newpw, pw, sizeof(struct passwd));    cp = (char *)(pwitem + 1);
    cp += sizeof(struct passwd); 
     FIELD_COPY(pw, newpw, pw_name, nsize);      FIELD_COPY(pw, newpw, pw_name, nsize);
     FIELD_COPY(pw, newpw, pw_passwd, psize);      FIELD_COPY(pw, newpw, pw_passwd, psize);
 #ifdef HAVE_LOGIN_CAP_H  #ifdef HAVE_LOGIN_CAP_H
Line 193  make_pwitem(const struct passwd *pw, const char *name) Line 213  make_pwitem(const struct passwd *pw, const char *name)
     /* Set key and datum. */      /* Set key and datum. */
     if (name != NULL) {      if (name != NULL) {
         memcpy(cp, name, strlen(name) + 1);          memcpy(cp, name, strlen(name) + 1);
        item->k.name = cp;        pwitem->cache.k.name = cp;
     } else {      } else {
        item->k.uid = pw->pw_uid;        pwitem->cache.k.uid = pw->pw_uid;
     }      }
    item->d.pw = newpw;    pwitem->cache.d.pw = newpw;
    item->refcnt = 1;    pwitem->cache.refcnt = 1;
   
    return item;    debug_return_ptr(&pwitem->cache);
 }  }
   
 void  void
pw_addref(struct passwd *pw)sudo_pw_addref(struct passwd *pw)
 {  {
       debug_decl(sudo_pw_addref, SUDO_DEBUG_NSS)
     ptr_to_item(pw)->refcnt++;      ptr_to_item(pw)->refcnt++;
       debug_return;
 }  }
   
 static void  static void
pw_delref_item(void *v)sudo_pw_delref_item(void *v)
 {  {
     struct cache_item *item = v;      struct cache_item *item = v;
       debug_decl(sudo_pw_delref_item, SUDO_DEBUG_NSS)
   
     if (--item->refcnt == 0)      if (--item->refcnt == 0)
         efree(item);          efree(item);
   
       debug_return;
 }  }
   
 void  void
pw_delref(struct passwd *pw)sudo_pw_delref(struct passwd *pw)
 {  {
    pw_delref_item(ptr_to_item(pw));    debug_decl(sudo_pw_delref, SUDO_DEBUG_NSS)
     sudo_pw_delref_item(ptr_to_item(pw));
     debug_return;
 }  }
   
 /*  /*
  * Get a password entry by uid and allocate space for it.   * Get a password entry by uid and allocate space for it.
  * Fills in pw_passwd from shadow file if necessary.  
  */   */
 struct passwd *  struct passwd *
 sudo_getpwuid(uid_t uid)  sudo_getpwuid(uid_t uid)
 {  {
     struct cache_item key, *item;      struct cache_item key, *item;
     struct rbnode *node;      struct rbnode *node;
       debug_decl(sudo_getpwuid, SUDO_DEBUG_NSS)
   
     key.k.uid = uid;      key.k.uid = uid;
     if ((node = rbfind(pwcache_byuid, &key)) != NULL) {      if ((node = rbfind(pwcache_byuid, &key)) != NULL) {
Line 251  sudo_getpwuid(uid_t uid) Line 278  sudo_getpwuid(uid_t uid)
             errorx(1, _("unable to cache uid %u (%s), already exists"),              errorx(1, _("unable to cache uid %u (%s), already exists"),
                 (unsigned int) uid, item->d.pw->pw_name);                  (unsigned int) uid, item->d.pw->pw_name);
     } else {      } else {
        item = emalloc(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)          if (rbinsert(pwcache_byuid, item) != NULL)
             errorx(1, _("unable to cache uid %u, already exists"),              errorx(1, _("unable to cache uid %u, already exists"),
                 (unsigned int) uid);                  (unsigned int) uid);
Line 264  sudo_getpwuid(uid_t uid) Line 291  sudo_getpwuid(uid_t uid)
 #endif  #endif
 done:  done:
     item->refcnt++;      item->refcnt++;
    return item->d.pw;    debug_return_ptr(item->d.pw);
 }  }
   
 /*  /*
  * Get a password entry by name and allocate space for it.   * Get a password entry by name and allocate space for it.
  * Fills in pw_passwd from shadow file if necessary.  
  */   */
 struct passwd *  struct passwd *
 sudo_getpwnam(const char *name)  sudo_getpwnam(const char *name)
Line 277  sudo_getpwnam(const char *name) Line 303  sudo_getpwnam(const char *name)
     struct cache_item key, *item;      struct cache_item key, *item;
     struct rbnode *node;      struct rbnode *node;
     size_t len;      size_t len;
       debug_decl(sudo_getpwnam, SUDO_DEBUG_NSS)
   
     key.k.name = (char *) name;      key.k.name = (char *) name;
     if ((node = rbfind(pwcache_byname, &key)) != NULL) {      if ((node = rbfind(pwcache_byname, &key)) != NULL) {
Line 295  sudo_getpwnam(const char *name) Line 322  sudo_getpwnam(const char *name)
             errorx(1, _("unable to cache user %s, already exists"), name);              errorx(1, _("unable to cache user %s, already exists"), name);
     } else {      } else {
         len = strlen(name) + 1;          len = strlen(name) + 1;
        item = emalloc(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)          if (rbinsert(pwcache_byname, item) != NULL)
             errorx(1, _("unable to cache user %s, already exists"), name);              errorx(1, _("unable to cache user %s, already exists"), name);
     }      }
Line 308  sudo_getpwnam(const char *name) Line 335  sudo_getpwnam(const char *name)
 #endif  #endif
 done:  done:
     item->refcnt++;      item->refcnt++;
    return item->d.pw;    debug_return_ptr(item->d.pw);
 }  }
   
 /*  /*
Line 317  done: Line 344  done:
 struct passwd *  struct passwd *
 sudo_fakepwnamid(const char *user, uid_t uid, gid_t gid)  sudo_fakepwnamid(const char *user, uid_t uid, gid_t gid)
 {  {
    struct cache_item *item;    struct cache_item_pw *pwitem;
     struct passwd *pw;      struct passwd *pw;
     struct rbnode *node;      struct rbnode *node;
     size_t len, namelen;      size_t len, namelen;
     int i;      int i;
       debug_decl(sudo_fakepwnam, SUDO_DEBUG_NSS)
   
     namelen = strlen(user);      namelen = strlen(user);
    len = sizeof(*item) + sizeof(*pw) + namelen + 1 /* pw_name */ +    len = sizeof(*pwitem) + namelen + 1 /* pw_name */ +
         sizeof("*") /* pw_passwd */ + sizeof("") /* pw_gecos */ +          sizeof("*") /* pw_passwd */ + sizeof("") /* pw_gecos */ +
         sizeof("/") /* pw_dir */ + sizeof(_PATH_BSHELL);          sizeof("/") /* pw_dir */ + sizeof(_PATH_BSHELL);
   
     for (i = 0; i < 2; i++) {      for (i = 0; i < 2; i++) {
        item = emalloc(len);        pwitem = ecalloc(1, len);
        zero_bytes(item, sizeof(*item) + sizeof(*pw));        pw = &pwitem->pw;
        pw = (struct passwd *) ((char *)item + sizeof(*item)); 
         pw->pw_uid = uid;          pw->pw_uid = uid;
         pw->pw_gid = gid;          pw->pw_gid = gid;
        pw->pw_name = (char *)pw + sizeof(struct passwd);        pw->pw_name = (char *)(pwitem + 1);
         memcpy(pw->pw_name, user, namelen + 1);          memcpy(pw->pw_name, user, namelen + 1);
         pw->pw_passwd = pw->pw_name + namelen + 1;          pw->pw_passwd = pw->pw_name + namelen + 1;
         memcpy(pw->pw_passwd, "*", 2);          memcpy(pw->pw_passwd, "*", 2);
Line 345  sudo_fakepwnamid(const char *user, uid_t uid, gid_t gi Line 372  sudo_fakepwnamid(const char *user, uid_t uid, gid_t gi
         pw->pw_shell = pw->pw_dir + 2;          pw->pw_shell = pw->pw_dir + 2;
         memcpy(pw->pw_shell, _PATH_BSHELL, sizeof(_PATH_BSHELL));          memcpy(pw->pw_shell, _PATH_BSHELL, sizeof(_PATH_BSHELL));
   
        item->refcnt = 1;        pwitem->cache.refcnt = 1;
        item->d.pw = pw;        pwitem->cache.d.pw = pw;
         if (i == 0) {          if (i == 0) {
             /* Store by uid, overwriting cached version. */              /* Store by uid, overwriting cached version. */
            item->k.uid = pw->pw_uid;            pwitem->cache.k.uid = pw->pw_uid;
            if ((node = rbinsert(pwcache_byuid, item)) != NULL) {            if ((node = rbinsert(pwcache_byuid, &pwitem->cache)) != NULL) {
                pw_delref_item(node->data);                sudo_pw_delref_item(node->data);
                node->data = item;                node->data = &pwitem->cache;
             }              }
         } else {          } else {
             /* Store by name, overwriting cached version. */              /* Store by name, overwriting cached version. */
            item->k.name = pw->pw_name;            pwitem->cache.k.name = pw->pw_name;
            if ((node = rbinsert(pwcache_byname, item)) != NULL) {            if ((node = rbinsert(pwcache_byname, &pwitem->cache)) != NULL) {
                pw_delref_item(node->data);                sudo_pw_delref_item(node->data);
                node->data = item;                node->data = &pwitem->cache;
             }              }
         }          }
     }      }
    item->refcnt++;    pwitem->cache.refcnt++;
    return pw;    debug_return_ptr(pw);
 }  }
   
 /*  /*
Line 382  sudo_fakepwnam(const char *user, gid_t gid) Line 409  sudo_fakepwnam(const char *user, gid_t gid)
 void  void
 sudo_setpwent(void)  sudo_setpwent(void)
 {  {
       debug_decl(sudo_setpwent, SUDO_DEBUG_NSS)
   
     setpwent();      setpwent();
     if (pwcache_byuid == NULL)      if (pwcache_byuid == NULL)
         pwcache_byuid = rbcreate(cmp_pwuid);          pwcache_byuid = rbcreate(cmp_pwuid);
     if (pwcache_byname == NULL)      if (pwcache_byname == NULL)
         pwcache_byname = rbcreate(cmp_pwnam);          pwcache_byname = rbcreate(cmp_pwnam);
   
       debug_return;
 }  }
   
 void  void
 sudo_freepwcache(void)  sudo_freepwcache(void)
 {  {
       debug_decl(sudo_freepwcache, SUDO_DEBUG_NSS)
   
     if (pwcache_byuid != NULL) {      if (pwcache_byuid != NULL) {
        rbdestroy(pwcache_byuid, pw_delref_item);        rbdestroy(pwcache_byuid, sudo_pw_delref_item);
         pwcache_byuid = NULL;          pwcache_byuid = NULL;
     }      }
     if (pwcache_byname != NULL) {      if (pwcache_byname != NULL) {
        rbdestroy(pwcache_byname, pw_delref_item);        rbdestroy(pwcache_byname, sudo_pw_delref_item);
         pwcache_byname = NULL;          pwcache_byname = NULL;
     }      }
   
       debug_return;
 }  }
   
 void  void
 sudo_endpwent(void)  sudo_endpwent(void)
 {  {
       debug_decl(sudo_endpwent, SUDO_DEBUG_NSS)
   
     endpwent();      endpwent();
     sudo_freepwcache();      sudo_freepwcache();
   
       debug_return;
 }  }
   
 /*  /*
Line 430  make_gritem(const struct group *gr, const char *name) Line 469  make_gritem(const struct group *gr, const char *name)
 {  {
     char *cp;      char *cp;
     size_t nsize, psize, nmem, total, len;      size_t nsize, psize, nmem, total, len;
    struct cache_item *item;    struct cache_item_gr *gritem;
     struct group *newgr;      struct group *newgr;
       debug_decl(make_gritem, SUDO_DEBUG_NSS)
   
     /* Allocate in one big chunk for easy freeing. */      /* Allocate in one big chunk for easy freeing. */
     nsize = psize = nmem = 0;      nsize = psize = nmem = 0;
    total = sizeof(struct cache_item) + sizeof(struct group);    total = sizeof(*gritem);
     FIELD_SIZE(gr, gr_name, nsize);      FIELD_SIZE(gr, gr_name, nsize);
     FIELD_SIZE(gr, gr_passwd, psize);      FIELD_SIZE(gr, gr_passwd, psize);
     if (gr->gr_mem) {      if (gr->gr_mem) {
Line 447  make_gritem(const struct group *gr, const char *name) Line 487  make_gritem(const struct group *gr, const char *name)
     if (name != NULL)      if (name != NULL)
         total += strlen(name) + 1;          total += strlen(name) + 1;
   
    item = emalloc(total);    gritem = ecalloc(1, total);
    cp = (char *) item + sizeof(struct cache_item); 
   
     /*      /*
      * Copy in group contents and make strings relative to space       * Copy in group contents and make strings relative to space
      * at the end of the buffer.  Note that gr_mem must come       * at the end of the buffer.  Note that gr_mem must come
      * immediately after struct group to guarantee proper alignment.       * immediately after struct group to guarantee proper alignment.
      */       */
    newgr = (struct group *)cp;    newgr = &gritem->gr;
    memcpy(newgr, gr, sizeof(struct group));    memcpy(newgr, gr, sizeof(*gr));
    cp += sizeof(struct group);    cp = (char *)(gritem + 1);
     if (gr->gr_mem) {      if (gr->gr_mem) {
         newgr->gr_mem = (char **)cp;          newgr->gr_mem = (char **)cp;
         cp += sizeof(char *) * nmem;          cp += sizeof(char *) * nmem;
Line 475  make_gritem(const struct group *gr, const char *name) Line 514  make_gritem(const struct group *gr, const char *name)
     /* Set key and datum. */      /* Set key and datum. */
     if (name != NULL) {      if (name != NULL) {
         memcpy(cp, name, strlen(name) + 1);          memcpy(cp, name, strlen(name) + 1);
        item->k.name = cp;        gritem->cache.k.name = cp;
     } else {      } else {
        item->k.gid = gr->gr_gid;        gritem->cache.k.gid = gr->gr_gid;
     }      }
    item->d.gr = newgr;    gritem->cache.d.gr = newgr;
    item->refcnt = 1;    gritem->cache.refcnt = 1;
   
    return item;    debug_return_ptr(&gritem->cache);
 }  }
   
 #ifdef HAVE_UTMPX_H  #ifdef HAVE_UTMPX_H
Line 504  make_grlist_item(const char *user, GETGROUPS_T *gids,  Line 543  make_grlist_item(const char *user, GETGROUPS_T *gids, 
 {  {
     char *cp;      char *cp;
     size_t i, nsize, ngroups, total, len;      size_t i, nsize, ngroups, total, len;
    struct cache_item *item;    struct cache_item_grlist *grlitem;
     struct group_list *grlist;      struct group_list *grlist;
     struct group *grp;      struct group *grp;
       debug_decl(make_grlist_item, SUDO_DEBUG_NSS)
   
 #ifdef HAVE_SETAUTHDB  #ifdef HAVE_SETAUTHDB
     aix_setauthdb((char *) user);      aix_setauthdb((char *) user);
Line 514  make_grlist_item(const char *user, GETGROUPS_T *gids,  Line 554  make_grlist_item(const char *user, GETGROUPS_T *gids, 
   
     /* Allocate in one big chunk for easy freeing. */      /* Allocate in one big chunk for easy freeing. */
     nsize = strlen(user) + 1;      nsize = strlen(user) + 1;
    total = sizeof(struct cache_item) + sizeof(struct group_list) + nsize;    total = sizeof(*grlitem) + nsize;
     total += sizeof(char *) * ngids;      total += sizeof(char *) * ngids;
     total += sizeof(gid_t *) * ngids;      total += sizeof(gid_t *) * ngids;
     total += GROUPNAME_LEN * ngids;      total += GROUPNAME_LEN * ngids;
   
 again:  again:
    item = emalloc(total);    grlitem = ecalloc(1, total);
    cp = (char *) item + sizeof(struct cache_item); 
   
     /*      /*
      * Copy in group list and make pointers relative to space       * Copy in group list and make pointers relative to space
      * at the end of the buffer.  Note that the groups array must come       * at the end of the buffer.  Note that the groups array must come
      * immediately after struct group to guarantee proper alignment.       * immediately after struct group to guarantee proper alignment.
      */       */
    grlist = (struct group_list *)cp;    grlist = &grlitem->grlist;
    zero_bytes(grlist, sizeof(struct group_list));    cp = (char *)(grlitem + 1);
    cp += sizeof(struct group_list); 
     grlist->groups = (char **)cp;      grlist->groups = (char **)cp;
     cp += sizeof(char *) * ngids;      cp += sizeof(char *) * ngids;
     grlist->gids = (gid_t *)cp;      grlist->gids = (gid_t *)cp;
Line 538  again: Line 576  again:
   
     /* Set key and datum. */      /* Set key and datum. */
     memcpy(cp, user, nsize);      memcpy(cp, user, nsize);
    item->k.name = cp;    grlitem->cache.k.name = cp;
    item->d.grlist = grlist;    grlitem->cache.d.grlist = grlist;
    item->refcnt = 1;    grlitem->cache.refcnt = 1;
     cp += nsize;      cp += nsize;
   
     /*      /*
Line 557  again: Line 595  again:
     for (i = 0; i < ngids; i++) {      for (i = 0; i < ngids; i++) {
         if ((grp = sudo_getgrgid(gids[i])) != NULL) {          if ((grp = sudo_getgrgid(gids[i])) != NULL) {
             len = strlen(grp->gr_name) + 1;              len = strlen(grp->gr_name) + 1;
            if (cp - (char *)item + len > total) {            if (cp - (char *)grlitem + len > total) {
                 total += len + GROUPNAME_LEN;                  total += len + GROUPNAME_LEN;
                efree(item);                efree(grlitem);
                gr_delref(grp);                sudo_gr_delref(grp);
                 goto again;                  goto again;
             }              }
             memcpy(cp, grp->gr_name, len);              memcpy(cp, grp->gr_name, len);
             grlist->groups[ngroups++] = cp;              grlist->groups[ngroups++] = cp;
             cp += len;              cp += len;
            gr_delref(grp);            sudo_gr_delref(grp);
         }          }
     }      }
     grlist->ngroups = ngroups;      grlist->ngroups = ngroups;
Line 575  again: Line 613  again:
     aix_restoreauthdb();      aix_restoreauthdb();
 #endif  #endif
   
    return item;    debug_return_ptr(&grlitem->cache);
 }  }
   
 void  void
gr_addref(struct group *gr)sudo_gr_addref(struct group *gr)
 {  {
       debug_decl(sudo_gr_addref, SUDO_DEBUG_NSS)
     ptr_to_item(gr)->refcnt++;      ptr_to_item(gr)->refcnt++;
       debug_return;
 }  }
   
 static void  static void
gr_delref_item(void *v)sudo_gr_delref_item(void *v)
 {  {
     struct cache_item *item = v;      struct cache_item *item = v;
       debug_decl(sudo_gr_delref_item, SUDO_DEBUG_NSS)
   
     if (--item->refcnt == 0)      if (--item->refcnt == 0)
         efree(item);          efree(item);
   
       debug_return;
 }  }
   
 void  void
gr_delref(struct group *gr)sudo_gr_delref(struct group *gr)
 {  {
    gr_delref_item(ptr_to_item(gr));    debug_decl(sudo_gr_delref, SUDO_DEBUG_NSS)
     sudo_gr_delref_item(ptr_to_item(gr));
     debug_return;
 }  }
   
 /*  /*
Line 607  sudo_getgrgid(gid_t gid) Line 652  sudo_getgrgid(gid_t gid)
 {  {
     struct cache_item key, *item;      struct cache_item key, *item;
     struct rbnode *node;      struct rbnode *node;
       debug_decl(sudo_getgrgid, SUDO_DEBUG_NSS)
   
     key.k.gid = gid;      key.k.gid = gid;
     if ((node = rbfind(grcache_bygid, &key)) != NULL) {      if ((node = rbfind(grcache_bygid, &key)) != NULL) {
Line 622  sudo_getgrgid(gid_t gid) Line 668  sudo_getgrgid(gid_t gid)
             errorx(1, _("unable to cache gid %u (%s), already exists"),              errorx(1, _("unable to cache gid %u (%s), already exists"),
                 (unsigned int) gid, key.d.gr->gr_name);                  (unsigned int) gid, key.d.gr->gr_name);
     } else {      } else {
        item = emalloc(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)          if (rbinsert(grcache_bygid, item) != NULL)
             errorx(1, _("unable to cache gid %u, already exists"),              errorx(1, _("unable to cache gid %u, already exists"),
                 (unsigned int) gid);                  (unsigned int) gid);
     }      }
 done:  done:
     item->refcnt++;      item->refcnt++;
    return item->d.gr;    debug_return_ptr(item->d.gr);
 }  }
   
 /*  /*
Line 644  sudo_getgrnam(const char *name) Line 690  sudo_getgrnam(const char *name)
     struct cache_item key, *item;      struct cache_item key, *item;
     struct rbnode *node;      struct rbnode *node;
     size_t len;      size_t len;
       debug_decl(sudo_getgrnam, SUDO_DEBUG_NSS)
   
     key.k.name = (char *) name;      key.k.name = (char *) name;
     if ((node = rbfind(grcache_byname, &key)) != NULL) {      if ((node = rbfind(grcache_byname, &key)) != NULL) {
Line 659  sudo_getgrnam(const char *name) Line 706  sudo_getgrnam(const char *name)
             errorx(1, _("unable to cache group %s, already exists"), name);              errorx(1, _("unable to cache group %s, already exists"), name);
     } else {      } else {
         len = strlen(name) + 1;          len = strlen(name) + 1;
        item = emalloc(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)          if (rbinsert(grcache_byname, item) != NULL)
             errorx(1, _("unable to cache group %s, already exists"), name);              errorx(1, _("unable to cache group %s, already exists"), name);
     }      }
 done:  done:
     item->refcnt++;      item->refcnt++;
    return item->d.gr;    debug_return_ptr(item->d.gr);
 }  }
   
 /*  /*
Line 678  done: Line 725  done:
 struct group *  struct group *
 sudo_fakegrnam(const char *group)  sudo_fakegrnam(const char *group)
 {  {
    struct cache_item *item;    struct cache_item_gr *gritem;
     struct group *gr;      struct group *gr;
     struct rbnode *node;      struct rbnode *node;
     size_t len, namelen;      size_t len, namelen;
     int i;      int i;
       debug_decl(sudo_fakegrnam, SUDO_DEBUG_NSS)
   
     namelen = strlen(group);      namelen = strlen(group);
    len = sizeof(*item) + sizeof(*gr) + namelen + 1;    len = sizeof(*gritem) + namelen + 1;
   
     for (i = 0; i < 2; i++) {      for (i = 0; i < 2; i++) {
        item = emalloc(len);        gritem = ecalloc(1, len);
        zero_bytes(item, sizeof(*item) + sizeof(*gr));        gr = &gritem->gr;
        gr = (struct group *) ((char *)item + sizeof(*item)); 
         gr->gr_gid = (gid_t) atoi(group + 1);          gr->gr_gid = (gid_t) atoi(group + 1);
        gr->gr_name = (char *)gr + sizeof(struct group);        gr->gr_name = (char *)(gritem + 1);
         memcpy(gr->gr_name, group, namelen + 1);          memcpy(gr->gr_name, group, namelen + 1);
   
        item->refcnt = 1;        gritem->cache.refcnt = 1;
        item->d.gr = gr;        gritem->cache.d.gr = gr;
         if (i == 0) {          if (i == 0) {
             /* Store by gid, overwriting cached version. */              /* Store by gid, overwriting cached version. */
            item->k.gid = gr->gr_gid;            gritem->cache.k.gid = gr->gr_gid;
            if ((node = rbinsert(grcache_bygid, item)) != NULL) {            if ((node = rbinsert(grcache_bygid, &gritem->cache)) != NULL) {
                gr_delref_item(node->data);                sudo_gr_delref_item(node->data);
                node->data = item;                node->data = &gritem->cache;
             }              }
         } else {          } else {
             /* Store by name, overwriting cached version. */              /* Store by name, overwriting cached version. */
            item->k.name = gr->gr_name;            gritem->cache.k.name = gr->gr_name;
            if ((node = rbinsert(grcache_byname, item)) != NULL) {            if ((node = rbinsert(grcache_byname, &gritem->cache)) != NULL) {
                gr_delref_item(node->data);                sudo_gr_delref_item(node->data);
                node->data = item;                node->data = &gritem->cache;
             }              }
         }          }
     }      }
    item->refcnt++;    gritem->cache.refcnt++;
    return gr;    debug_return_ptr(gr);
 }  }
   
 void  void
grlist_addref(struct group_list *grlist)sudo_grlist_addref(struct group_list *grlist)
 {  {
       debug_decl(sudo_gr_addref, SUDO_DEBUG_NSS)
     ptr_to_item(grlist)->refcnt++;      ptr_to_item(grlist)->refcnt++;
       debug_return;
 }  }
   
 static void  static void
grlist_delref_item(void *v)sudo_grlist_delref_item(void *v)
 {  {
     struct cache_item *item = v;      struct cache_item *item = v;
       debug_decl(sudo_gr_delref_item, SUDO_DEBUG_NSS)
   
     if (--item->refcnt == 0)      if (--item->refcnt == 0)
         efree(item);          efree(item);
   
       debug_return;
 }  }
   
 void  void
grlist_delref(struct group_list *grlist)sudo_grlist_delref(struct group_list *grlist)
 {  {
    grlist_delref_item(ptr_to_item(grlist));    debug_decl(sudo_gr_delref, SUDO_DEBUG_NSS)
     sudo_grlist_delref_item(ptr_to_item(grlist));
     debug_return;
 }  }
   
 void  void
 sudo_setgrent(void)  sudo_setgrent(void)
 {  {
       debug_decl(sudo_setgrent, SUDO_DEBUG_NSS)
   
     setgrent();      setgrent();
     if (grcache_bygid == NULL)      if (grcache_bygid == NULL)
         grcache_bygid = rbcreate(cmp_grgid);          grcache_bygid = rbcreate(cmp_grgid);
Line 748  sudo_setgrent(void) Line 804  sudo_setgrent(void)
         grcache_byname = rbcreate(cmp_grnam);          grcache_byname = rbcreate(cmp_grnam);
     if (grlist_cache == NULL)      if (grlist_cache == NULL)
         grlist_cache = rbcreate(cmp_grnam);          grlist_cache = rbcreate(cmp_grnam);
   
       debug_return;
 }  }
   
 void  void
 sudo_freegrcache(void)  sudo_freegrcache(void)
 {  {
       debug_decl(sudo_freegrcache, SUDO_DEBUG_NSS)
   
     if (grcache_bygid != NULL) {      if (grcache_bygid != NULL) {
        rbdestroy(grcache_bygid, gr_delref_item);        rbdestroy(grcache_bygid, sudo_gr_delref_item);
         grcache_bygid = NULL;          grcache_bygid = NULL;
     }      }
     if (grcache_byname != NULL) {      if (grcache_byname != NULL) {
        rbdestroy(grcache_byname, gr_delref_item);        rbdestroy(grcache_byname, sudo_gr_delref_item);
         grcache_byname = NULL;          grcache_byname = NULL;
     }      }
     if (grlist_cache != NULL) {      if (grlist_cache != NULL) {
        rbdestroy(grlist_cache, grlist_delref_item);        rbdestroy(grlist_cache, sudo_grlist_delref_item);
         grlist_cache = NULL;          grlist_cache = NULL;
     }      }
   
       debug_return;
 }  }
   
 void  void
 sudo_endgrent(void)  sudo_endgrent(void)
 {  {
       debug_decl(sudo_endgrent, SUDO_DEBUG_NSS)
   
     endgrent();      endgrent();
     sudo_freegrcache();      sudo_freegrcache();
   
       debug_return;
 }  }
   
 struct group_list *  struct group_list *
get_group_list(struct passwd *pw)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;      GETGROUPS_T *gids;
     int ngids;      int ngids;
       debug_decl(sudo_get_grlist, SUDO_DEBUG_NSS)
   
     key.k.name = pw->pw_name;      key.k.name = pw->pw_name;
     if ((node = rbfind(grlist_cache, &key)) != NULL) {      if ((node = rbfind(grlist_cache, &key)) != NULL) {
Line 790  get_group_list(struct passwd *pw) Line 857  get_group_list(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) {
           gids = user_gids;
           ngids = user_ngids;
           user_gids = NULL;
           user_ngids = 0;
       } else {
 #if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX)  #if defined(HAVE_SYSCONF) && defined(_SC_NGROUPS_MAX)
    ngids = (int)sysconf(_SC_NGROUPS_MAX) * 2;        ngids = (int)sysconf(_SC_NGROUPS_MAX) * 2;
    if (ngids < 0)        if (ngids < 0)
 #endif  #endif
        ngids = NGROUPS_MAX * 2;            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));          gids = emalloc2(ngids, sizeof(GETGROUPS_T));
         if (getgrouplist(pw->pw_name, pw->pw_gid, gids, &ngids) == -1) {          if (getgrouplist(pw->pw_name, pw->pw_gid, gids, &ngids) == -1) {
             efree(gids);              efree(gids);
            return NULL;            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 (ngids > 0) {
Line 815  get_group_list(struct passwd *pw) Line 890  get_group_list(struct passwd *pw)
     } else {      } else {
         /* Should not happen. */          /* Should not happen. */
         len = strlen(pw->pw_name) + 1;          len = strlen(pw->pw_name) + 1;
        item = emalloc(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, 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)          if (rbinsert(grlist_cache, item) != NULL)
             errorx(1, "unable to cache group list for %s, already exists",              errorx(1, "unable to cache group list for %s, already exists",
                 pw->pw_name);                  pw->pw_name);
     }      }
 done:  done:
     item->refcnt++;      item->refcnt++;
    return item->d.grlist;    debug_return_ptr(item->d.grlist);
 }  }
   
voidbool
set_group_list(const char *user, GETGROUPS_T *gids, int ngids) 
{ 
    struct cache_item key, *item; 
    struct rbnode *node; 
 
    /* 
     * Cache group db entry if it doesn't already exist 
     */ 
    key.k.name = (char *) user; 
    if ((node = rbfind(grlist_cache, &key)) == NULL) { 
        if ((item = make_grlist_item(user, gids, ngids)) == NULL) 
            errorx(1, "unable to parse group list for %s", user); 
        if (rbinsert(grlist_cache, item) != NULL) 
            errorx(1, "unable to cache group list for %s, already exists", 
                user); 
    } 
} 
 
int 
 user_in_group(struct passwd *pw, const char *group)  user_in_group(struct passwd *pw, const char *group)
 {  {
     struct group_list *grlist;      struct group_list *grlist;
     struct group *grp = NULL;      struct group *grp = NULL;
    int i, matched = FALSE;    int i;
     bool matched = false;
     debug_decl(user_in_group, SUDO_DEBUG_NSS)
   
    if ((grlist = get_group_list(pw)) != NULL) {    if ((grlist = sudo_get_grlist(pw)) != NULL) {
         /*          /*
          * If it could be a sudo-style group ID check gids first.           * If it could be a sudo-style group ID check gids first.
          */           */
         if (group[0] == '#') {          if (group[0] == '#') {
             gid_t gid = atoi(group + 1);              gid_t gid = atoi(group + 1);
             if (gid == pw->pw_gid) {              if (gid == pw->pw_gid) {
                matched = TRUE;                matched = true;
                 goto done;                  goto done;
             }              }
             for (i = 0; i < grlist->ngids; i++) {              for (i = 0; i < grlist->ngids; i++) {
                 if (gid == grlist->gids[i]) {                  if (gid == grlist->gids[i]) {
                    matched = TRUE;                    matched = true;
                     goto done;                      goto done;
                 }                  }
             }              }
Line 879  user_in_group(struct passwd *pw, const char *group) Line 937  user_in_group(struct passwd *pw, const char *group)
          */           */
         for (i = 0; i < grlist->ngroups; i++) {          for (i = 0; i < grlist->ngroups; i++) {
             if (strcasecmp(group, grlist->groups[i]) == 0) {              if (strcasecmp(group, grlist->groups[i]) == 0) {
                matched = TRUE;                matched = true;
                 goto done;                  goto done;
             }              }
         }          }
Line 887  user_in_group(struct passwd *pw, const char *group) Line 945  user_in_group(struct passwd *pw, const char *group)
         /* Finally check against user's primary (passwd file) group. */          /* Finally check against user's primary (passwd file) group. */
         if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) {          if ((grp = sudo_getgrgid(pw->pw_gid)) != NULL) {
             if (strcasecmp(group, grp->gr_name) == 0) {              if (strcasecmp(group, grp->gr_name) == 0) {
                matched = TRUE;                matched = true;
                 goto done;                  goto done;
             }              }
         }          }
 done:  done:
         if (grp != NULL)          if (grp != NULL)
            gr_delref(grp);            sudo_gr_delref(grp);
        grlist_delref(grlist);        sudo_grlist_delref(grlist);
     }      }
    return matched;    debug_return_bool(matched);
 }  }

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


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