compat: assign metadata ndx after batch flags; pick own preferred name

Move the uid/gid/acls/xattrs *_ndx assignments past check_batch_flags():
a mismatched-flag batch otherwise wrote F_XATTR(file) at offset 0 of
every file_struct, clobbering file->dirname. parse_negotiate_str() no
longer short-circuits on am_server, so each side picks its own #1 mutual
digest/checksum/compress choice rather than deferring to the peer's
order; man pages updated to match.

Co-authored-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Andrew TridgellandGreg Kroah-Hartman committed 2026-06-22 09:21:59 +10:00
1 parent 422fc5aff8
commit cd82ef3782
3 files changed
+35 -21

No files matched your search

+22 -11
View File
@@ -350,7 +350,7 @@ static int parse_negotiate_str(struct name_num_obj *nno, char *tmpbuf)
continue;
ret = nni;
best = nno->saw[nni->num];
if (best == 1 || am_server) /* The server side stops at the first acceptable client choice */
if (best == 1) /* Can't improve on our own #1 preference */
break;
}
if (ret) {
@@ -525,8 +525,11 @@ static void send_negotiate_str(int f_out, struct name_num_obj *nno, int ntype)
rprintf(FINFO, "Client %s list (on client): %s\n", nno->type, tmpbuf);
}
/* Each side sends their list of valid names to the other side and then both sides
* pick the first name in the client's list that is also in the server's list. */
/* Each side sends their list of valid names to the other side and then each
* side picks its own most-preferred name that also appears in the peer's
* list. Honest peers emit their list in table (strongest-first) order via
* get_default_nno_list(), so both sides converge on the strongest mutual
* choice; a peer that front-loads a weaker name only desyncs itself. */
if (do_negotiated_strings)
write_vstring(f_out, tmpbuf, len);
}
@@ -584,14 +587,13 @@ void setup_protocol(int f_out,int f_in)
pathname_ndx = (file_extra_cnt += PTR_EXTRA_CNT);
else
depth_ndx = ++file_extra_cnt;
if (preserve_uid)
uid_ndx = ++file_extra_cnt;
if (preserve_gid)
gid_ndx = ++file_extra_cnt;
if (preserve_acls && !am_sender)
acls_ndx = ++file_extra_cnt;
if (preserve_xattrs)
xattrs_ndx = ++file_extra_cnt;
/* uid_ndx/gid_ndx/acls_ndx/xattrs_ndx are assigned AFTER
* check_batch_flags() below: a batch file's stream-flags can flip
* preserve_uid/gid/acls/xattrs on, and computing the *_ndx slots
* before that leaves e.g. preserve_xattrs=1 with xattrs_ndx=0 -- so
* F_XATTR(file) (= REQ_EXTRA(file, 0)) writes at offset 0 of every
* file_struct, clobbering file->dirname. Nothing between here and
* check_batch_flags() reads file_extra_cnt or the *_ndx values. */
if (am_server)
set_allow_inc_recurse();
@@ -638,6 +640,15 @@ void setup_protocol(int f_out,int f_in)
if (read_batch)
check_batch_flags();
if (preserve_uid)
uid_ndx = ++file_extra_cnt;
if (preserve_gid)
gid_ndx = ++file_extra_cnt;
if (preserve_acls && !am_sender)
acls_ndx = ++file_extra_cnt;
if (preserve_xattrs)
xattrs_ndx = ++file_extra_cnt;
if (!saw_stderr_opt && protocol_version <= 28 && am_server)
msgs2stderr = 0; /* The client side may not have stderr setup for us. */
+8 -6
View File
@@ -1876,9 +1876,10 @@ expand it.
The "auto" option is the default, where rsync bases its algorithm choice on
a negotiation between the client and the server as follows:
When both sides of the transfer are at least 3.2.0, rsync chooses the first
algorithm in the client's list of choices that is also in the server's list
of choices. If no common checksum choice is found, rsync exits with
When both sides of the transfer are at least 3.2.0, each side chooses its own
most-preferred algorithm that also appears in the peer's list. Both sides
order their lists strongest-first, so they converge on the strongest mutual
choice. If no common checksum choice is found, rsync exits with
an error. If the remote rsync is too old to support checksum negotiation,
a value is chosen based on the protocol version (which chooses between MD5
and various flavors of MD4 based on protocol age).
@@ -2813,9 +2814,10 @@ expand it.
Run `rsync --version` to see the default compress list compiled into your
version.
When both sides of the transfer are at least 3.2.0, rsync chooses the first
algorithm in the client's list of choices that is also in the server's list
of choices. If no common compress choice is found, rsync exits with
When both sides of the transfer are at least 3.2.0, each side chooses its own
most-preferred algorithm that also appears in the peer's list. Both sides
order their lists strongest-first, so they converge on the strongest mutual
choice. If no common compress choice is found, rsync exits with
an error. If the remote rsync is too old to support checksum negotiation,
its list is assumed to be "zlib".
+5 -4
View File
@@ -758,10 +758,11 @@ in the values of parameters. See that section for details.
This parameter sets the *minimum* message digest that the daemon will accept
for the challenge-response authentication of an "[auth users](#)" module.
The available digests, strongest first, are `sha512`, `sha256`, `sha1`,
`md5`, `md4`. The daemon selects the auth digest from the connecting
client's advertised list (and falls back to `md5`, or `md4` below protocol
30, for a client that advertises none), so the negotiated digest can be
weaker than both sides actually support. If it is weaker than the configured
`md5`, `md4`. The daemon selects its own most-preferred digest that also
appears in the connecting client's advertised list (and falls back to `md5`,
or `md4` below protocol 30, for a client that advertises none), so a client
that advertises only weak digests can still force a weak negotiated digest.
If it is weaker than the configured
name, the connection is refused before the challenge is sent. The value is a
single digest name, for example: