Diff for /embedaddon/rsync/uidlist.c between versions 1.1.1.1 and 1.1.1.4

version 1.1.1.1, 2012/02/17 15:09:30 version 1.1.1.4, 2021/03/17 00:32:36
Line 3 Line 3
  *   *
  * Copyright (C) 1996 Andrew Tridgell   * Copyright (C) 1996 Andrew Tridgell
  * Copyright (C) 1996 Paul Mackerras   * Copyright (C) 1996 Paul Mackerras
 * Copyright (C) 2004-2009 Wayne Davison * Copyright (C) 2004-2020 Wayne Davison
  *   *
  * This program is free software; you can redistribute it and/or modify   * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License as published by   * it under the terms of the GNU General Public License as published by
Line 24 Line 24
  * are special. */   * are special. */
   
 #include "rsync.h"  #include "rsync.h"
   #include "ifuncs.h"
   #include "itypes.h"
 #include "io.h"  #include "io.h"
   
 extern int verbose;  
 extern int am_root;  extern int am_root;
 extern int preserve_uid;  extern int preserve_uid;
 extern int preserve_gid;  extern int preserve_gid;
 extern int preserve_acls;  extern int preserve_acls;
 extern int numeric_ids;  extern int numeric_ids;
   extern int xmit_id0_names;
   extern pid_t namecvt_pid;
   extern gid_t our_gid;
   extern char *usermap;
   extern char *groupmap;
   
 #ifdef HAVE_GETGROUPS  #ifdef HAVE_GETGROUPS
 # ifndef GETGROUPS_T  # ifndef GETGROUPS_T
Line 39  extern int numeric_ids; Line 45  extern int numeric_ids;
 # endif  # endif
 #endif  #endif
   
   #define NFLAGS_WILD_NAME_MATCH (1<<0)
   #define NFLAGS_NAME_MATCH (1<<1)
   
   union name_or_id {
           const char *name;
           id_t max_id;
   };
   
 struct idlist {  struct idlist {
         struct idlist *next;          struct idlist *next;
        const char *name;        union name_or_id u;
         id_t id, id2;          id_t id, id2;
         uint16 flags;          uint16 flags;
 };  };
   
static struct idlist *uidlist;static struct idlist *uidlist, *uidmap;
static struct idlist *gidlist;static struct idlist *gidlist, *gidmap;
   
