Send the uid/gid 0 name since not all systems use 0 for root.
authorWayne Davison <wayne@opencoder.net>
Mon, 6 Jul 2020 05:51:12 +0000 (22:51 -0700)
committerWayne Davison <wayne@opencoder.net>
Mon, 6 Jul 2020 05:51:12 +0000 (22:51 -0700)
compat.c
flist.c
options.c
uidlist.c

index 527201ace54e1a07e01bf0e5d0d3defcc8d4167f..4719ef56a7fdd87e1178858adaa60872767c3ccc 100644 (file)
--- a/compat.c
+++ b/compat.c
@@ -73,6 +73,7 @@ int want_xattr_optim = 0;
 int proper_seed_order = 0;
 int inplace_partial = 0;
 int do_negotiated_strings = 0;
+int xmit_id0_names = 0;
 
 /* These index values are for the file-list's extra-attribute array. */
 int pathname_ndx, depth_ndx, atimes_ndx, uid_ndx, gid_ndx, acls_ndx, xattrs_ndx, unsort_ndx;
@@ -109,6 +110,7 @@ struct name_num_obj valid_compressions = {
 #define CF_CHKSUM_SEED_FIX (1<<5)
 #define CF_INPLACE_PARTIAL_DIR (1<<6)
 #define CF_VARINT_FLIST_FLAGS (1<<7)
+#define CF_ID0_NAMES (1<<8)
 
 static const char *client_info;
 
@@ -694,6 +696,8 @@ void setup_protocol(int f_out,int f_in)
                                compat_flags |= CF_CHKSUM_SEED_FIX;
                        if (local_server || strchr(client_info, 'I') != NULL)
                                compat_flags |= CF_INPLACE_PARTIAL_DIR;
+                       if (local_server || strchr(client_info, 'u') != NULL)
+                               compat_flags |= CF_ID0_NAMES;
                        if (local_server || strchr(client_info, 'v') != NULL) {
                                do_negotiated_strings = 1;
                                compat_flags |= CF_VARINT_FLIST_FLAGS;
@@ -714,6 +718,7 @@ void setup_protocol(int f_out,int f_in)
                want_xattr_optim = protocol_version >= 31 && !(compat_flags & CF_AVOID_XATTR_OPTIM);
                proper_seed_order = compat_flags & CF_CHKSUM_SEED_FIX ? 1 : 0;
                xfer_flags_as_varint = compat_flags & CF_VARINT_FLIST_FLAGS ? 1 : 0;
+               xmit_id0_names = compat_flags & CF_ID0_NAMES ? 1 : 0;
                if (am_sender) {
                        receiver_symlink_times = am_server
                            ? strchr(client_info, 'L') != NULL
diff --git a/flist.c b/flist.c
index 5970ce548f4eeb88988f2a301f2db3da89e11d8f..21c0b31a0d2ed47936c7f9d81d8ace645215fbd7 100644 (file)
--- a/flist.c
+++ b/flist.c
@@ -2412,7 +2412,7 @@ struct file_list *send_file_list(int f, int argc, char *argv[])
        file_old_total += flist->used;
 
        if (numeric_ids <= 0 && !inc_recurse)
-               send_id_list(f);
+               send_id_lists(f);
 
        /* send the io_error flag */
        if (protocol_version < 30)
index 956d6e33ee715d0080016c0f84dedc8b8d561b22..5a372ae7de30ee6a40a83aa73cbd8babce0a1746 100644 (file)
--- a/options.c
+++ b/options.c
@@ -2608,6 +2608,7 @@ void server_options(char **args, int *argc_p)
                eFlags[x++] = 'C'; /* support checksum seed order fix */
                eFlags[x++] = 'I'; /* support inplace_partial behavior */
                eFlags[x++] = 'v'; /* use varint for flist & compat flags; negotiate checksum */
+               eFlags[x++] = 'u'; /* include name of uid 0 & gid 0 in the id map */
                /* NOTE: Avoid using 'V' -- it was the high bit of a write_byte() that became write_varint(). */
 #undef eFlags
        }
index cf42f103bdbcac4629970b7b452f58dbdc1f4e43..975636a84ab7de77d7b062018463cb95b7c6ff23 100644 (file)
--- a/uidlist.c
+++ b/uidlist.c
@@ -33,6 +33,7 @@ extern int preserve_uid;
 extern int preserve_gid;
 extern int preserve_acls;
 extern int numeric_ids;
+extern int xmit_id0_names;
 extern gid_t our_gid;
 extern char *usermap;
 extern char *groupmap;
@@ -295,9 +296,6 @@ const char *add_uid(uid_t uid)
        struct idlist *node;
        union name_or_id noiu;
 
-       if (uid == 0)   /* don't map root */
-               return NULL;
-
        for (list = uidlist; list; list = list->next) {
                if (list->id == uid)
                        return NULL;
@@ -315,9 +313,6 @@ const char *add_gid(gid_t gid)
        struct idlist *node;
        union name_or_id noiu;
 
-       if (gid == 0)   /* don't map root */
-               return NULL;
-
        for (list = gidlist; list; list = list->next) {
                if (list->id == gid)
                        return NULL;
@@ -328,40 +323,43 @@ const char *add_gid(gid_t gid)
        return node->u.name;
 }
 
-/* send a complete uid/gid mapping to the peer */
-void send_id_list(int f)
+static void send_one_name(int f, id_t id, const char *name)
 {
-       struct idlist *list;
+       int len = strlen(name);
+       if (len > 255) /* Impossible? */
+               len = 255;
 
-       if (preserve_uid || preserve_acls) {
-               int len;
-               /* we send sequences of uid/byte-length/name */
-               for (list = uidlist; list; list = list->next) {
-                       if (!list->u.name)
-                               continue;
-                       len = strlen(list->u.name);
-                       write_varint30(f, list->id);
-                       write_byte(f, len);
-                       write_buf(f, list->u.name, len);
-               }
+       write_varint30(f, id);
+       write_byte(f, len);
+       write_buf(f, name, len);
+}
 
-               /* terminate the uid list with a 0 uid. We explicitly exclude
-                * 0 from the list */
-               write_varint30(f, 0);
+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) {
-               int len;
-               for (list = gidlist; list; list = list->next) {
-                       if (!list->u.name)
-                               continue;
-                       len = strlen(list->u.name);
-                       write_varint30(f, list->id);
-                       write_byte(f, len);
-                       write_buf(f, list->u.name, len);
-               }
+       /* Terminate the uid list with 0 (which was excluded above).
+        * A modern rsync also sends the name of id 0. */
+       if (xmit_id0_names)
+               send_one_name(f, 0, usernames ? uid_to_user(0) : gid_to_group(0));
+       else
                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)
@@ -405,12 +403,16 @@ void recv_id_list(int f, struct file_list *flist)
                /* read the uid list */
                while ((id = read_varint30(f)) != 0)
                        recv_user_name(f, id);
+               if (xmit_id0_names)
+                       recv_user_name(f, 0);
        }
 
        if ((preserve_gid || preserve_acls) && numeric_ids <= 0) {
                /* read the gid list */
                while ((id = read_varint30(f)) != 0)
                        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. */
@@ -502,8 +504,9 @@ void parse_name_map(char *map, BOOL usernames)
                *--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));
+       /* 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