From 7e2711bb2b4b30bc842dd8670c34a87e2ca0c2df Mon Sep 17 00:00:00 2001 From: Wayne Davison Date: Sat, 10 Sep 2022 09:43:47 -0700 Subject: [PATCH] Improve various things in the checksum code - Size flist checksum data to hold the active size, not the max. - Add a negotiated hash method to the daemon auth code. - Use EVP for all openssl digests. This makes it easy to add more openssl digest methods and avoids deprecation warnings. - Support a way to re-enable deprecated digests via openssl conf file and allow a default file to be configured. - Supply a simple openssl-rsync.cnf file to enable legacy digests. --- NEWS.md | 22 ++ authenticate.c | 11 +- checksum.c | 398 +++++++++++++++++++++++------------- clientserver.c | 19 +- compat.c | 190 +++++++++++------ configure.ac | 10 + flist.c | 6 +- lib/md-defines.h | 1 + lib/md5.c | 2 - lib/mdigest.h | 11 +- log.c | 10 +- main.c | 11 + match.c | 18 +- packaging/openssl-rsync.cnf | 18 ++ receiver.c | 13 +- rsync.h | 11 +- usage.c | 7 +- xattrs.c | 29 +-- 18 files changed, 517 insertions(+), 270 deletions(-) create mode 100644 packaging/openssl-rsync.cnf diff --git a/NEWS.md b/NEWS.md index ba32fdd2..cbeb31b7 100644 --- a/NEWS.md +++ b/NEWS.md @@ -6,6 +6,28 @@ - ... +### ENHANCEMENTS: + +- Added negotiated daemon-auth support that allows a stronger checksum digest + to be used. + +### PACKAGING RELATED: + +- The checksum code now uses openssl's EVP methods, which gets rid of various + deprecation warnings and makes it easy to support more digest methods. On + newer systems, the MD4 digest is marked as legacy in the openssl code, which + makes openssl refuse to support it via EVP. You can just ignore this and + allow the included MD4 code to be used for older rsync connections (when + talking to an rsync prior to 3.0.0) or you can configure rsync to tell + openssl to enable legacy algorithms (see below). + +- A simple openssl config file is supplied that can be optionally installed for + rsync to use. If you install packaging/openssl-rsync.cnf to a public spot + (such as ` /etc/ssl/openssl-rsync.cnf` or similar) and then configure rsync + using `--with-openssl-conf=/path/name.cnf`, this will cause rsync to export + the configured path in the OPENSSL_CONF environment variable (when it is not + already set). This will enable openssl's MD4 code for rsync to use. + ------------------------------------------------------------------------------ # NEWS for rsync 3.2.6 (9 Sep 2022) diff --git a/authenticate.c b/authenticate.c index 4306d167..01b26c08 100644 --- a/authenticate.c +++ b/authenticate.c @@ -24,6 +24,7 @@ extern int read_only; extern char *password_file; +extern struct name_num_obj valid_auth_checksums; /*************************************************************************** encode a buffer using base64 - simple and slow algorithm. null terminates @@ -72,9 +73,9 @@ static void gen_challenge(const char *addr, char *challenge) SIVAL(input, 20, tv.tv_usec); SIVAL(input, 24, getpid()); - sum_init(-1, 0); + len = sum_init(valid_auth_checksums.negotiated_nni, 0); sum_update(input, sizeof input); - len = sum_end(digest); + sum_end(digest); base64_encode(digest, len, challenge, 0); } @@ -86,10 +87,10 @@ static void generate_hash(const char *in, const char *challenge, char *out) char buf[MAX_DIGEST_LEN]; int len; - sum_init(-1, 0); + len = sum_init(valid_auth_checksums.negotiated_nni, 0); sum_update(in, strlen(in)); sum_update(challenge, strlen(challenge)); - len = sum_end(buf); + sum_end(buf); base64_encode(buf, len, out, 0); } @@ -238,6 +239,7 @@ char *auth_server(int f_in, int f_out, int module, const char *host, if (!users || !*users) return ""; + negotiate_daemon_auth(f_out, 0); gen_challenge(addr, challenge); io_printf(f_out, "%s%s\n", leader, challenge); @@ -350,6 +352,7 @@ void auth_client(int fd, const char *user, const char *challenge) if (!user || !*user) user = "nobody"; + negotiate_daemon_auth(-1, 1); if (!(pass = getpassf(password_file)) && !(pass = getenv("RSYNC_PASSWORD"))) { diff --git a/checksum.c b/checksum.c index 7eb50f17..4fa8faa0 100644 --- a/checksum.c +++ b/checksum.c @@ -42,50 +42,83 @@ extern int protocol_version; extern int proper_seed_order; extern const char *checksum_choice; +#define NNI_BUILTIN (1<<0) +#define NNI_EVP (1<<1) +#define NNI_EVP_OK (1<<2) + struct name_num_item valid_checksums_items[] = { #ifdef SUPPORT_XXH3 - { CSUM_XXH3_128, "xxh128", NULL }, - { CSUM_XXH3_64, "xxh3", NULL }, + { CSUM_XXH3_128, 0, "xxh128", NULL }, + { CSUM_XXH3_64, 0, "xxh3", NULL }, #endif #ifdef SUPPORT_XXHASH - { CSUM_XXH64, "xxh64", NULL }, - { CSUM_XXH64, "xxhash", NULL }, + { CSUM_XXH64, 0, "xxh64", NULL }, + { CSUM_XXH64, 0, "xxhash", NULL }, #endif - { CSUM_MD5, "md5", NULL }, - { CSUM_MD4, "md4", NULL }, - { CSUM_NONE, "none", NULL }, - { 0, NULL, NULL } + { CSUM_MD5, NNI_BUILTIN|NNI_EVP, "md5", NULL }, + { CSUM_MD4, NNI_BUILTIN|NNI_EVP, "md4", NULL }, + { CSUM_NONE, 0, "none", NULL }, + { 0, 0, NULL, NULL } }; struct name_num_obj valid_checksums = { - "checksum", NULL, NULL, 0, 0, valid_checksums_items + "checksum", NULL, 0, 0, valid_checksums_items +}; + +struct name_num_item valid_auth_checksums_items[] = { + { CSUM_MD5, NNI_BUILTIN|NNI_EVP, "md5", NULL }, + { CSUM_MD4, NNI_BUILTIN|NNI_EVP, "md4", NULL }, + { 0, 0, NULL, NULL } }; -int xfersum_type = 0; /* used for the file transfer checksums */ -int checksum_type = 0; /* used for the pre-transfer (--checksum) checksums */ +struct name_num_obj valid_auth_checksums = { + "daemon auth checksum", NULL, 0, 0, valid_auth_checksums_items +}; +/* These cannot make use of openssl, so they're marked just as built-in */ +struct name_num_item implied_checksum_md4 = + { CSUM_MD4, NNI_BUILTIN, "md4", NULL }; +struct name_num_item implied_checksum_md5 = + { CSUM_MD5, NNI_BUILTIN, "md5", NULL }; + +struct name_num_item *xfer_sum_nni; /* used for the transfer checksum2 computations */ +const EVP_MD *xfer_sum_evp_md; +int xfer_sum_len; +struct name_num_item *file_sum_nni; /* used for the pre-transfer --checksum computations */ +const EVP_MD *file_sum_evp_md; +int file_sum_len; + +#ifdef USE_OPENSSL +EVP_MD_CTX *ctx_evp = NULL; +#endif static int initialized_choices = 0; -int parse_csum_name(const char *name, int len) +struct name_num_item *parse_csum_name(const char *name, int len) { struct name_num_item *nni; if (len < 0 && name) len = strlen(name); + init_checksum_choices(); + if (!name || (len == 4 && strncasecmp(name, "auto", 4) == 0)) { - if (protocol_version >= 30) - return CSUM_MD5; - if (protocol_version >= 27) - return CSUM_MD4_OLD; - if (protocol_version >= 21) - return CSUM_MD4_BUSTED; - return CSUM_MD4_ARCHAIC; + if (protocol_version >= 30) { + if (!proper_seed_order) + return &implied_checksum_md5; + name = "md5"; + len = 3; + } else { + if (protocol_version >= 27) + implied_checksum_md4.num = CSUM_MD4_OLD; + else if (protocol_version >= 21) + implied_checksum_md4.num = CSUM_MD4_BUSTED; + else + implied_checksum_md4.num = CSUM_MD4_ARCHAIC; + return &implied_checksum_md4; + } } - if (!initialized_choices) - init_checksum_choices(); - nni = get_nni_by_name(&valid_checksums, name, len); if (!nni) { @@ -93,44 +126,72 @@ int parse_csum_name(const char *name, int len) exit_cleanup(RERR_UNSUPPORTED); } - return nni->num; + return nni; } -static const char *checksum_name(int num) +static const EVP_MD *csum_evp_md(struct name_num_item *nni) { - struct name_num_item *nni = get_nni_by_num(&valid_checksums, num); - - return nni ? nni->name : num < CSUM_MD4 ? "md4" : "UNKNOWN"; +#ifdef USE_OPENSSL + const EVP_MD *emd; + if (!(nni->flags & NNI_EVP)) + return NULL; + +#ifdef USE_MD5_ASM + if (nni->num == CSUM_MD5) + emd = NULL; + else +#endif + emd = EVP_get_digestbyname(nni->name); + if (emd && !(nni->flags & NNI_EVP_OK)) { /* Make sure it works before we advertise it */ + if (!ctx_evp && !(ctx_evp = EVP_MD_CTX_create())) + out_of_memory("csum_evp_md"); + /* Some routines are marked as legacy and are not enabled in the openssl.cnf file. + * If we can't init the emd, we'll fall back to our built-in code. */ + if (EVP_DigestInit_ex(ctx_evp, emd, NULL) == 0) + emd = NULL; + else + nni->flags = (nni->flags & ~NNI_BUILTIN) | NNI_EVP_OK; + } + if (!emd) + nni->flags &= ~NNI_EVP; + return emd; +#else + return NULL; +#endif } void parse_checksum_choice(int final_call) { - if (valid_checksums.negotiated_name) - xfersum_type = checksum_type = valid_checksums.negotiated_num; + if (valid_checksums.negotiated_nni) + xfer_sum_nni = file_sum_nni = valid_checksums.negotiated_nni; else { char *cp = checksum_choice ? strchr(checksum_choice, ',') : NULL; if (cp) { - xfersum_type = parse_csum_name(checksum_choice, cp - checksum_choice); - checksum_type = parse_csum_name(cp+1, -1); + xfer_sum_nni = parse_csum_name(checksum_choice, cp - checksum_choice); + file_sum_nni = parse_csum_name(cp+1, -1); } else - xfersum_type = checksum_type = parse_csum_name(checksum_choice, -1); + xfer_sum_nni = file_sum_nni = parse_csum_name(checksum_choice, -1); if (am_server && checksum_choice) - validate_choice_vs_env(NSTR_CHECKSUM, xfersum_type, checksum_type); + validate_choice_vs_env(NSTR_CHECKSUM, xfer_sum_nni->num, file_sum_nni->num); } + xfer_sum_len = csum_len_for_type(xfer_sum_nni->num, 0); + file_sum_len = csum_len_for_type(file_sum_nni->num, 0); + xfer_sum_evp_md = csum_evp_md(xfer_sum_nni); + file_sum_evp_md = csum_evp_md(file_sum_nni); - if (xfersum_type == CSUM_NONE) + if (xfer_sum_nni->num == CSUM_NONE) whole_file = 1; /* Snag the checksum name for both write_batch's option output & the following debug output. */ - if (valid_checksums.negotiated_name) - checksum_choice = valid_checksums.negotiated_name; + if (valid_checksums.negotiated_nni) + checksum_choice = valid_checksums.negotiated_nni->name; else if (checksum_choice == NULL) - checksum_choice = checksum_name(xfersum_type); + checksum_choice = xfer_sum_nni->name; if (final_call && DEBUG_GTE(NSTR, am_server ? 3 : 1)) { rprintf(FINFO, "%s%s checksum: %s\n", am_server ? "Server" : "Client", - valid_checksums.negotiated_name ? " negotiated" : "", + valid_checksums.negotiated_nni ? " negotiated" : "", checksum_choice); } } @@ -211,7 +272,22 @@ uint32 get_checksum1(char *buf1, int32 len) void get_checksum2(char *buf, int32 len, char *sum) { - switch (xfersum_type) { +#ifdef USE_OPENSSL + if (xfer_sum_evp_md) { + static EVP_MD_CTX *evp = NULL; + uchar seedbuf[4]; + if (!evp && !(evp = EVP_MD_CTX_create())) + out_of_memory("get_checksum2"); + EVP_DigestInit_ex(evp, xfer_sum_evp_md, NULL); + if (checksum_seed) { + SIVALu(seedbuf, 0, checksum_seed); + EVP_DigestUpdate(evp, seedbuf, 4); + } + EVP_DigestUpdate(evp, (uchar *)buf, len); + EVP_DigestFinal_ex(evp, (uchar *)sum, NULL); + } else +#endif + switch (xfer_sum_nni->num) { #ifdef SUPPORT_XXHASH case CSUM_XXH64: SIVAL64(sum, 0, XXH64(buf, len, checksum_seed)); @@ -229,7 +305,7 @@ void get_checksum2(char *buf, int32 len, char *sum) } #endif case CSUM_MD5: { - md5_context m5; + md_context m5; uchar seedbuf[4]; md5_begin(&m5); if (proper_seed_order) { @@ -249,20 +325,6 @@ void get_checksum2(char *buf, int32 len, char *sum) break; } case CSUM_MD4: -#ifdef USE_OPENSSL - { - MD4_CTX m4; - MD4_Init(&m4); - MD4_Update(&m4, (uchar *)buf, len); - if (checksum_seed) { - uchar seedbuf[4]; - SIVALu(seedbuf, 0, checksum_seed); - MD4_Update(&m4, seedbuf, 4); - } - MD4_Final((uchar *)sum, &m4); - break; - } -#endif case CSUM_MD4_OLD: case CSUM_MD4_BUSTED: case CSUM_MD4_ARCHAIC: { @@ -295,7 +357,7 @@ void get_checksum2(char *buf, int32 len, char *sum) * are multiples of 64. This is fixed by calling mdfour_update() * even when there are no more bytes. */ - if (len - i > 0 || xfersum_type > CSUM_MD4_BUSTED) + if (len - i > 0 || xfer_sum_nni->num > CSUM_MD4_BUSTED) mdfour_update(&m, (uchar *)(buf1+i), len-i); mdfour_result(&m, (uchar *)sum); @@ -313,15 +375,33 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum) int32 remainder; int fd; - memset(sum, 0, MAX_DIGEST_LEN); - fd = do_open(fname, O_RDONLY, 0); - if (fd == -1) + if (fd == -1) { + memset(sum, 0, file_sum_len); return; + } buf = map_file(fd, len, MAX_MAP_SIZE, CHUNK_SIZE); - switch (checksum_type) { +#ifdef USE_OPENSSL + if (file_sum_evp_md) { + static EVP_MD_CTX *evp = NULL; + if (!evp && !(evp = EVP_MD_CTX_create())) + out_of_memory("file_checksum"); + + EVP_DigestInit_ex(evp, file_sum_evp_md, NULL); + + for (i = 0; i + CHUNK_SIZE <= len; i += CHUNK_SIZE) + EVP_DigestUpdate(evp, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE); + + remainder = (int32)(len - i); + if (remainder > 0) + EVP_DigestUpdate(evp, (uchar *)map_ptr(buf, i, remainder), remainder); + + EVP_DigestFinal_ex(evp, (uchar *)sum, NULL); + } else +#endif + switch (file_sum_nni->num) { #ifdef SUPPORT_XXHASH case CSUM_XXH64: { static XXH64_state_t* state = NULL; @@ -381,7 +461,7 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum) } #endif case CSUM_MD5: { - md5_context m5; + md_context m5; md5_begin(&m5); @@ -396,23 +476,6 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum) break; } case CSUM_MD4: -#ifdef USE_OPENSSL - { - MD4_CTX m4; - - MD4_Init(&m4); - - for (i = 0; i + CHUNK_SIZE <= len; i += CHUNK_SIZE) - MD4_Update(&m4, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE); - - remainder = (int32)(len - i); - if (remainder > 0) - MD4_Update(&m4, (uchar *)map_ptr(buf, i, remainder), remainder); - - MD4_Final((uchar *)sum, &m4); - break; - } -#endif case CSUM_MD4_OLD: case CSUM_MD4_BUSTED: case CSUM_MD4_ARCHAIC: { @@ -428,7 +491,7 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum) * are multiples of 64. This is fixed by calling mdfour_update() * even when there are no more bytes. */ remainder = (int32)(len - i); - if (remainder > 0 || checksum_type > CSUM_MD4_BUSTED) + if (remainder > 0 || file_sum_nni->num > CSUM_MD4_BUSTED) mdfour_update(&m, (uchar *)map_ptr(buf, i, remainder), remainder); mdfour_result(&m, (uchar *)sum); @@ -436,7 +499,7 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum) } default: rprintf(FERROR, "Invalid checksum-choice for --checksum: %s (%d)\n", - checksum_name(checksum_type), checksum_type); + file_sum_nni->name, file_sum_nni->num); exit_cleanup(RERR_UNSUPPORTED); } @@ -445,30 +508,35 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum) } static int32 sumresidue; -static union { - md_context md; -#ifdef USE_OPENSSL - MD4_CTX m4; -#endif - md5_context m5; -} ctx; +static md_context ctx_md; #ifdef SUPPORT_XXHASH static XXH64_state_t* xxh64_state; #endif #ifdef SUPPORT_XXH3 static XXH3_state_t* xxh3_state; #endif -static int cursum_type; +static struct name_num_item *cur_sum_nni; +static const EVP_MD *cur_sum_evp_md; +int cur_sum_len; -void sum_init(int csum_type, int seed) +int sum_init(struct name_num_item *nni, int seed) { char s[4]; - if (csum_type < 0) - csum_type = parse_csum_name(NULL, 0); - cursum_type = csum_type; + if (!nni) + nni = parse_csum_name(NULL, 0); + cur_sum_nni = nni; + cur_sum_len = csum_len_for_type(nni->num, 0); + cur_sum_evp_md = csum_evp_md(nni); - switch (csum_type) { +#ifdef USE_OPENSSL + if (cur_sum_evp_md) { + if (!ctx_evp && !(ctx_evp = EVP_MD_CTX_create())) + out_of_memory("file_checksum"); + EVP_DigestInit_ex(ctx_evp, cur_sum_evp_md, NULL); + } else +#endif + switch (cur_sum_nni->num) { #ifdef SUPPORT_XXHASH case CSUM_XXH64: if (!xxh64_state && !(xxh64_state = XXH64_createState())) @@ -489,20 +557,16 @@ void sum_init(int csum_type, int seed) break; #endif case CSUM_MD5: - md5_begin(&ctx.m5); + md5_begin(&ctx_md); break; case CSUM_MD4: -#ifdef USE_OPENSSL - MD4_Init(&ctx.m4); -#else - mdfour_begin(&ctx.md); + mdfour_begin(&ctx_md); sumresidue = 0; -#endif break; case CSUM_MD4_OLD: case CSUM_MD4_BUSTED: case CSUM_MD4_ARCHAIC: - mdfour_begin(&ctx.md); + mdfour_begin(&ctx_md); sumresidue = 0; SIVAL(s, 0, seed); sum_update(s, 4); @@ -512,6 +576,8 @@ void sum_init(int csum_type, int seed) default: /* paranoia to prevent missing case values */ exit_cleanup(RERR_UNSUPPORTED); } + + return cur_sum_len; } /** @@ -524,7 +590,12 @@ void sum_init(int csum_type, int seed) **/ void sum_update(const char *p, int32 len) { - switch (cursum_type) { +#ifdef USE_OPENSSL + if (cur_sum_evp_md) { + EVP_DigestUpdate(ctx_evp, (uchar *)p, len); + } else +#endif + switch (cur_sum_nni->num) { #ifdef SUPPORT_XXHASH case CSUM_XXH64: XXH64_update(xxh64_state, p, len); @@ -539,39 +610,35 @@ void sum_update(const char *p, int32 len) break; #endif case CSUM_MD5: - md5_update(&ctx.m5, (uchar *)p, len); + md5_update(&ctx_md, (uchar *)p, len); break; case CSUM_MD4: -#ifdef USE_OPENSSL - MD4_Update(&ctx.m4, (uchar *)p, len); - break; -#endif case CSUM_MD4_OLD: case CSUM_MD4_BUSTED: case CSUM_MD4_ARCHAIC: if (len + sumresidue < CSUM_CHUNK) { - memcpy(ctx.md.buffer + sumresidue, p, len); + memcpy(ctx_md.buffer + sumresidue, p, len); sumresidue += len; break; } if (sumresidue) { int32 i = CSUM_CHUNK - sumresidue; - memcpy(ctx.md.buffer + sumresidue, p, i); - mdfour_update(&ctx.md, (uchar *)ctx.md.buffer, CSUM_CHUNK); + memcpy(ctx_md.buffer + sumresidue, p, i); + mdfour_update(&ctx_md, (uchar *)ctx_md.buffer, CSUM_CHUNK); len -= i; p += i; } while (len >= CSUM_CHUNK) { - mdfour_update(&ctx.md, (uchar *)p, CSUM_CHUNK); + mdfour_update(&ctx_md, (uchar *)p, CSUM_CHUNK); len -= CSUM_CHUNK; p += CSUM_CHUNK; } sumresidue = len; if (sumresidue) - memcpy(ctx.md.buffer, p, sumresidue); + memcpy(ctx_md.buffer, p, sumresidue); break; case CSUM_NONE: break; @@ -580,13 +647,18 @@ void sum_update(const char *p, int32 len) } } -/* NOTE: all the callers of sum_end() pass in a pointer to a buffer that is - * MAX_DIGEST_LEN in size, so even if the csum-len is shorter than that (i.e. - * CSUM_MD4_ARCHAIC), we don't have to worry about limiting the data we write - * into the "sum" buffer. */ -int sum_end(char *sum) +/* The sum buffer only needs to be as long as the current checksum's digest + * len, not MAX_DIGEST_LEN. Note that for CSUM_MD4_ARCHAIC that is the full + * MD4_DIGEST_LEN even if the file-list code is going to ignore all but the + * first 2 bytes of it. */ +void sum_end(char *sum) { - switch (cursum_type) { +#ifdef USE_OPENSSL + if (cur_sum_evp_md) { + EVP_DigestFinal_ex(ctx_evp, (uchar *)sum, NULL); + } else +#endif + switch (cur_sum_nni->num) { #ifdef SUPPORT_XXHASH case CSUM_XXH64: SIVAL64(sum, 0, XXH64_digest(xxh64_state)); @@ -604,22 +676,18 @@ int sum_end(char *sum) } #endif case CSUM_MD5: - md5_result(&ctx.m5, (uchar *)sum); + md5_result(&ctx_md, (uchar *)sum); break; case CSUM_MD4: -#ifdef USE_OPENSSL - MD4_Final((uchar *)sum, &ctx.m4); - break; -#endif case CSUM_MD4_OLD: - mdfour_update(&ctx.md, (uchar *)ctx.md.buffer, sumresidue); - mdfour_result(&ctx.md, (uchar *)sum); + mdfour_update(&ctx_md, (uchar *)ctx_md.buffer, sumresidue); + mdfour_result(&ctx_md, (uchar *)sum); break; case CSUM_MD4_BUSTED: case CSUM_MD4_ARCHAIC: if (sumresidue) - mdfour_update(&ctx.md, (uchar *)ctx.md.buffer, sumresidue); - mdfour_result(&ctx.md, (uchar *)sum); + mdfour_update(&ctx_md, (uchar *)ctx_md.buffer, sumresidue); + mdfour_result(&ctx_md, (uchar *)sum); break; case CSUM_NONE: *sum = '\0'; @@ -627,34 +695,72 @@ int sum_end(char *sum) default: /* paranoia to prevent missing case values */ exit_cleanup(RERR_UNSUPPORTED); } - - return csum_len_for_type(cursum_type, 0); } -void init_checksum_choices() +#if defined SUPPORT_XXH3 || defined USE_OPENSSL +static void verify_digest(struct name_num_item *nni, BOOL check_auth_list) { #ifdef SUPPORT_XXH3 - char buf[32816]; - int j; - for (j = 0; j < (int)sizeof buf; j++) { - buf[j] = ' ' + (j % 96); + static int xxh3_result = 0; +#endif +#ifdef USE_OPENSSL + static int prior_num = 0, prior_flags = 0, prior_result = 0; +#endif + +#ifdef SUPPORT_XXH3 + if (nni->num == CSUM_XXH3_64 || nni->num == CSUM_XXH3_128) { + if (!xxh3_result) { + char buf[32816]; + int j; + for (j = 0; j < (int)sizeof buf; j++) + buf[j] = ' ' + (j % 96); + sum_init(nni, 0); + sum_update(buf, 32816); + sum_update(buf, 31152); + sum_update(buf, 32474); + sum_update(buf, 9322); + xxh3_result = XXH3_64bits_digest(xxh3_state) != 0xadbcf16d4678d1de ? -1 : 1; + } + if (xxh3_result < 0) + nni->num = CSUM_gone; + return; } - sum_init(CSUM_XXH3_64, 0); - sum_update(buf, 32816); - sum_update(buf, 31152); - sum_update(buf, 32474); - sum_update(buf, 9322); - if (XXH3_64bits_digest(xxh3_state) != 0xadbcf16d4678d1de) { - int t, f; - struct name_num_item *nni = valid_checksums.list; - for (t = f = 0; nni[f].name; f++) { - if (nni[f].num == CSUM_XXH3_64 || nni[f].num == CSUM_XXH3_128) - continue; - if (t != f) - nni[t++] = nni[f]; +#endif + +#ifdef USE_OPENSSL + if (BITS_SETnUNSET(nni->flags, NNI_EVP, NNI_BUILTIN|NNI_EVP_OK)) { + if (nni->num == prior_num && nni->flags == prior_flags) { + nni->flags = prior_result; + if (!(nni->flags & NNI_EVP)) + nni->num = CSUM_gone; + } else { + prior_num = nni->num; + prior_flags = nni->flags; + if (!csum_evp_md(nni)) + nni->num = CSUM_gone; + prior_result = nni->flags; + if (check_auth_list && (nni = get_nni_by_num(&valid_auth_checksums, prior_num)) != NULL) + verify_digest(nni, False); } - nni[t].name = NULL; } #endif +} +#endif + +void init_checksum_choices() +{ + struct name_num_item *nni; + + if (initialized_choices) + return; + +#if defined SUPPORT_XXH3 || defined USE_OPENSSL + for (nni = valid_checksums.list; nni->name; nni++) + verify_digest(nni, True); + + for (nni = valid_auth_checksums.list; nni->name; nni++) + verify_digest(nni, False); +#endif + initialized_choices = 1; } diff --git a/clientserver.c b/clientserver.c index ca897ff1..7436d01e 100644 --- a/clientserver.c +++ b/clientserver.c @@ -67,6 +67,7 @@ extern uid_t our_uid; extern gid_t our_gid; char *auth_user; +char *daemon_auth_choices; int read_only = 0; int module_id = -1; int pid_file_fd = -1; @@ -149,13 +150,9 @@ int start_socket_client(char *host, int remote_argc, char *remote_argv[], static int exchange_protocols(int f_in, int f_out, char *buf, size_t bufsiz, int am_client) { int remote_sub = -1; -#if SUBPROTOCOL_VERSION != 0 - int our_sub = protocol_version < PROTOCOL_VERSION ? 0 : SUBPROTOCOL_VERSION; -#else - int our_sub = 0; -#endif + int our_sub = get_subprotocol_version(); - io_printf(f_out, "@RSYNCD: %d.%d\n", protocol_version, our_sub); + output_daemon_greeting(f_out, am_client); if (!am_client) { char *motd = lp_motd_file(); if (motd && *motd) { @@ -197,6 +194,14 @@ static int exchange_protocols(int f_in, int f_out, char *buf, size_t bufsiz, int remote_sub = 0; } + daemon_auth_choices = strchr(buf + 9, ' '); + if (daemon_auth_choices) { + char *cp; + daemon_auth_choices = strdup(daemon_auth_choices + 1); + if ((cp = strchr(daemon_auth_choices, '\n')) != NULL) + *cp = '\0'; + } + if (protocol_version > remote_protocol) { protocol_version = remote_protocol; if (remote_sub) @@ -429,7 +434,7 @@ static int read_arg_from_pipe(int fd, char *buf, int limit) } #endif -static void set_env_str(const char *var, const char *str) +void set_env_str(const char *var, const char *str) { #ifdef HAVE_SETENV if (setenv(var, str, 1) < 0) diff --git a/compat.c b/compat.c index 622910eb..a8a6afe8 100644 --- a/compat.c +++ b/compat.c @@ -60,13 +60,16 @@ extern char *files_from; extern char *filesfrom_host; extern const char *checksum_choice; extern const char *compress_choice; +extern char *daemon_auth_choices; extern filter_rule_list filter_list; extern int need_unsorted_flist; #ifdef ICONV_OPTION extern iconv_t ic_send, ic_recv; extern char *iconv_opt; #endif -extern struct name_num_obj valid_checksums; +extern struct name_num_obj valid_checksums, valid_auth_checksums; + +extern struct name_num_item *xfer_sum_nni; int remote_protocol = 0; int file_extra_cnt = 0; /* count of file-list extras that everyone gets */ @@ -79,6 +82,9 @@ int inplace_partial = 0; int do_negotiated_strings = 0; int xmit_id0_names = 0; +struct name_num_item *xattr_sum_nni; +int xattr_sum_len = 0; + /* These index values are for the file-list's extra-attribute array. */ int pathname_ndx, depth_ndx, atimes_ndx, crtimes_ndx, uid_ndx, gid_ndx, acls_ndx, xattrs_ndx, unsort_ndx; @@ -93,19 +99,19 @@ int filesfrom_convert = 0; struct name_num_item valid_compressions_items[] = { #ifdef SUPPORT_ZSTD - { CPRES_ZSTD, "zstd", NULL }, + { CPRES_ZSTD, 0, "zstd", NULL }, #endif #ifdef SUPPORT_LZ4 - { CPRES_LZ4, "lz4", NULL }, + { CPRES_LZ4, 0, "lz4", NULL }, #endif - { CPRES_ZLIBX, "zlibx", NULL }, - { CPRES_ZLIB, "zlib", NULL }, - { CPRES_NONE, "none", NULL }, - { 0, NULL, NULL } + { CPRES_ZLIBX, 0, "zlibx", NULL }, + { CPRES_ZLIB, 0, "zlib", NULL }, + { CPRES_NONE, 0, "none", NULL }, + { 0, 0, NULL, NULL } }; struct name_num_obj valid_compressions = { - "compress", NULL, NULL, 0, 0, valid_compressions_items + "compress", NULL, 0, 0, valid_compressions_items }; #define CF_INC_RECURSE (1<<0) @@ -127,11 +133,7 @@ static void check_sub_protocol(void) { char *dot; int their_protocol, their_sub; -#if SUBPROTOCOL_VERSION != 0 - int our_sub = protocol_version < PROTOCOL_VERSION ? 0 : SUBPROTOCOL_VERSION; -#else - int our_sub = 0; -#endif + int our_sub = get_subprotocol_version(); /* client_info starts with VER.SUB string if client is a pre-release. */ if (!(their_protocol = atoi(client_info)) @@ -178,8 +180,8 @@ void set_allow_inc_recurse(void) void parse_compress_choice(int final_call) { - if (valid_compressions.negotiated_name) - do_compression = valid_compressions.negotiated_num; + if (valid_compressions.negotiated_nni) + do_compression = valid_compressions.negotiated_nni->num; else if (compress_choice) { struct name_num_item *nni = get_nni_by_name(&valid_compressions, compress_choice, -1); if (!nni) { @@ -201,8 +203,8 @@ void parse_compress_choice(int final_call) compress_choice = NULL; /* Snag the compression name for both write_batch's option output & the following debug output. */ - if (valid_compressions.negotiated_name) - compress_choice = valid_compressions.negotiated_name; + if (valid_compressions.negotiated_nni) + compress_choice = valid_compressions.negotiated_nni->name; else if (compress_choice == NULL) { struct name_num_item *nni = get_nni_by_num(&valid_compressions, do_compression); compress_choice = nni ? nni->name : "UNKNOWN"; @@ -212,7 +214,7 @@ void parse_compress_choice(int final_call) && (do_compression != CPRES_NONE || do_compression_level != CLVL_NOT_SPECIFIED)) { rprintf(FINFO, "%s%s compress: %s (level %d)\n", am_server ? "Server" : "Client", - valid_compressions.negotiated_name ? " negotiated" : "", + valid_compressions.negotiated_nni ? " negotiated" : "", compress_choice, do_compression_level); } } @@ -225,6 +227,8 @@ struct name_num_item *get_nni_by_name(struct name_num_obj *nno, const char *name len = strlen(name); for (nni = nno->list; nni->name; nni++) { + if (nni->num == CSUM_gone) + continue; if (strncasecmp(name, nni->name, len) == 0 && nni->name[len] == '\0') return nni; } @@ -259,10 +263,12 @@ static void init_nno_saw(struct name_num_obj *nno, int val) if (!nno->saw) { nno->saw = new_array0(uchar, nno->saw_len); - /* We'll take this opportunity to make sure that the main_name values are set right. */ + /* We'll take this opportunity to set the main_nni values for duplicates. */ for (cnt = 1, nni = nno->list; nni->name; nni++, cnt++) { + if (nni->num == CSUM_gone) + continue; if (nno->saw[nni->num]) - nni->main_name = nno->list[nno->saw[nni->num]-1].name; + nni->main_nni = &nno->list[nno->saw[nni->num]-1]; else nno->saw[nni->num] = cnt; } @@ -288,8 +294,8 @@ static int parse_nni_str(struct name_num_obj *nno, const char *from, char *tobuf struct name_num_item *nni = get_nni_by_name(nno, tok, to - tok); if (nni && !nno->saw[nni->num]) { nno->saw[nni->num] = ++cnt; - if (nni->main_name) { - to = tok + strlcpy(tok, nni->main_name, tobuf_len - (tok - tobuf)); + if (nni->main_nni) { + to = tok + strlcpy(tok, nni->main_nni->name, tobuf_len - (tok - tobuf)); if (to - tobuf >= tobuf_len) { to = tok - 1; break; @@ -323,13 +329,44 @@ static int parse_nni_str(struct name_num_obj *nno, const char *from, char *tobuf return to - tobuf; } +static int parse_negotiate_str(struct name_num_obj *nno, char *tmpbuf) +{ + struct name_num_item *nni, *ret = NULL; + int best = nno->saw_len; /* We want best == 1 from the client list, so start with a big number. */ + char *space, *tok = tmpbuf; + while (tok) { + while (*tok == ' ') tok++; /* Should be unneeded... */ + if (!*tok) + break; + if ((space = strchr(tok, ' ')) != NULL) + *space = '\0'; + nni = get_nni_by_name(nno, tok, -1); + if (space) { + *space = ' '; + tok = space + 1; + } else + tok = NULL; + if (!nni || !nno->saw[nni->num] || best <= nno->saw[nni->num]) + continue; + ret = nni; + best = nno->saw[nni->num]; + if (best == 1 || am_server) /* The server side stops at the first acceptable client choice */ + break; + } + if (ret) { + free(nno->saw); + nno->saw = NULL; + nno->negotiated_nni = ret->main_nni ? ret->main_nni : ret; + return 1; + } + return 0; +} + /* This routine is always called with a tmpbuf of MAX_NSTR_STRLEN length, but the * buffer may be pre-populated with a "len" length string to use OR a len of -1 * to tell us to read a string from the fd. */ static void recv_negotiate_str(int f_in, struct name_num_obj *nno, char *tmpbuf, int len) { - struct name_num_item *ret = NULL; - if (len < 0) len = read_vstring(f_in, tmpbuf, MAX_NSTR_STRLEN); @@ -340,37 +377,8 @@ static void recv_negotiate_str(int f_in, struct name_num_obj *nno, char *tmpbuf, rprintf(FINFO, "Server %s list (on client): %s\n", nno->type, tmpbuf); } - if (len > 0) { - struct name_num_item *nni; - int best = nno->saw_len; /* We want best == 1 from the client list, so start with a big number. */ - char *space, *tok = tmpbuf; - while (tok) { - while (*tok == ' ') tok++; /* Should be unneeded... */ - if (!*tok) - break; - if ((space = strchr(tok, ' ')) != NULL) - *space = '\0'; - nni = get_nni_by_name(nno, tok, -1); - if (space) { - *space = ' '; - tok = space + 1; - } else - tok = NULL; - if (!nni || !nno->saw[nni->num] || best <= nno->saw[nni->num]) - continue; - ret = nni; - best = nno->saw[nni->num]; - if (best == 1 || am_server) /* The server side stops at the first acceptable client choice */ - break; - } - if (ret) { - free(nno->saw); - nno->saw = NULL; - nno->negotiated_name = ret->main_name ? ret->main_name : ret->name; - nno->negotiated_num = ret->num; - return; - } - } + if (len > 0 && parse_negotiate_str(nno, tmpbuf)) + return; if (!am_server || !do_negotiated_strings) { char *cp = tmpbuf; @@ -466,8 +474,10 @@ int get_default_nno_list(struct name_num_obj *nno, char *to_buf, int to_buf_len, init_nno_saw(nno, 0); for (nni = nno->list, len = 0; nni->name; nni++) { - if (nni->main_name) { - if (!dup_markup) + if (nni->num == CSUM_gone) + continue; + if (nni->main_nni) { + if (!dup_markup || nni->main_nni->num == CSUM_gone) continue; delim = dup_markup; } @@ -556,7 +566,7 @@ static void negotiate_the_strings(int f_in, int f_out) /* 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; + valid_checksums.negotiated_nni = valid_compressions.negotiated_nni = NULL; } void setup_protocol(int f_out,int f_in) @@ -805,11 +815,73 @@ void setup_protocol(int f_out,int f_in) checksum_seed = read_int(f_in); } - parse_checksum_choice(1); /* Sets checksum_type & xfersum_type */ + parse_checksum_choice(1); /* Sets file_sum_nni & xfer_sum_nni */ parse_compress_choice(1); /* Sets do_compression */ + /* TODO in the future allow this algorithm to be chosen somehow, but it can't get too + * long or the size starts to cause a problem in the xattr abbrev/non-abbrev code. */ + xattr_sum_nni = parse_csum_name(NULL, 0); + xattr_sum_len = csum_len_for_type(xattr_sum_nni->num, 0); + if (write_batch && !am_server) write_batch_shell_file(); init_flist(); } + +void output_daemon_greeting(int f_out, int am_client) +{ + char tmpbuf[MAX_NSTR_STRLEN]; + int our_sub = get_subprotocol_version(); + + get_default_nno_list(&valid_auth_checksums, tmpbuf, MAX_NSTR_STRLEN, '\0'); + + io_printf(f_out, "@RSYNCD: %d.%d %s\n", protocol_version, our_sub, tmpbuf); + + if (am_client && DEBUG_GTE(NSTR, 2)) + rprintf(FINFO, "Client %s list (on client): %s\n", valid_auth_checksums.type, tmpbuf); +} + +void negotiate_daemon_auth(int f_out, int am_client) +{ + char tmpbuf[MAX_NSTR_STRLEN]; + int save_am_server = am_server; + int md4_is_old = 0; + + if (!am_client) + am_server = 1; + + if (daemon_auth_choices) + strlcpy(tmpbuf, daemon_auth_choices, MAX_NSTR_STRLEN); + else { + strlcpy(tmpbuf, protocol_version >= 30 ? "md5" : "md4", MAX_NSTR_STRLEN); + md4_is_old = 1; + } + + if (am_client) { + recv_negotiate_str(-1, &valid_auth_checksums, tmpbuf, strlen(tmpbuf)); + if (DEBUG_GTE(NSTR, 1)) { + rprintf(FINFO, "Client negotiated %s: %s\n", valid_auth_checksums.type, + valid_auth_checksums.negotiated_nni->name); + } + } else { + if (!parse_negotiate_str(&valid_auth_checksums, tmpbuf)) { + get_default_nno_list(&valid_auth_checksums, tmpbuf, MAX_NSTR_STRLEN, '\0'); + io_printf(f_out, "@ERROR: your client does not support one of our daemon-auth checksums: %s\n", + tmpbuf); + exit_cleanup(RERR_UNSUPPORTED); + } + } + am_server = save_am_server; + if (md4_is_old && valid_auth_checksums.negotiated_nni->num == CSUM_MD4) + valid_auth_checksums.negotiated_nni->num = CSUM_MD4_OLD; +} + +int get_subprotocol_version() +{ +#if SUBPROTOCOL_VERSION != 0 + return protocol_version < PROTOCOL_VERSION ? 0 : SUBPROTOCOL_VERSION; +#else + return 0; +#endif +} diff --git a/configure.ac b/configure.ac index b6de4eb3..7fa6ff73 100644 --- a/configure.ac +++ b/configure.ac @@ -136,6 +136,16 @@ if test x"$GCC" = x"yes"; then CFLAGS="$CFLAGS -Wall -W" fi +AC_ARG_WITH(openssl-conf, + AS_HELP_STRING([--with-openssl-conf=PATH],[set default OPENSSL_CONF path for rsync])) +case "$with_openssl_conf" in + *[^-/a-zA-Z0-9.,=@+_]*) AC_MSG_ERROR([Invalid path given to --with-openssl-conf]) ;; + /*) CFLAGS="$CFLAGS -DSET_OPENSSL_CONF=$with_openssl_conf" ;; + no|'') ;; + yes) AC_MSG_ERROR([No path given to --with-openssl-conf]) ;; + *) AC_MSG_ERROR([Non absolute path given to --with-openssl-conf]) ;; +esac + AC_ARG_WITH(rrsync, AS_HELP_STRING([--with-rrsync],[also install the rrsync script and its manpage])) if test x"$with_rrsync" != x"yes"; then diff --git a/flist.c b/flist.c index 0e6bf782..0313db54 100644 --- a/flist.c +++ b/flist.c @@ -33,7 +33,6 @@ extern int am_sender; extern int am_generator; extern int inc_recurse; extern int always_checksum; -extern int checksum_type; extern int module_id; extern int ignore_errors; extern int numeric_ids; @@ -80,6 +79,8 @@ extern struct stats stats; extern char *filesfrom_host; extern char *usermap, *groupmap; +extern struct name_num_item *file_sum_nni; + extern char curr_dir[MAXPATHLEN]; extern struct chmod_mode_struct *chmod_modes; @@ -145,7 +146,8 @@ void init_flist(void) rprintf(FINFO, "FILE_STRUCT_LEN=%d, EXTRA_LEN=%d\n", (int)FILE_STRUCT_LEN, (int)EXTRA_LEN); } - flist_csum_len = csum_len_for_type(checksum_type, 1); + /* Note that this isn't identical to file_sum_len in the case of CSUM_MD4_ARCHAIC: */ + flist_csum_len = csum_len_for_type(file_sum_nni->num, 1); show_filelist_progress = INFO_GTE(FLIST, 1) && xfer_dirs && !am_server && !inc_recurse; } diff --git a/lib/md-defines.h b/lib/md-defines.h index 1410af5f..5adf19f8 100644 --- a/lib/md-defines.h +++ b/lib/md-defines.h @@ -6,6 +6,7 @@ #define CSUM_CHUNK 64 +#define CSUM_gone -1 #define CSUM_NONE 0 #define CSUM_MD4_ARCHAIC 1 #define CSUM_MD4_BUSTED 2 diff --git a/lib/md5.c b/lib/md5.c index 2366339e..f36c5ba7 100644 --- a/lib/md5.c +++ b/lib/md5.c @@ -20,7 +20,6 @@ #include "rsync.h" -#if !defined USE_OPENSSL || USE_MD5_ASM /* { */ void md5_begin(md_context *ctx) { ctx->A = 0x67452301; @@ -224,7 +223,6 @@ void md5_result(md_context *ctx, uchar digest[MD5_DIGEST_LEN]) SIVALu(digest, 8, ctx->C); SIVALu(digest, 12, ctx->D); } -#endif /* } */ #ifdef TEST_MD5 /* { */ diff --git a/lib/mdigest.h b/lib/mdigest.h index f1d6d934..1e816901 100644 --- a/lib/mdigest.h +++ b/lib/mdigest.h @@ -1,8 +1,7 @@ /* The include file for both the MD4 and MD5 routines. */ #ifdef USE_OPENSSL -#include "openssl/md4.h" -#include "openssl/md5.h" +#include #endif #include "md-defines.h" @@ -17,14 +16,6 @@ void mdfour_begin(md_context *md); void mdfour_update(md_context *md, const uchar *in, uint32 length); void mdfour_result(md_context *md, uchar digest[MD4_DIGEST_LEN]); -#if defined USE_OPENSSL && !defined USE_MD5_ASM -#define md5_context MD5_CTX -#define md5_begin MD5_Init -#define md5_update MD5_Update -#define md5_result(cptr, digest) MD5_Final(digest, cptr) -#else -#define md5_context md_context void md5_begin(md_context *ctx); void md5_update(md_context *ctx, const uchar *input, uint32 length); void md5_result(md_context *ctx, uchar digest[MD5_DIGEST_LEN]); -#endif diff --git a/log.c b/log.c index 44344e2a..e4ba1cce 100644 --- a/log.c +++ b/log.c @@ -36,8 +36,6 @@ extern int protocol_version; extern int always_checksum; extern int preserve_mtimes; extern int msgs2stderr; -extern int xfersum_type; -extern int checksum_type; extern int stdout_format_has_i; extern int stdout_format_has_o_or_i; extern int logfile_format_has_i; @@ -62,6 +60,8 @@ extern unsigned int module_dirlen; extern char sender_file_sum[MAX_DIGEST_LEN]; extern const char undetermined_hostname[]; +extern struct name_num_item *xfer_sum_nni, *file_sum_nni; + static int log_initialised; static int logfile_was_closed; static FILE *logfile_fp; @@ -680,12 +680,12 @@ static void log_formatted(enum logcode code, const char *format, const char *op, n = NULL; if (S_ISREG(file->mode)) { if (always_checksum) - n = sum_as_hex(checksum_type, F_SUM(file), 1); + n = sum_as_hex(file_sum_nni->num, F_SUM(file), 1); else if (iflags & ITEM_TRANSFER) - n = sum_as_hex(xfersum_type, sender_file_sum, 0); + n = sum_as_hex(xfer_sum_nni->num, sender_file_sum, 0); } if (!n) { - int sum_len = csum_len_for_type(always_checksum ? checksum_type : xfersum_type, + int sum_len = csum_len_for_type(always_checksum ? file_sum_nni->num : xfer_sum_nni->num, always_checksum); memset(buf2, ' ', sum_len*2); buf2[sum_len*2] = '\0'; diff --git a/main.c b/main.c index 9ebfbea7..02b70079 100644 --- a/main.c +++ b/main.c @@ -1743,6 +1743,17 @@ int main(int argc,char *argv[]) unset_env_var("DISPLAY"); +#if defined USE_OPENSSL && defined SET_OPENSSL_CONF +#define TO_STR2(x) #x +#define TO_STR(x) TO_STR2(x) + /* ./configure --with-openssl-conf=/etc/ssl/openssl-rsync.cnf + * defines SET_OPENSSL_CONF as that unquoted pathname. */ + if (!getenv("OPENSSL_CONF")) /* Don't override it if it's already set. */ + set_env_str("OPENSSL_CONF", TO_STR(SET_OPENSSL_CONF)); +#undef TO_STR +#undef TO_STR2 +#endif + memset(&stats, 0, sizeof(stats)); /* Even a non-daemon runs needs the default config values to be set, e.g. diff --git a/match.c b/match.c index 9d5c9259..923ba1f9 100644 --- a/match.c +++ b/match.c @@ -24,7 +24,9 @@ extern int checksum_seed; extern int append_mode; -extern int xfersum_type; + +extern struct name_num_item *xfer_sum_nni; +extern int xfer_sum_len; int updating_basis_file; char sender_file_sum[MAX_DIGEST_LEN]; @@ -356,15 +358,13 @@ static void hash_search(int f,struct sum_struct *s, **/ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len) { - int sum_len; - last_match = 0; false_alarms = 0; hash_hits = 0; matches = 0; data_transfer = 0; - sum_init(xfersum_type, checksum_seed); + sum_init(xfer_sum_nni, checksum_seed); if (append_mode > 0) { if (append_mode == 2) { @@ -405,22 +405,22 @@ void match_sums(int f, struct sum_struct *s, struct map_struct *buf, OFF_T len) matched(f, s, buf, len, -1); } - sum_len = sum_end(sender_file_sum); + sum_end(sender_file_sum); /* If we had a read error, send a bad checksum. We use all bits * off as long as the checksum doesn't happen to be that, in * which case we turn the last 0 bit into a 1. */ if (buf && buf->status != 0) { int i; - for (i = 0; i < sum_len && sender_file_sum[i] == 0; i++) {} - memset(sender_file_sum, 0, sum_len); - if (i == sum_len) + for (i = 0; i < xfer_sum_len && sender_file_sum[i] == 0; i++) {} + memset(sender_file_sum, 0, xfer_sum_len); + if (i == xfer_sum_len) sender_file_sum[i-1]++; } if (DEBUG_GTE(DELTASUM, 2)) rprintf(FINFO,"sending file_sum\n"); - write_buf(f, sender_file_sum, sum_len); + write_buf(f, sender_file_sum, xfer_sum_len); if (DEBUG_GTE(DELTASUM, 2)) { rprintf(FINFO, "false_alarms=%d hash_hits=%d matches=%d\n", diff --git a/packaging/openssl-rsync.cnf b/packaging/openssl-rsync.cnf new file mode 100644 index 00000000..7432285d --- /dev/null +++ b/packaging/openssl-rsync.cnf @@ -0,0 +1,18 @@ +# This config file can be used with rsync to enable legacy digests +# (such as MD4) by using the OPENSSL_CONF environment variable. +# See rsync's configure --with-openssl-conf=/path/name option. + +openssl_conf = openssl_init + +[openssl_init] +providers = provider_sect + +[provider_sect] +default = default_sect +legacy = legacy_sect + +[default_sect] +activate = 1 + +[legacy_sect] +activate = 1 diff --git a/receiver.c b/receiver.c index 0f5d92d2..c9d7e01d 100644 --- a/receiver.c +++ b/receiver.c @@ -56,7 +56,6 @@ extern int inplace; extern int inplace_partial; extern int allowed_lull; extern int delay_updates; -extern int xfersum_type; extern BOOL want_progress_now; extern mode_t orig_umask; extern struct stats stats; @@ -68,6 +67,9 @@ extern struct file_list *cur_flist, *first_flist, *dir_flist; extern filter_rule_list daemon_filter_list; extern OFF_T preallocated_len; +extern struct name_num_item *xfer_sum_nni; +extern int xfer_sum_len; + static struct bitbag *delayed_bits = NULL; static int phase = 0, redoing = 0; static flist_ndx_list batch_redo_list; @@ -240,7 +242,6 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r, static char file_sum1[MAX_DIGEST_LEN]; struct map_struct *mapbuf; struct sum_struct sum; - int sum_len; int32 len; OFF_T total_size = F_LENGTH(file); OFF_T offset = 0; @@ -280,7 +281,7 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r, } else mapbuf = NULL; - sum_init(xfersum_type, checksum_seed); + sum_init(xfer_sum_nni, checksum_seed); if (append_mode > 0) { OFF_T j; @@ -393,7 +394,7 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r, if (INFO_GTE(PROGRESS, 1)) end_progress(total_size); - sum_len = sum_end(file_sum1); + sum_end(file_sum1); if (do_fsync && fd != -1 && fsync(fd) != 0) { rsyserr(FERROR, errno, "fsync failed on %s", full_fname(fname)); @@ -403,10 +404,10 @@ static int receive_data(int f_in, char *fname_r, int fd_r, OFF_T size_r, if (mapbuf) unmap_file(mapbuf); - read_buf(f_in, sender_file_sum, sum_len); + read_buf(f_in, sender_file_sum, xfer_sum_len); if (DEBUG_GTE(DELTASUM, 2)) rprintf(FINFO,"got file_sum\n"); - if (fd != -1 && memcmp(file_sum1, sender_file_sum, sum_len) != 0) + if (fd != -1 && memcmp(file_sum1, sender_file_sum, xfer_sum_len) != 0) return 0; return 1; } diff --git a/rsync.h b/rsync.h index e29c37c3..f0d3dd0b 100644 --- a/rsync.h +++ b/rsync.h @@ -826,6 +826,7 @@ extern int uid_ndx; extern int gid_ndx; extern int acls_ndx; extern int xattrs_ndx; +extern int file_sum_len; #ifdef USE_FLEXIBLE_ARRAY #define FILE_STRUCT_LEN (sizeof (struct file_struct)) @@ -836,7 +837,7 @@ extern int xattrs_ndx; #define DEV_EXTRA_CNT 2 #define DIRNODE_EXTRA_CNT 3 #define EXTRA64_CNT ((sizeof (union file_extras64) + EXTRA_LEN - 1) / EXTRA_LEN) -#define SUM_EXTRA_CNT ((MAX_DIGEST_LEN + EXTRA_LEN - 1) / EXTRA_LEN) +#define SUM_EXTRA_CNT ((file_sum_len + EXTRA_LEN - 1) / EXTRA_LEN) #define REQ_EXTRA(f,ndx) ((union file_extras*)(f) - (ndx)) #define OPT_EXTRA(f,bump) ((union file_extras*)(f) - file_extra_cnt - 1 - (bump)) @@ -1162,16 +1163,16 @@ typedef struct { #define NSTR_COMPRESS 1 struct name_num_item { - int num; - const char *name, *main_name; + int num, flags; + const char *name; + struct name_num_item *main_nni; }; struct name_num_obj { const char *type; - const char *negotiated_name; + struct name_num_item *negotiated_nni; uchar *saw; int saw_len; - int negotiated_num; struct name_num_item *list; }; diff --git a/usage.c b/usage.c index 048fd4cb..253f6660 100644 --- a/usage.c +++ b/usage.c @@ -23,8 +23,7 @@ #include "git-version.h" #include "default-cvsignore.h" -extern struct name_num_obj valid_checksums; -extern struct name_num_obj valid_compressions; +extern struct name_num_obj valid_checksums, valid_compressions, valid_auth_checksums; static char *istring(const char *fmt, int val) { @@ -205,6 +204,10 @@ void print_rsync_version(enum logcode f) get_default_nno_list(&valid_compressions, tmpbuf, sizeof tmpbuf, '('); rprintf(f, " %s\n", tmpbuf); + rprintf(f, "Daemon auth list:\n"); + get_default_nno_list(&valid_auth_checksums, tmpbuf, sizeof tmpbuf, '('); + rprintf(f, " %s\n", tmpbuf); + #ifdef MAINTAINER_MODE rprintf(f, "Panic Action: \"%s\"\n", get_panic_action()); #endif diff --git a/xattrs.c b/xattrs.c index 1f2bfacd..b9e79a1e 100644 --- a/xattrs.c +++ b/xattrs.c @@ -39,9 +39,13 @@ extern int preserve_specials; extern int checksum_seed; extern int saw_xattr_filter; +extern struct name_num_item *xattr_sum_nni; +extern int xattr_sum_len; + #define RSYNC_XAL_INITIAL 5 #define RSYNC_XAL_LIST_INITIAL 100 +#define MAX_XATTR_DIGEST_LEN MD5_DIGEST_LEN #define MAX_FULL_DATUM 32 #define HAS_PREFIX(str, prfx) (*(str) == *(prfx) && strncmp(str, prfx, sizeof (prfx) - 1) == 0) @@ -269,8 +273,8 @@ static int rsync_xal_get(const char *fname, item_list *xalp) if (datum_len > MAX_FULL_DATUM) { /* For large datums, we store a flag and a checksum. */ - name_offset = 1 + MAX_DIGEST_LEN; - sum_init(-1, checksum_seed); + name_offset = 1 + MAX_XATTR_DIGEST_LEN; + sum_init(xattr_sum_nni, checksum_seed); sum_update(ptr, datum_len); free(ptr); @@ -382,7 +386,7 @@ static int64 xattr_lookup_hash(const item_list *xalp) for (i = 0; i < xalp->count; i++) { key += hashlittle(rxas[i].name, rxas[i].name_len); if (rxas[i].datum_len > MAX_FULL_DATUM) - key += hashlittle(rxas[i].datum, MAX_DIGEST_LEN); + key += hashlittle(rxas[i].datum, xattr_sum_len); else key += hashlittle(rxas[i].datum, rxas[i].datum_len); } @@ -435,7 +439,7 @@ static int find_matching_xattr(const item_list *xalp) if (rxas1[j].datum_len > MAX_FULL_DATUM) { if (memcmp(rxas1[j].datum + 1, rxas2[j].datum + 1, - MAX_DIGEST_LEN) != 0) + xattr_sum_len) != 0) break; } else { if (memcmp(rxas1[j].datum, rxas2[j].datum, @@ -535,7 +539,7 @@ int send_xattr(int f, stat_x *sxp) #endif write_buf(f, name, name_len); if (rxa->datum_len > MAX_FULL_DATUM) - write_buf(f, rxa->datum + 1, MAX_DIGEST_LEN); + write_buf(f, rxa->datum + 1, xattr_sum_len); else write_bigbuf(f, rxa->datum, rxa->datum_len); } @@ -588,7 +592,7 @@ int xattr_diff(struct file_struct *file, stat_x *sxp, int find_all) else if (snd_rxa->datum_len > MAX_FULL_DATUM) { same = cmp == 0 && snd_rxa->datum_len == rec_rxa->datum_len && memcmp(snd_rxa->datum + 1, rec_rxa->datum + 1, - MAX_DIGEST_LEN) == 0; + xattr_sum_len) == 0; /* Flag unrequested items that we need. */ if (!same && find_all && snd_rxa->datum[0] == XSTATE_ABBREV) snd_rxa->datum[0] = XSTATE_TODO; @@ -797,7 +801,7 @@ void receive_xattr(int f, struct file_struct *file) rsync_xa *rxa; size_t name_len = read_varint(f); size_t datum_len = read_varint(f); - size_t dget_len = datum_len > MAX_FULL_DATUM ? 1 + MAX_DIGEST_LEN : datum_len; + size_t dget_len = datum_len > MAX_FULL_DATUM ? 1 + (size_t)xattr_sum_len : datum_len; size_t extra_len = MIGHT_NEED_RPRE ? RPRE_LEN : 0; if (SIZE_MAX - dget_len < extra_len || SIZE_MAX - dget_len - extra_len < name_len) overflow_exit("receive_xattr"); @@ -812,7 +816,7 @@ void receive_xattr(int f, struct file_struct *file) read_buf(f, ptr, dget_len); else { *ptr = XSTATE_ABBREV; - read_buf(f, ptr + 1, MAX_DIGEST_LEN); + read_buf(f, ptr + 1, xattr_sum_len); } if (saw_xattr_filter) { @@ -943,7 +947,7 @@ static int rsync_xal_set(const char *fname, item_list *xalp, rsync_xa *rxas = xalp->items; ssize_t list_len; size_t i, len; - char *name, *ptr, sum[MAX_DIGEST_LEN]; + char *name, *ptr, sum[MAX_XATTR_DIGEST_LEN]; #ifdef HAVE_LINUX_XATTRS int user_only = am_root <= 0; #endif @@ -958,7 +962,6 @@ static int rsync_xal_set(const char *fname, item_list *xalp, name = rxas[i].name; if (XATTR_ABBREV(rxas[i])) { - int sum_len; /* See if the fnamecmp version is identical. */ len = name_len = rxas[i].name_len; if ((ptr = get_xattr_data(fnamecmp, name, &len, 1)) == NULL) { @@ -975,10 +978,10 @@ static int rsync_xal_set(const char *fname, item_list *xalp, goto still_abbrev; } - sum_init(-1, checksum_seed); + sum_init(xattr_sum_nni, checksum_seed); sum_update(ptr, len); - sum_len = sum_end(sum); - if (memcmp(sum, rxas[i].datum + 1, sum_len) != 0) { + sum_end(sum); + if (memcmp(sum, rxas[i].datum + 1, xattr_sum_len) != 0) { free(ptr); goto still_abbrev; } -- 2.47.2