static struct idlist *add_to_list(struct idlist **root, id_t id, const char *name,static id_t id_parse(const char *num_str)
 {
         id_t tmp, num = 0;
         const char *cp = num_str;
 
         while (*cp) {
                 if (!isDigit(cp)) {
                   invalid_num:
                         rprintf(FERROR, "Invalid ID number: %s\n", num_str);
                         exit_cleanup(RERR_SYNTAX);
                 }
                 tmp = num * 10 + *cp++ - '0';
                 if (tmp < num)
                         goto invalid_num;
                 num = tmp;
         }
 
         return num;
 }
 
 static struct idlist *add_to_list(struct idlist **root, id_t id, union name_or_id noiu,
                                   id_t id2, uint16 flags)                                    id_t id2, uint16 flags)
 {  {
         struct idlist *node = new(struct idlist);          struct idlist *node = new(struct idlist);
         if (!node)  
                 out_of_memory("add_to_list");  
         node->next = *root;          node->next = *root;
        node->name = name;        node->u = noiu;
         node->id = id;          node->id = id;
         node->id2 = id2;          node->id2 = id2;
         node->flags = flags;          node->flags = flags;
Line 65  static struct idlist *add_to_list(struct idlist **root Line 97  static struct idlist *add_to_list(struct idlist **root
 }  }
   
 /* turn a uid into a user name */  /* turn a uid into a user name */
static const char *uid_to_name(uid_t uid)const char *uid_to_user(uid_t uid)
 {  {
        struct passwd *pass = getpwuid(uid);        const char *name = NULL;
        if (pass)
                return strdup(pass->pw_name);        if (namecvt_pid) {
        return NULL;                id_t id = uid;
                 namecvt_call("uid", &name, &id);
         } else {
                 struct passwd *pass = getpwuid(uid);
                 if (pass)
                         name = strdup(pass->pw_name);
         }
 
         return name;
 }  }
   
 /* turn a gid into a group name */  /* turn a gid into a group name */
static const char *gid_to_name(gid_t gid)const char *gid_to_group(gid_t gid)
 {  {
        struct group *grp = getgrgid(gid);        const char *name = NULL;
        if (grp)
                return strdup(grp->gr_name);        if (namecvt_pid) {
        return NULL;                id_t id = gid;
                 namecvt_call("gid", &name, &id);
         } else {
                 struct group *grp = getgrgid(gid);
                 if (grp)
                         name = strdup(grp->gr_name);
         }
 
         return name;
 }  }
   
static uid_t map_uid(uid_t id, const char *name)/* Parse a user name or (optionally) a number into a uid */
 int user_to_uid(const char *name, uid_t *uid_p, BOOL num_ok)
 {  {
        uid_t uid;        if (!name || !*name)
        if (id != 0 && name_to_uid(name, &uid))                return 0;
                return uid;
        return id;        if (num_ok && name[strspn(name, "0123456789")] == '\0') {
                 *uid_p = id_parse(name);
                 return 1;
         }
 
         if (namecvt_pid) {
                 id_t id;
                 if (!namecvt_call("usr", &name, &id))
                         return 0;
                 *uid_p = id;
         } else {
                 struct passwd *pass = getpwnam(name);
                 if (!pass)
                         return 0;
                 *uid_p = pass->pw_uid;
         }
 
         return 1;
 }  }
   
static gid_t map_gid(gid_t id, const char *name)/* Parse a group name or (optionally) a number into a gid */
 int group_to_gid(const char *name, gid_t *gid_p, BOOL num_ok)
 {  {
        gid_t gid;        if (!name || !*name)
        if (id != 0 && name_to_gid(name, &gid))                return 0;
                return gid;
        return id;        if (num_ok && name[strspn(name, "0123456789")] == '\0') {
                 *gid_p = id_parse(name);
                 return 1;
         }
 
         if (namecvt_pid) {
                 id_t id;
                 if (!namecvt_call("grp", &name, &id))
                         return 0;
                 *gid_p = id;
         } else {
                 struct group *grp = getgrnam(name);
                 if (!grp)
                         return 0;
                 *gid_p = grp->gr_gid;
         }
 
         return 1;
 }  }
   
 static int is_in_group(gid_t gid)  static int is_in_group(gid_t gid)
Line 109  static int is_in_group(gid_t gid) Line 193  static int is_in_group(gid_t gid)
         if (gid == last_in && last_out >= 0)          if (gid == last_in && last_out >= 0)
                 return last_out;                  return last_out;
         if (ngroups < -1) {          if (ngroups < -1) {
                 gid_t mygid = MY_GID();  
                 if ((ngroups = getgroups(0, NULL)) < 0)                  if ((ngroups = getgroups(0, NULL)) < 0)
                         ngroups = 0;                          ngroups = 0;
                 gidset = new_array(GETGROUPS_T, ngroups+1);                  gidset = new_array(GETGROUPS_T, ngroups+1);
                 if (!gidset)  
                         out_of_memory("is_in_group");  
                 if (ngroups > 0)                  if (ngroups > 0)
                         ngroups = getgroups(ngroups, gidset);                          ngroups = getgroups(ngroups, gidset);
                 /* The default gid might not be in the list on some systems. */                  /* The default gid might not be in the list on some systems. */
                 for (n = 0; n < ngroups; n++) {                  for (n = 0; n < ngroups; n++) {
                        if (gidset[n] == mygid)                        if (gidset[n] == our_gid)
                                 break;                                  break;
                 }                  }
                 if (n == ngroups)                  if (n == ngroups)
                        gidset[ngroups++] = mygid;                        gidset[ngroups++] = our_gid;
                if (verbose > 3) {                if (DEBUG_GTE(OWN, 2)) {
                         int pos;                          int pos;
                         char *gidbuf = new_array(char, ngroups*21+32);                          char *gidbuf = new_array(char, ngroups*21+32);
                        if (!gidbuf)                        pos = snprintf(gidbuf, 32, "process has %d gid%s: ", ngroups, ngroups == 1? "" : "s");
                                out_of_memory("is_in_group"); 
                        pos = snprintf(gidbuf, 32, "process has %d gid%s: ", 
                                       ngroups, ngroups == 1? "" : "s"); 
                         for (n = 0; n < ngroups; n++) {                          for (n = 0; n < ngroups; n++) {
                                 pos += snprintf(gidbuf+pos, 21, " %d", (int)gidset[n]);                                  pos += snprintf(gidbuf+pos, 21, " %d", (int)gidset[n]);
                         }                          }
Line 147  static int is_in_group(gid_t gid) Line 225  static int is_in_group(gid_t gid)
         return last_out = 0;          return last_out = 0;
   
 #else  #else
        static gid_t mygid = GID_NONE;        return gid == our_gid;
        if (mygid == GID_NONE) { 
                mygid = MY_GID(); 
                if (verbose > 3) 
                        rprintf(FINFO, "process has gid %u\n", (unsigned)mygid); 
        } 
        return gid == mygid; 
 #endif  #endif
 }  }
   
/* Add a uid to the list of uids.  Only called on receiving side. *//* Add a uid/gid to its list of ids.  Only called on receiving side. */
static struct idlist *recv_add_uid(uid_t id, const char *name)static struct idlist *recv_add_id(struct idlist **idlist_ptr, struct idlist *idmap,
                                   id_t id, const char *name)
 {  {
         uid_t id2 = name ? map_uid(id, name) : id;  
         struct idlist *node;          struct idlist *node;
           union name_or_id noiu;
           int flag;
           id_t id2;
   
        node = add_to_list(&uidlist, id, name, id2, 0);        noiu.name = name; /* ensure that add_to_list() gets the raw value. */
         if (!name)
                 name = "";
   
        if (verbose > 3) {        for (node = idmap; node; node = node->next) {
                rprintf(FINFO, "uid %u(%s) maps to %u\n",                if (node->flags & NFLAGS_WILD_NAME_MATCH) {
                        (unsigned)id, name ? name : "", (unsigned)id2);                        if (!wildmatch(node->u.name, name))
                                 continue;
                 } else if (node->flags & NFLAGS_NAME_MATCH) {
                         if (strcmp(node->u.name, name) != 0)
                                 continue;
                 } else if (node->u.max_id) {
                         if (id < node->id || id > node->u.max_id)
                                 continue;
                 } else {
                         if (node->id != id)
                                 continue;
                 }
                 break;
         }          }
           if (node)
                   id2 = node->id2;
           else if (*name && id) {
                   if (idlist_ptr == &uidlist) {
                           uid_t uid;
                           id2 = user_to_uid(name, &uid, False) ? uid : id;
                   } else {
                           gid_t gid;
                           id2 = group_to_gid(name, &gid, False) ? gid : id;
                   }
           } else
                   id2 = id;
   
        return node;        flag = idlist_ptr == &gidlist && !am_root && !is_in_group(id2) ? FLAG_SKIP_GROUP : 0;
}        node = add_to_list(idlist_ptr, id, noiu, id2, flag);
   
/* Add a gid to the list of gids.  Only called on receiving side. */        if (DEBUG_GTE(OWN, 2)) {
static struct idlist *recv_add_gid(gid_t id, const char *name)                rprintf(FINFO, "%sid %u(%s) maps to %u\n",
{                        idlist_ptr == &uidlist ? "u" : "g",
        gid_t id2 = name ? map_gid(id, name) : id;                        (unsigned)id, name, (unsigned)id2);
        struct idlist *node; 
 
        node = add_to_list(&gidlist, id, name, id2, 
                !am_root && !is_in_group(id2) ? FLAG_SKIP_GROUP : 0); 
 
        if (verbose > 3) { 
                rprintf(FINFO, "gid %u(%s) maps to %u\n", 
                        (unsigned)id, name ? name : "", (unsigned)id2); 
         }          }
   
         return node;          return node;
 }  }
   
/* this function is a definate candidate for a faster algorithm *//* this function is a definite candidate for a faster algorithm */
 uid_t match_uid(uid_t uid)  uid_t match_uid(uid_t uid)
 {  {
        static uid_t last_in, last_out;        static struct idlist *last = NULL;
         struct idlist *list;          struct idlist *list;
   
        if (uid == 0)        if (last && uid == last->id)
                return 0;                return last->id2;
   
         if (uid == last_in)  
                 return last_out;  
   
         last_in = uid;  
   
         for (list = uidlist; list; list = list->next) {          for (list = uidlist; list; list = list->next) {
                 if (list->id == uid)                  if (list->id == uid)
                        return last_out = list->id2;                        break;
         }          }
   
        return last_out = uid;        if (!list)
                 list = recv_add_id(&uidlist, uidmap, uid, NULL);
         last = list;
 
         return list->id2;
 }  }
   
 gid_t match_gid(gid_t gid, uint16 *flags_ptr)  gid_t match_gid(gid_t gid, uint16 *flags_ptr)
Line 225  gid_t match_gid(gid_t gid, uint16 *flags_ptr) Line 317  gid_t match_gid(gid_t gid, uint16 *flags_ptr)
                                 break;                                  break;
                 }                  }
                 if (!list)                  if (!list)
                        list = recv_add_gid(gid, NULL);                        list = recv_add_id(&gidlist, gidmap, gid, NULL);
                 last = list;                  last = list;
         }          }
   
