if (!users || !*users)
return "";
-+ negotiate_daemon_auth(f_out);
++ negotiate_daemon_auth(f_out, 0);
gen_challenge(addr, challenge);
io_printf(f_out, "%s%s\n", leader, challenge);
-@@ -368,6 +370,7 @@ void auth_client(int fd, const char *user, const char *challenge)
- if (!pass)
- pass = "";
+@@ -350,6 +352,7 @@ void auth_client(int fd, const char *user, const char *challenge)
-+ negotiate_daemon_auth(-1);
- generate_hash(pass, challenge, pass2);
- io_printf(fd, "%s %s\n", user, pass2);
- }
+ 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
--- a/checksum.c
+++ b/checksum.c
+ int our_sub = get_subprotocol_version();
- io_printf(f_out, "@RSYNCD: %d.%d\n", protocol_version, our_sub);
-+ output_daemon_greeting(f_out);
++ output_daemon_greeting(f_out, am_client);
if (!am_client) {
char *motd = lp_motd_file();
if (motd && *motd) {
/* 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;
-@@ -115,6 +119,7 @@ struct name_num_obj valid_compressions = {
- #define CF_INPLACE_PARTIAL_DIR (1<<6)
- #define CF_VARINT_FLIST_FLAGS (1<<7)
- #define CF_ID0_NAMES (1<<8)
-+#define CF_XATTR_SUM_CHOICE (1<<9)
-
- static const char *client_info;
-
-@@ -125,11 +130,7 @@ static void check_sub_protocol(void)
+@@ -125,11 +129,7 @@ static void check_sub_protocol(void)
{
char *dot;
int their_protocol, their_sub;
/* client_info starts with VER.SUB string if client is a pre-release. */
if (!(their_protocol = atoi(client_info))
-@@ -321,13 +322,45 @@ static int parse_nni_str(struct name_num_obj *nno, const char *from, char *tobuf
+@@ -321,13 +321,45 @@ static int parse_nni_str(struct name_num_obj *nno, const char *from, char *tobuf
return to - tobuf;
}
if (len < 0)
len = read_vstring(f_in, tmpbuf, MAX_NSTR_STRLEN);
-@@ -338,37 +371,8 @@ static void recv_negotiate_str(int f_in, struct name_num_obj *nno, char *tmpbuf,
+@@ -338,37 +370,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 (!am_server || !do_negotiated_strings) {
char *cp = tmpbuf;
-@@ -716,6 +720,8 @@ void setup_protocol(int f_out,int f_in)
- do_negotiated_strings = 1;
- compat_flags |= CF_VARINT_FLIST_FLAGS;
- }
-+ if (strchr(client_info, 'X') != NULL)
-+ compat_flags |= CF_XATTR_SUM_CHOICE;
- if (strchr(client_info, 'V') != NULL) { /* Support a pre-release 'V' that got superseded */
- if (!write_batch)
- compat_flags |= CF_VARINT_FLIST_FLAGS;
-@@ -801,11 +807,66 @@ void setup_protocol(int f_out,int f_in)
+@@ -801,11 +804,73 @@ void setup_protocol(int f_out,int f_in)
checksum_seed = read_int(f_in);
}
+ parse_checksum_choice(1); /* Sets file_sum_type & xfer_sum_type */
parse_compress_choice(1); /* Sets do_compression */
-+ if (compat_flags & CF_XATTR_SUM_CHOICE)
-+ xattr_sum_type = xfer_sum_type;
-+ else
-+ xattr_sum_type = parse_csum_name(NULL, 0);
++ /* 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_type = parse_csum_name(NULL, 0);
+ xattr_sum_len = csum_len_for_type(xattr_sum_type, 0);
+
if (write_batch && !am_server)
init_flist();
}
+
-+void output_daemon_greeting(int f_out)
++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)
++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 (f_out >= 0)
++ if (!am_client)
+ am_server = 1;
+
+ if (daemon_auth_choices)
+ md4_is_old = 1;
+ }
+
-+ if (am_server) {
++ 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_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);
+ }
-+ } else
-+ recv_negotiate_str(-1, &valid_auth_checksums, tmpbuf, strlen(tmpbuf));
++ }
+ am_server = save_am_server;
+ if (md4_is_old && valid_auth_checksums.negotiated_num == CSUM_MD4)
+ valid_auth_checksums.negotiated_num = CSUM_MD4_OLD;
if (DEBUG_GTE(DELTASUM, 2)) {
rprintf(FINFO, "false_alarms=%d hash_hits=%d matches=%d\n",
-diff --git a/options.c b/options.c
---- a/options.c
-+++ b/options.c
-@@ -3006,6 +3006,7 @@ int maybe_add_e_option(char *buf, int buf_len)
- buf[x++] = 'I'; /* support inplace_partial behavior */
- buf[x++] = 'v'; /* use varint for flist & compat flags; negotiate checksum */
- buf[x++] = 'u'; /* include name of uid 0 & gid 0 in the id map */
-+ buf[x++] = 'X'; /* xattr checksums use negotiated checksum not protocol default */
-
- /* NOTE: Avoid using 'V' -- it was represented with the high bit of a write_byte() that became a write_varint(). */
- }
diff --git a/receiver.c b/receiver.c
--- a/receiver.c
+++ b/receiver.c
diff --git a/xattrs.c b/xattrs.c
--- a/xattrs.c
+++ b/xattrs.c
-@@ -38,6 +38,8 @@ extern int preserve_devices;
+@@ -38,10 +38,13 @@ extern int preserve_devices;
extern int preserve_specials;
extern int checksum_seed;
extern int saw_xattr_filter;
#define RSYNC_XAL_INITIAL 5
#define RSYNC_XAL_LIST_INITIAL 100
-@@ -270,7 +272,7 @@ static int rsync_xal_get(const char *fname, item_list *xalp)
+
++#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 +272,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;
+- name_offset = 1 + MAX_DIGEST_LEN;
- sum_init(-1, checksum_seed);
++ name_offset = 1 + MAX_XATTR_DIGEST_LEN;
+ sum_init(xattr_sum_type, checksum_seed);
sum_update(ptr, datum_len);
free(ptr);
-@@ -382,7 +384,7 @@ static int64 xattr_lookup_hash(const item_list *xalp)
+@@ -382,7 +385,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)
else
key += hashlittle(rxas[i].datum, rxas[i].datum_len);
}
-@@ -435,7 +437,7 @@ static int find_matching_xattr(const item_list *xalp)
+@@ -435,7 +438,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,
break;
} else {
if (memcmp(rxas1[j].datum, rxas2[j].datum,
-@@ -535,7 +537,7 @@ int send_xattr(int f, stat_x *sxp)
+@@ -535,7 +538,7 @@ int send_xattr(int f, stat_x *sxp)
#endif
write_buf(f, name, name_len);
if (rxa->datum_len > MAX_FULL_DATUM)
else
write_bigbuf(f, rxa->datum, rxa->datum_len);
}
-@@ -588,7 +590,7 @@ int xattr_diff(struct file_struct *file, stat_x *sxp, int find_all)
+@@ -588,7 +591,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,
/* Flag unrequested items that we need. */
if (!same && find_all && snd_rxa->datum[0] == XSTATE_ABBREV)
snd_rxa->datum[0] = XSTATE_TODO;
-@@ -797,7 +799,7 @@ void receive_xattr(int f, struct file_struct *file)
+@@ -797,7 +800,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 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 +814,7 @@ void receive_xattr(int f, struct file_struct *file)
+@@ -812,7 +815,7 @@ void receive_xattr(int f, struct file_struct *file)
read_buf(f, ptr, dget_len);
else {
*ptr = XSTATE_ABBREV;
}
if (saw_xattr_filter) {
-@@ -958,7 +960,6 @@ static int rsync_xal_set(const char *fname, item_list *xalp,
+@@ -943,7 +946,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 +961,6 @@ static int rsync_xal_set(const char *fname, item_list *xalp,
name = rxas[i].name;
if (XATTR_ABBREV(rxas[i])) {
/* 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 +976,10 @@ static int rsync_xal_set(const char *fname, item_list *xalp,
+@@ -975,10 +977,10 @@ static int rsync_xal_set(const char *fname, item_list *xalp,
goto still_abbrev;
}
diff --git a/checksum.c b/checksum.c
--- a/checksum.c
+++ b/checksum.c
-@@ -51,6 +51,9 @@ struct name_num_obj valid_checksums = {
- #ifdef SUPPORT_XXHASH
- { CSUM_XXH64, "xxh64", NULL },
- { CSUM_XXH64, "xxhash", NULL },
-+#endif
-+#ifdef SHA_DIGEST_LENGTH
-+ { CSUM_SHA1, "sha1", NULL },
+@@ -54,6 +54,15 @@ struct name_num_obj valid_checksums = {
#endif
{ CSUM_MD5, "md5", NULL },
{ CSUM_MD4, "md4", NULL },
-@@ -61,6 +64,9 @@ struct name_num_obj valid_checksums = {
++#ifdef SHA_DIGEST_LENGTH
++ { CSUM_SHA1, "sha1", NULL },
++#endif
++#ifdef SHA256_DIGEST_LENGTH
++ { CSUM_SHA256, "sha256", NULL },
++#endif
++#ifdef SHA512_DIGEST_LENGTH
++ { CSUM_SHA512, "sha512", NULL },
++#endif
+ { CSUM_NONE, "none", NULL },
+ { 0, NULL, NULL }
+ }
+@@ -61,6 +70,15 @@ struct name_num_obj valid_checksums = {
struct name_num_obj valid_auth_checksums = {
"daemon auth checksum", NULL, NULL, 0, 0, {
++#ifdef SHA512_DIGEST_LENGTH
++ { CSUM_SHA512, "sha512", NULL },
++#endif
++#ifdef SHA256_DIGEST_LENGTH
++ { CSUM_SHA256, "sha256", NULL },
++#endif
+#ifdef SHA_DIGEST_LENGTH
+ { CSUM_SHA1, "sha1", NULL },
+#endif
{ CSUM_MD5, "md5", NULL },
{ CSUM_MD4, "md4", NULL },
{ 0, NULL, NULL }
-@@ -155,6 +161,10 @@ int csum_len_for_type(int cst, BOOL flist_csum)
+@@ -155,6 +173,18 @@ int csum_len_for_type(int cst, BOOL flist_csum)
return MD4_DIGEST_LEN;
case CSUM_MD5:
return MD5_DIGEST_LEN;
+#ifdef SHA_DIGEST_LENGTH
+ case CSUM_SHA1:
+ return SHA_DIGEST_LENGTH;
++#endif
++#ifdef SHA256_DIGEST_LENGTH
++ case CSUM_SHA256:
++ return SHA256_DIGEST_LENGTH;
++#endif
++#ifdef SHA512_DIGEST_LENGTH
++ case CSUM_SHA512:
++ return SHA512_DIGEST_LENGTH;
+#endif
case CSUM_XXH64:
case CSUM_XXH3_64:
return 64/8;
-@@ -180,6 +190,7 @@ int canonical_checksum(int csum_type)
+@@ -180,6 +210,9 @@ int canonical_checksum(int csum_type)
break;
case CSUM_MD4:
case CSUM_MD5:
+ case CSUM_SHA1:
++ case CSUM_SHA256:
++ case CSUM_SHA512:
return -1;
case CSUM_XXH64:
case CSUM_XXH3_64:
-@@ -232,6 +243,18 @@ void get_checksum2(char *buf, int32 len, char *sum)
+@@ -232,6 +265,26 @@ void get_checksum2(char *buf, int32 len, char *sum)
SIVAL64(sum, 8, digest.high64);
break;
}
+#endif
+#ifdef SHA_DIGEST_LENGTH
-+ case CSUM_SHA1: {
-+ SHA_CTX sha;
++ case CSUM_SHA1:
++ case CSUM_SHA256:
++ case CSUM_SHA512: {
++ static EVP_MD_CTX *evp = NULL;
++ static const EVP_MD *emd = NULL;
+ uchar seedbuf[4];
-+ SHA1_Init(&sha);
++ if (!evp) {
++ if (!(evp = EVP_MD_CTX_create()))
++ out_of_memory("get_checksum2");
++ emd = EVP_get_digestbyname(checksum_name(xfer_sum_type));
++ }
++ EVP_DigestInit_ex(evp, emd, NULL);
+ SIVALu(seedbuf, 0, checksum_seed);
-+ SHA1_Update(&sha, seedbuf, 4);
-+ SHA1_Update(&sha, (uchar *)buf, len);
-+ SHA1_Final((uchar *)sum, &sha);
++ EVP_DigestUpdate(evp, seedbuf, 4);
++ EVP_DigestUpdate(evp, (uchar *)buf, len);
++ EVP_DigestFinal_ex(evp, (uchar *)sum, NULL);
+ break;
+ }
#endif
case CSUM_MD5: {
md5_context m5;
-@@ -384,6 +407,23 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum)
+@@ -384,6 +437,31 @@ void file_checksum(const char *fname, const STRUCT_STAT *st_p, char *sum)
SIVAL64(sum, 8, digest.high64);
break;
}
+#endif
+#ifdef SHA_DIGEST_LENGTH
-+ case CSUM_SHA1: {
-+ SHA_CTX sha;
++ case CSUM_SHA1:
++ case CSUM_SHA256:
++ case CSUM_SHA512: {
++ static EVP_MD_CTX *evp = NULL;
++ static const EVP_MD *emd = NULL;
++ if (!evp) {
++ if (!(evp = EVP_MD_CTX_create()))
++ out_of_memory("file_checksum");
++ emd = EVP_get_digestbyname(checksum_name(xfer_sum_type));
++ }
+
-+ SHA1_Init(&sha);
++ EVP_DigestInit_ex(evp, emd, NULL);
+
+ for (i = 0; i + CHUNK_SIZE <= len; i += CHUNK_SIZE)
-+ SHA1_Update(&sha, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE);
++ EVP_DigestUpdate(evp, (uchar *)map_ptr(buf, i, CHUNK_SIZE), CHUNK_SIZE);
+
+ remainder = (int32)(len - i);
+ if (remainder > 0)
-+ SHA1_Update(&sha, (uchar *)map_ptr(buf, i, remainder), remainder);
++ EVP_DigestUpdate(evp, (uchar *)map_ptr(buf, i, remainder), remainder);
+
-+ SHA1_Final((uchar *)sum, &sha);
++ EVP_DigestFinal_ex(evp, (uchar *)sum, NULL);
+ break;
+ }
#endif
case CSUM_MD5: {
md5_context m5;
-@@ -454,6 +494,9 @@ static union {
- md_context md;
- #ifdef USE_OPENSSL
- MD4_CTX m4;
-+#endif
-+#ifdef SHA_DIGEST_LENGTH
-+ SHA_CTX sha;
+@@ -457,6 +535,9 @@ static union {
#endif
md5_context m5;
} ctx;
-@@ -494,6 +537,11 @@ int sum_init(int csum_type, int seed)
++#ifdef SHA_DIGEST_LENGTH
++EVP_MD_CTX *ctx_evp = NULL;
++#endif
+ #ifdef SUPPORT_XXHASH
+ static XXH64_state_t* xxh64_state;
+ #endif
+@@ -494,6 +575,17 @@ int sum_init(int csum_type, int seed)
out_of_memory("sum_init");
XXH3_128bits_reset(xxh3_state);
break;
+#endif
+#ifdef SHA_DIGEST_LENGTH
+ case CSUM_SHA1:
-+ SHA1_Init(&ctx.sha);
++ case CSUM_SHA256:
++ case CSUM_SHA512: {
++ const EVP_MD *emd = EVP_get_digestbyname(checksum_name(csum_type));
++ if (!ctx_evp && !(ctx_evp = EVP_MD_CTX_create()))
++ out_of_memory("file_checksum");
++ EVP_DigestInit_ex(ctx_evp, emd, NULL);
+ break;
++ }
#endif
case CSUM_MD5:
md5_begin(&ctx.m5);
-@@ -546,6 +594,11 @@ void sum_update(const char *p, int32 len)
+@@ -546,6 +638,13 @@ void sum_update(const char *p, int32 len)
case CSUM_XXH3_128:
XXH3_128bits_update(xxh3_state, p, len);
break;
+#endif
+#ifdef SHA_DIGEST_LENGTH
+ case CSUM_SHA1:
-+ SHA1_Update(&ctx.sha, (uchar *)p, len);
++ case CSUM_SHA256:
++ case CSUM_SHA512:
++ EVP_DigestUpdate(ctx_evp, (uchar *)p, len);
+ break;
#endif
case CSUM_MD5:
md5_update(&ctx.m5, (uchar *)p, len);
-@@ -611,6 +664,11 @@ void sum_end(char *sum)
+@@ -611,6 +710,13 @@ void sum_end(char *sum)
SIVAL64(sum, 8, digest.high64);
break;
}
+#endif
+#ifdef SHA_DIGEST_LENGTH
+ case CSUM_SHA1:
-+ SHA1_Final((uchar *)sum, &ctx.sha);
++ case CSUM_SHA256:
++ case CSUM_SHA512:
++ EVP_DigestFinal_ex(ctx_evp, (uchar *)sum, NULL);
+ break;
#endif
case CSUM_MD5:
diff --git a/lib/md-defines.h b/lib/md-defines.h
--- a/lib/md-defines.h
+++ b/lib/md-defines.h
-@@ -2,7 +2,11 @@
+@@ -1,8 +1,19 @@
+ /* Keep this simple so both C and ASM can use it */
++/*#undef SHA512_DIGEST_LENGTH*/
++/*#undef SHA256_DIGEST_LENGTH*/
++
#define MD4_DIGEST_LEN 16
#define MD5_DIGEST_LEN 16
-+#ifdef SHA_DIGEST_LENGTH
++#if defined SHA512_DIGEST_LENGTH
++#define MAX_DIGEST_LEN SHA512_DIGEST_LENGTH
++#elif defined SHA256_DIGEST_LENGTH
++#define MAX_DIGEST_LEN SHA256_DIGEST_LENGTH
++#elif defined SHA_DIGEST_LENGTH
+#define MAX_DIGEST_LEN SHA_DIGEST_LENGTH
+#else
#define MAX_DIGEST_LEN MD5_DIGEST_LEN
#define CSUM_CHUNK 64
-@@ -15,3 +19,4 @@
+@@ -15,3 +26,6 @@
#define CSUM_XXH64 6
#define CSUM_XXH3_64 7
#define CSUM_XXH3_128 8
+#define CSUM_SHA1 9
++#define CSUM_SHA256 10
++#define CSUM_SHA512 11
diff --git a/lib/mdigest.h b/lib/mdigest.h
--- a/lib/mdigest.h
+++ b/lib/mdigest.h
-@@ -3,6 +3,7 @@
+@@ -3,6 +3,8 @@
#ifdef USE_OPENSSL
#include "openssl/md4.h"
#include "openssl/md5.h"
+#include <openssl/sha.h>
++#include <openssl/evp.h>
#endif
#include "md-defines.h"