From: Wayne Davison Date: Wed, 24 Jun 2020 00:19:58 +0000 (-0700) Subject: Improve how the env restricts negotiated strings X-Git-Tag: v3.2.2pre1~21 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=323c42d51e2a7d94dd641d7be5de89a2704d441c;p=thirdparty%2Frsync.git Improve how the env restricts negotiated strings - The env on the server side now affects the negotiated strings that are sent to the client. - A too-old remote rsync gets a default negotiated string value so that an env restriction now handles old clients the same way as new ones. --- diff --git a/checksum.c b/checksum.c index 87e83658..7c915173 100644 --- a/checksum.c +++ b/checksum.c @@ -85,7 +85,7 @@ static const char *checksum_name(int num) { struct name_num_item *nni = get_nni_by_num(&valid_checksums, num); - return nni ? nni->name : num < CSUM_MD4 ? "MD4" : "UNKNOWN"; + return nni ? nni->name : num < CSUM_MD4 ? "md4" : "UNKNOWN"; } void parse_checksum_choice(int final_call) diff --git a/compat.c b/compat.c index 9ec39ea0..7a97cfc3 100644 --- a/compat.c +++ b/compat.c @@ -390,20 +390,12 @@ static void send_negotiate_str(int f_out, struct name_num_obj *nno, const char * { char tmpbuf[MAX_NSTR_STRLEN]; const char *list_str = getenv(env_name); - int len, fail_if_empty = list_str && strstr(list_str, "FAIL"); + int len; - if (!do_negotiated_strings) { - if (!am_server && fail_if_empty) { - rprintf(FERROR, "Remote rsync is too old for %s negotiation\n", nno->type); - exit_cleanup(RERR_UNSUPPORTED); - } - return; - } - - if (list_str && *list_str && (!am_server || local_server)) { + if (list_str && *list_str) { init_nno_saw(nno, 0); len = parse_nni_str(nno, list_str, tmpbuf, MAX_NSTR_STRLEN); - if (fail_if_empty && !len) + if (!len) len = strlcpy(tmpbuf, "FAIL", MAX_NSTR_STRLEN); list_str = tmpbuf; } else @@ -423,7 +415,7 @@ static void send_negotiate_str(int f_out, struct name_num_obj *nno, const char * /* A local server doesn't bother to send/recv the strings, it just constructs * and parses the same string on both sides. */ recv_negotiate_str(-1, nno, tmpbuf, len); - } else { + } else if (do_negotiated_strings) { /* 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. */ write_vstring(f_out, tmpbuf, len); @@ -442,13 +434,28 @@ static void negotiate_the_strings(int f_in, int f_out) if (valid_checksums.saw) { char tmpbuf[MAX_NSTR_STRLEN]; - recv_negotiate_str(f_in, &valid_checksums, tmpbuf, -1); + int len; + if (do_negotiated_strings) + len = -1; + else + len = strlcpy(tmpbuf, protocol_version >= 30 ? "md5" : "md4", MAX_NSTR_STRLEN); + recv_negotiate_str(f_in, &valid_checksums, tmpbuf, len); } if (valid_compressions.saw) { char tmpbuf[MAX_NSTR_STRLEN]; - recv_negotiate_str(f_in, &valid_compressions, tmpbuf, -1); + int len; + if (do_negotiated_strings) + len = -1; + else + len = strlcpy(tmpbuf, "zlib", MAX_NSTR_STRLEN); + recv_negotiate_str(f_in, &valid_compressions, tmpbuf, len); } + + /* If the other side is too old to negotiate, the above steps just made sure that + * the env didn't disallow the old algorithm. Mark things as non-negotiated. */ + if (!do_negotiated_strings) + valid_checksums.negotiated_name = valid_compressions.negotiated_name = NULL; } void setup_protocol(int f_out,int f_in) diff --git a/rsync.1.md b/rsync.1.md index 164cbd44..ebd59dca 100644 --- a/rsync.1.md +++ b/rsync.1.md @@ -1490,7 +1490,8 @@ your home directory (remove the '=' for that). a negotiation between the client and the server as follows: If both the client and the server are at least version 3.2.0, they will - exchange a list of checksum names and choose the first one in the list that + exchange a list of checksum names and choose the first one in the client's + list that they have in common. This typically means that they will choose xxh64 if they both support it and fall back to MD5. If one side of the transfer is not new enough to support this checksum negotiation, then a value is chosen @@ -1503,8 +1504,8 @@ your home directory (remove the '=' for that). client exits with an error. This method does not allow you to specify the transfer checksum separately from the pre-transfer checksum, and it ignores "auto" and all unknown checksum names. If the remote rsync is not new - enough to handle a checksum negotiation list, the list is silently ignored - unless it contains the string "FAIL". + enough to handle a checksum negotiation list, its list is assumed to + consist of a single "md5" or "md4" item based on the protocol version. The use of the `--checksum-choice` option overrides this environment list. @@ -2267,13 +2268,11 @@ your home directory (remove the '=' for that). 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. You default order can be customized by setting the environment + of choices. Your default order can be customized by setting the environment variable RSYNC_COMPRESS_LIST to a space-separated list of acceptable compression names. If no common compress choice is found, the client exits - with an error. The one exception to this is that the list is ignored when - talking with an old rsync that doesn't support the checksum negotiation. - Include the string "FAIL" in your list if you want rsync to fail in such a - case. + with an error. If the remote rsync is too old to support checksum negotiation, + its list is assumed to be "zlib". There are some older rsync versions that were configured to reject a `-z` option and require the use of `-zz` because their compression library was @@ -2297,6 +2296,8 @@ your home directory (remove the '=' for that). - `zlib` - `none` + Run `rsync -V` to see the compress list compiled into your version. + Note that if you see an error about an option named `--old-compress` or `--new-compress`, this is rsync trying to send the `--compress-choice=zlib` or `--compress-choice=zlibx` option in a backward-compatible manner that