Line 239  const char *add_uid(uid_t uid) Line 331  const char *add_uid(uid_t uid)
 {  {
         struct idlist *list;          struct idlist *list;
         struct idlist *node;          struct idlist *node;
           union name_or_id noiu;
   
         if (uid == 0)   /* don't map root */  
                 return NULL;  
   
         for (list = uidlist; list; list = list->next) {          for (list = uidlist; list; list = list->next) {
                 if (list->id == uid)                  if (list->id == uid)
                         return NULL;                          return NULL;
         }          }
   
        node = add_to_list(&uidlist, uid, uid_to_name(uid), 0, 0);        noiu.name = uid_to_user(uid);
        return node->name;        node = add_to_list(&uidlist, uid, noiu, 0, 0);
         return node->u.name;
 }  }
   
 /* Add a gid to the list of gids.  Only called on sending side. */  /* Add a gid to the list of gids.  Only called on sending side. */
Line 257  const char *add_gid(gid_t gid) Line 348  const char *add_gid(gid_t gid)
 {  {
         struct idlist *list;          struct idlist *list;
         struct idlist *node;          struct idlist *node;
           union name_or_id noiu;
   
         if (gid == 0)   /* don't map root */  
                 return NULL;  
   
         for (list = gidlist; list; list = list->next) {          for (list = gidlist; list; list = list->next) {
                 if (list->id == gid)                  if (list->id == gid)
                         return NULL;                          return NULL;
         }          }
   
        node = add_to_list(&gidlist, gid, gid_to_name(gid), 0, 0);        noiu.name = gid_to_group(gid);
        return node->name;        node = add_to_list(&gidlist, gid, noiu, 0, 0);
         return node->u.name;
 }  }
   
