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

version 1.1.1.1, 2012/02/17 15:09:30 version 1.1.1.2, 2013/10/14 07:51:14
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-2013 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 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 43  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)          if (!node)
                 out_of_memory("add_to_list");                  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)char *uid_to_user(uid_t uid)
 {  {
         struct passwd *pass = getpwuid(uid);          struct passwd *pass = getpwuid(uid);
         if (pass)          if (pass)
Line 74  static const char *uid_to_name(uid_t uid) Line 106  static const char *uid_to_name(uid_t uid)
 }  }
   
 /* turn a gid into a group name */  /* turn a gid into a group name */
static const char *gid_to_name(gid_t gid)char *gid_to_group(gid_t gid)
 {  {
         struct group *grp = getgrgid(gid);          struct group *grp = getgrgid(gid);
         if (grp)          if (grp)
Line 82  static const char *gid_to_name(gid_t gid) Line 114  static const char *gid_to_name(gid_t gid)
         return NULL;          return NULL;
 }  }
   
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;        struct passwd *pass;
        if (id != 0 && name_to_uid(name, &uid))        if (!name || !*name)
                return uid;                return 0;
        return id;        if (num_ok && name[strspn(name, "0123456789")] == '\0') {
                 *uid_p = id_parse(name);
                 return 1;
         }
         if (!(pass = getpwnam(name)))
                 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;        struct group *grp;
        if (id != 0 && name_to_gid(name, &gid))        if (!name || !*name)
                return gid;                return 0;
        return id;        if (num_ok && name[strspn(name, "0123456789")] == '\0') {
                 *gid_p = id_parse(name);
                 return 1;
         }
         if (!(grp = getgrnam(name)))
                 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 157  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);
Line 119  static int is_in_group(gid_t gid) Line 166  static int is_in_group(gid_t gid)
                         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)                          if (!gidbuf)
Line 147  static int is_in_group(gid_t gid) Line 194  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;
Line 193  static struct idlist *recv_add_gid(gid_t id, const cha Line 255  static struct idlist *recv_add_gid(gid_t id, const cha
 /* this function is a definate candidate for a faster algorithm */  /* this function is a definate 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 286  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 300  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 */          if (uid == 0)   /* don't map root */
                 return NULL;                  return NULL;
Line 248  const char *add_uid(uid_t uid) Line 310  const char *add_uid(uid_t 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 320  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 */          if (gid == 0)   /* don't map root */
                 return NULL;                  return NULL;
Line 266  const char *add_gid(gid_t gid) Line 330  const char *add_gid(gid_t 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 */  /* send a complete uid/gid mapping to the peer */
Line 279  void send_id_list(int f) Line 344  void send_id_list(int f)
                 int len;                  int len;
                 /* we send sequences of uid/byte-length/name */                  /* we send sequences of uid/byte-length/name */
                 for (list = uidlist; list; list = list->next) {                  for (list = uidlist; list; list = list->next) {
                        if (!list->name)                        if (!list->u.name)
                                 continue;                                  continue;
                        len = strlen(list->name);                        len = strlen(list->u.name);
                         write_varint30(f, list->id);                          write_varint30(f, list->id);
                         write_byte(f, len);                          write_byte(f, len);
                        write_buf(f, list->name, len);                        write_buf(f, list->u.name, len);
                 }                  }
   
                 /* terminate the uid list with a 0 uid. We explicitly exclude                  /* terminate the uid list with a 0 uid. We explicitly exclude
Line 295  void send_id_list(int f) Line 360  void send_id_list(int f)
         if (preserve_gid || preserve_acls) {          if (preserve_gid || preserve_acls) {
                 int len;                  int len;
                 for (list = gidlist; list; list = list->next) {                  for (list = gidlist; list; list = list->next) {
                        if (!list->name)                        if (!list->u.name)
                                 continue;                                  continue;
                        len = strlen(list->name);                        len = strlen(list->u.name);
                         write_varint30(f, list->id);                          write_varint30(f, list->id);
                         write_byte(f, len);                          write_byte(f, len);
                        write_buf(f, list->name, len);                        write_buf(f, list->u.name, len);
                 }                  }
                 write_varint30(f, 0);                  write_varint30(f, 0);
         }          }
Line 318  uid_t recv_user_name(int f, uid_t uid) Line 383  uid_t recv_user_name(int f, uid_t uid)
                 free(name);                  free(name);
                 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 334  gid_t recv_group_name(int f, gid_t gid, uint16 *flags_ Line 399  gid_t recv_group_name(int f, gid_t gid, uint16 *flags_
                 free(name);                  free(name);
                 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 361  void recv_id_list(int f, struct file_list *flist) Line 426  void recv_id_list(int f, struct file_list *flist)
   
         /* 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)
                                   noiu.max_id = id_parse(dash+1);
                           else
                                   noiu.max_id = 0;
                           flags = 0;
                           id1 = id_parse(cp);
                   } 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 */
           }
   
           /* The 0 user/group doesn't get its name sent, so add it explicitly. */
           recv_add_id(idlist_ptr, *idmap_ptr, 0,
                       numeric_ids ? NULL : usernames ? uid_to_user(0) : gid_to_group(0));
   }
   
   #ifdef HAVE_GETGROUPLIST
   const char *getallgroups(uid_t uid, gid_t *gid_list, int *size_ptr)
   {
           struct passwd *pw;
           if ((pw = getpwuid(uid)) == NULL)
                   return "getpwuid failed";
           /* Get all the process's groups, with the pw_gid group first. */
           if (getgrouplist(pw->pw_name, pw->pw_gid, gid_list, size_ptr) < 0)
                   return "getgrouplist failed";
           /* Paranoia: is the default group not first in the list? */
           if (gid_list[0] != pw->pw_gid) {
                   int j;
                   for (j = 0; j < *size_ptr; j++) {
                           if (gid_list[j] == pw->pw_gid) {
                                   gid_list[j] = gid_list[0];
                                   gid_list[0] = pw->pw_gid;
                                   break;
                           }
                   }
           }
           return NULL;
   }
   #endif

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


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