/* send a complete uid/gid mapping to the peer */static void send_one_name(int f, id_t id, const char *name)
void send_id_list(int f) 
 {  {
        struct idlist *list;        int len;
   
        if (preserve_uid || preserve_acls) {        if (!name)
                int len;                name = "";
                /* we send sequences of uid/byte-length/name */        if ((len = strlen(name)) > 255) /* Impossible? */
                for (list = uidlist; list; list = list->next) {                len = 255;
                        if (!list->name) 
                                continue; 
                        len = strlen(list->name); 
                        write_varint30(f, list->id); 
                        write_byte(f, len); 
                        write_buf(f, list->name, len); 
                } 
   
                /* terminate the uid list with a 0 uid. We explicitly exclude        write_varint30(f, id);
                 * 0 from the list */        write_byte(f, len);
                write_varint30(f, 0);        if (len)
                 write_buf(f, name, len);
 }
 
 static void send_one_list(int f, struct idlist *idlist, int usernames)
 {
         struct idlist *list;
 
         /* we send sequences of id/byte-len/name */
         for (list = idlist; list; list = list->next) {
                 if (list->id && list->u.name)
                         send_one_name(f, list->id, list->u.name);
         }          }
   
        if (preserve_gid || preserve_acls) {        /* Terminate the uid list with 0 (which was excluded above).
                int len;         * A modern rsync also sends the name of id 0. */
                for (list = gidlist; list; list = list->next) {        if (xmit_id0_names)
                        if (!list->name)                send_one_name(f, 0, usernames ? uid_to_user(0) : gid_to_group(0));
                                continue;        else
                        len = strlen(list->name); 
                        write_varint30(f, list->id); 
                        write_byte(f, len); 
                        write_buf(f, list->name, len); 
                } 
                 write_varint30(f, 0);                  write_varint30(f, 0);
         }  
 }  }
   
   /* send a complete uid/gid mapping to the peer */
   void send_id_lists(int f)
   {
           if (preserve_uid || preserve_acls)
                   send_one_list(f, uidlist, 1);
   
           if (preserve_gid || preserve_acls)
                   send_one_list(f, gidlist, 0);
   }
   
 uid_t recv_user_name(int f, uid_t uid)  uid_t recv_user_name(int f, uid_t uid)
 {  {
         struct idlist *node;          struct idlist *node;
         int len = read_byte(f);          int len = read_byte(f);
        char *name = new_array(char, len+1);        char *name;
        if (!name)
                out_of_memory("recv_user_name");        if (len) {
        read_sbuf(f, name, len);                name = new_array(char, len+1);
        if (numeric_ids < 0) {                read_sbuf(f, name, len);
                free(name);                if (numeric_ids < 0) {
                         free(name);
                         name = NULL;
                 }
         } else
                 name = NULL;                  name = NULL;
        }
        node = recv_add_uid(uid, name); /* node keeps name's memory */        node = recv_add_id(&uidlist, uidmap, uid, name); /* node keeps name's memory */
         return node->id2;          return node->id2;
 }  }
   
Line 326  gid_t recv_group_name(int f, gid_t gid, uint16 *flags_ Line 427  gid_t recv_group_name(int f, gid_t gid, uint16 *flags_
 {  {
         struct idlist *node;          struct idlist *node;
         int len = read_byte(f);          int len = read_byte(f);
        char *name = new_array(char, len+1);        char *name;
        if (!name)
                out_of_memory("recv_group_name");        if (len) {
        read_sbuf(f, name, len);                name = new_array(char, len+1);
        if (numeric_ids < 0) {                read_sbuf(f, name, len);
                free(name);                if (numeric_ids < 0) {
                         free(name);
                         name = NULL;
                 }
         } else
                 name = NULL;                  name = NULL;
        }
        node = recv_add_gid(gid, name); /* node keeps name's memory */        node = recv_add_id(&gidlist, gidmap, gid, name); /* node keeps name's memory */
         if (flags_ptr && node->flags & FLAG_SKIP_GROUP)          if (flags_ptr && node->flags & FLAG_SKIP_GROUP)
                 *flags_ptr |= FLAG_SKIP_GROUP;                  *flags_ptr |= FLAG_SKIP_GROUP;
         return node->id2;          return node->id2;
Line 351  void recv_id_list(int f, struct file_list *flist) Line 456  void recv_id_list(int f, struct file_list *flist)
                 /* read the uid list */                  /* read the uid list */
                 while ((id = read_varint30(f)) != 0)                  while ((id = read_varint30(f)) != 0)
                         recv_user_name(f, id);                          recv_user_name(f, id);
                   if (xmit_id0_names)
                           recv_user_name(f, 0);
         }          }
   
         if ((preserve_gid || preserve_acls) && numeric_ids <= 0) {          if ((preserve_gid || preserve_acls) && numeric_ids <= 0) {
                 /* read the gid list */                  /* read the gid list */
                 while ((id = read_varint30(f)) != 0)                  while ((id = read_varint30(f)) != 0)
                         recv_group_name(f, id, NULL);                          recv_group_name(f, id, NULL);
                   if (xmit_id0_names)
                           recv_group_name(f, 0, NULL);
         }          }
   
         /* Now convert all the uids/gids from sender values to our values. */          /* Now convert all the uids/gids from sender values to our values. */
 #ifdef SUPPORT_ACLS  #ifdef SUPPORT_ACLS
        if (preserve_acls && !numeric_ids)        if (preserve_acls && (!numeric_ids || usermap || groupmap))
                 match_acl_ids();                  match_acl_ids();
 #endif  #endif
        if (am_root && preserve_uid && !numeric_ids) {        if (am_root && preserve_uid && (!numeric_ids || usermap)) {
                 for (i = 0; i < flist->used; i++)                  for (i = 0; i < flist->used; i++)
                         F_OWNER(flist->files[i]) = match_uid(F_OWNER(flist->files[i]));                          F_OWNER(flist->files[i]) = match_uid(F_OWNER(flist->files[i]));
         }          }
        if (preserve_gid && (!am_root || !numeric_ids)) {        if (preserve_gid && (!am_root || !numeric_ids || groupmap)) {
                 for (i = 0; i < flist->used; i++) {                  for (i = 0; i < flist->used; i++) {
                        F_GROUP(flist->files[i]) = match_gid(F_GROUP(flist->files[i]),                        F_GROUP(flist->files[i]) = match_gid(F_GROUP(flist->files[i]), &flist->files[i]->flags);
                                                             &flist->files[i]->flags); 
                 }                  }
         }          }
 }  }
   
   void parse_name_map(char *map, BOOL usernames)
   {
           struct idlist **idmap_ptr = usernames ? &uidmap : &gidmap;
           struct idlist **idlist_ptr = usernames ? &uidlist : &gidlist;
           char *colon, *cp = map + strlen(map);
           union name_or_id noiu;
           id_t id1;
           uint16 flags;
   
           /* Parse the list in reverse, so the order in the struct is right. */
           while (1) {
                   while (cp > map && cp[-1] != ',') cp--;
                   if (!(colon = strchr(cp, ':'))) {
                           rprintf(FERROR, "No colon found in --%smap: %s\n",
                                   usernames ? "user" : "group", cp);
                           exit_cleanup(RERR_SYNTAX);
                   }
                   if (!colon[1]) {
                           rprintf(FERROR, "No name found after colon --%smap: %s\n",
                                   usernames ? "user" : "group", cp);
                           exit_cleanup(RERR_SYNTAX);
                   }
                   *colon = '\0';
   
                   if (isDigit(cp)) {
                           char *dash = strchr(cp, '-');
                           if (strspn(cp, "0123456789-") != (size_t)(colon - cp)
                            || (dash && (!dash[1] || strchr(dash+1, '-')))) {
                                   rprintf(FERROR, "Invalid number in --%smap: %s\n",
                                           usernames ? "user" : "group", cp);
                                   exit_cleanup(RERR_SYNTAX);
                           }
                           if (dash) {
                                   *dash = '\0';
                                   noiu.max_id = id_parse(dash+1);
                           } else
                                   noiu.max_id = 0;
                           flags = 0;
                           id1 = id_parse(cp);
                           if (dash)
                                   *dash = '-';
                   } else if (strpbrk(cp, "*[?")) {
                           flags = NFLAGS_WILD_NAME_MATCH;
                           noiu.name = cp;
                           id1 = 0;
                   } else {
                           flags = NFLAGS_NAME_MATCH;
                           noiu.name = cp;
                           id1 = 0;
                   }
   
                   if (usernames) {
                           uid_t uid;
                           if (user_to_uid(colon+1, &uid, True))
                                   add_to_list(idmap_ptr, id1, noiu, uid, flags);
                           else {
                                   rprintf(FERROR, "Unknown --usermap name on receiver: %s\n", colon+1);
                           }
                   } else {
                           gid_t gid;
                           if (group_to_gid(colon+1, &gid, True))
                                   add_to_list(idmap_ptr, id1, noiu, gid, flags);
                           else {
                                   rprintf(FERROR, "Unknown --groupmap name on receiver: %s\n", colon+1);
                           }
                   }
   
                   if (cp == map)
                           break;
   
                   *--cp = '\0'; /* replace comma */
           }
   
           /* If the sender isn't going to xmit the id0 name, we assume it's "root". */
           if (!xmit_id0_names)
                   recv_add_id(idlist_ptr, *idmap_ptr, 0, numeric_ids ? NULL : "root");
   }
   
   #ifdef HAVE_GETGROUPLIST
   const char *getallgroups(uid_t uid, item_list *gid_list)
   {
           struct passwd *pw;
           gid_t *gid_array;
           int size;
   
           if ((pw = getpwuid(uid)) == NULL)
                   return "getpwuid failed";
   
           gid_list->count = 0; /* We're overwriting any items in the list */
           (void)EXPAND_ITEM_LIST(gid_list, gid_t, 32);
           size = gid_list->malloced;
   
           /* Get all the process's groups, with the pw_gid group first. */
           if (getgrouplist(pw->pw_name, pw->pw_gid, gid_list->items, &size) < 0) {
                   if (size > (int)gid_list->malloced) {
                           gid_list->count = gid_list->malloced;
                           (void)EXPAND_ITEM_LIST(gid_list, gid_t, size);
                           if (getgrouplist(pw->pw_name, pw->pw_gid, gid_list->items, &size) < 0)
                                   size = -1;
                   } else
                           size = -1;
                   if (size < 0)
                           return "getgrouplist failed";
           }
           gid_list->count = size;
           gid_array = gid_list->items;
   
           /* Paranoia: is the default group not first in the list? */
           if (gid_array[0] != pw->pw_gid) {
                   int j;
                   for (j = 1; j < size; j++) {
                           if (gid_array[j] == pw->pw_gid)
                                   break;
                   }
                   if (j == size) { /* The default group wasn't found! */
                           (void)EXPAND_ITEM_LIST(gid_list, gid_t, size+1);
                           gid_array = gid_list->items;
                   }
                   gid_array[j] = gid_array[0];
                   gid_array[0] = pw->pw_gid;
           }
   
           return NULL;
   }
   #endif

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


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