version 1.1.1.3, 2016/11/01 09:54:32
|
version 1.1.1.4, 2021/03/17 00:32:36
|
Line 3
|
Line 3
|
* |
* |
* Copyright (C) 1996 Andrew Tridgell |
* Copyright (C) 1996 Andrew Tridgell |
* Copyright (C) 1996 Paul Mackerras |
* Copyright (C) 1996 Paul Mackerras |
* Copyright (C) 2006-2015 Wayne Davison | * Copyright (C) 2006-2020 Wayne Davison |
* |
* |
* This program is free software; you can redistribute it and/or modify |
* This program is free software; you can redistribute it and/or modify |
* it under the terms of the GNU General Public License as published by |
* it under the terms of the GNU General Public License as published by |
Line 48 extern int preserve_specials;
|
Line 48 extern int preserve_specials;
|
/* When we send the access bits over the wire, we shift them 2 bits to the |
/* When we send the access bits over the wire, we shift them 2 bits to the |
* left and use the lower 2 bits as flags (relevant only to a name entry). |
* left and use the lower 2 bits as flags (relevant only to a name entry). |
* This makes the protocol more efficient than sending a value that would |
* This makes the protocol more efficient than sending a value that would |
* be likely to have its hightest bits set. */ | * be likely to have its highest bits set. */ |
#define XFLAG_NAME_FOLLOWS 0x0001u |
#define XFLAG_NAME_FOLLOWS 0x0001u |
#define XFLAG_NAME_IS_USER 0x0002u |
#define XFLAG_NAME_IS_USER 0x0002u |
|
|
Line 78 typedef struct rsync_acl {
|
Line 78 typedef struct rsync_acl {
|
uchar other_obj; |
uchar other_obj; |
} rsync_acl; |
} rsync_acl; |
|
|
typedef struct nfs4_acl { |
|
char *nfs4_acl_text; |
|
ssize_t nfs4_acl_len; |
|
} nfs4_acl; |
|
|
|
typedef struct { |
typedef struct { |
rsync_acl racl; |
rsync_acl racl; |
SMB_ACL_T sacl; |
SMB_ACL_T sacl; |
} acl_duo; |
} acl_duo; |
|
|
typedef struct { |
|
nfs4_acl nacl; |
|
SMB_ACL_T sacl; |
|
} nfs4_duo; |
|
|
|
static const rsync_acl empty_rsync_acl = { |
static const rsync_acl empty_rsync_acl = { |
{NULL, 0}, NO_ENTRY, NO_ENTRY, NO_ENTRY, NO_ENTRY |
{NULL, 0}, NO_ENTRY, NO_ENTRY, NO_ENTRY, NO_ENTRY |
}; |
}; |
static const nfs4_acl empty_nfs4_acl = { |
|
NULL, -1 |
|
}; |
|
|
|
static item_list access_acl_list = EMPTY_ITEM_LIST; |
static item_list access_acl_list = EMPTY_ITEM_LIST; |
static item_list default_acl_list = EMPTY_ITEM_LIST; |
static item_list default_acl_list = EMPTY_ITEM_LIST; |
static item_list nfs4_acl_list = EMPTY_ITEM_LIST; |
|
|
|
static size_t prior_access_count = (size_t)-1; |
static size_t prior_access_count = (size_t)-1; |
static size_t prior_default_count = (size_t)-1; |
static size_t prior_default_count = (size_t)-1; |
static size_t prior_nfs4_count = (size_t)-1; |
|
|
|
/* === Calculations on ACL types === */ |
/* === Calculations on ACL types === */ |
|
|
Line 183 static rsync_acl *create_racl(void)
|
Line 168 static rsync_acl *create_racl(void)
|
{ |
{ |
rsync_acl *racl = new(rsync_acl); |
rsync_acl *racl = new(rsync_acl); |
|
|
if (!racl) |
|
out_of_memory("create_racl"); |
|
*racl = empty_rsync_acl; |
*racl = empty_rsync_acl; |
|
|
return racl; |
return racl; |
} |
} |
|
|
static nfs4_acl *create_nfs4_acl(void) |
|
{ |
|
nfs4_acl *nacl = new(nfs4_acl); |
|
|
|
if (!nacl) |
|
out_of_memory("create_nfs4_acl"); |
|
*nacl = empty_nfs4_acl; |
|
|
|
return nacl; |
|
} |
|
|
|
static BOOL ida_entries_equal(const ida_entries *ial1, const ida_entries *ial2) |
static BOOL ida_entries_equal(const ida_entries *ial1, const ida_entries *ial2) |
{ |
{ |
id_access *ida1, *ida2; |
id_access *ida1, *ida2; |
Line 225 static BOOL rsync_acl_equal(const rsync_acl *racl1, co
|
Line 197 static BOOL rsync_acl_equal(const rsync_acl *racl1, co
|
&& ida_entries_equal(&racl1->names, &racl2->names); |
&& ida_entries_equal(&racl1->names, &racl2->names); |
} |
} |
|
|
static BOOL nfs4_acl_equal(const nfs4_acl *nacl1, const nfs4_acl *nacl2) |
|
{ |
|
return (strcmp(nacl1->nfs4_acl_text, nacl2->nfs4_acl_text) == 0); |
|
} |
|
|
|
/* Are the extended (non-permission-bit) entries equal? If so, the rest of |
/* Are the extended (non-permission-bit) entries equal? If so, the rest of |
* the ACL will be handled by the normal mode-preservation code. This is |
* the ACL will be handled by the normal mode-preservation code. This is |
* only meaningful for access ACLs! Note: the 1st arg is a fully-populated |
* only meaningful for access ACLs! Note: the 1st arg is a fully-populated |
Line 263 static void rsync_acl_free(rsync_acl *racl)
|
Line 230 static void rsync_acl_free(rsync_acl *racl)
|
*racl = empty_rsync_acl; |
*racl = empty_rsync_acl; |
} |
} |
|
|
static void nfs4_acl_free(nfs4_acl *nacl) |
|
{ |
|
if (nacl->nfs4_acl_text) |
|
free(nacl->nfs4_acl_text); |
|
*nacl = empty_nfs4_acl; |
|
} |
|
|
|
void free_acl(stat_x *sxp) |
void free_acl(stat_x *sxp) |
{ |
{ |
if (sxp->acc_acl) { |
if (sxp->acc_acl) { |
Line 282 void free_acl(stat_x *sxp)
|
Line 242 void free_acl(stat_x *sxp)
|
free(sxp->def_acl); |
free(sxp->def_acl); |
sxp->def_acl = NULL; |
sxp->def_acl = NULL; |
} |
} |
if (sxp->nfs4_acl) { |
|
nfs4_acl_free(sxp->nfs4_acl); |
|
free(sxp->nfs4_acl); |
|
sxp->nfs4_acl = NULL; |
|
} |
|
} |
} |
|
|
#ifdef SMB_ACL_NEED_SORT |
#ifdef SMB_ACL_NEED_SORT |
Line 375 static BOOL unpack_smb_acl(SMB_ACL_T sacl, rsync_acl *
|
Line 330 static BOOL unpack_smb_acl(SMB_ACL_T sacl, rsync_acl *
|
if (temp_ida_list.count) { |
if (temp_ida_list.count) { |
#ifdef SMB_ACL_NEED_SORT |
#ifdef SMB_ACL_NEED_SORT |
if (temp_ida_list.count > 1) { |
if (temp_ida_list.count > 1) { |
qsort(temp_ida_list.items, temp_ida_list.count, | qsort(temp_ida_list.items, temp_ida_list.count, sizeof (id_access), id_access_sorter); |
sizeof (id_access), id_access_sorter); | |
} |
} |
#endif |
#endif |
if (!(racl->names.idas = new_array(id_access, temp_ida_list.count))) | racl->names.idas = new_array(id_access, temp_ida_list.count); |
out_of_memory("unpack_smb_acl"); | memcpy(racl->names.idas, temp_ida_list.items, temp_ida_list.count * sizeof (id_access)); |
memcpy(racl->names.idas, temp_ida_list.items, | |
temp_ida_list.count * sizeof (id_access)); | |
} else |
} else |
racl->names.idas = NULL; |
racl->names.idas = NULL; |
|
|
Line 517 static int find_matching_rsync_acl(const rsync_acl *ra
|
Line 469 static int find_matching_rsync_acl(const rsync_acl *ra
|
return *match; |
return *match; |
} |
} |
|
|
static int find_matching_nfs4_acl(const nfs4_acl *nacl, const item_list *nfs4_acl_list) |
|
{ |
|
static int nfs4_match = -1; |
|
int *match = &nfs4_match; |
|
size_t count = nfs4_acl_list->count; |
|
|
|
if (*match == -1) |
|
*match = nfs4_acl_list->count - 1; |
|
while (count--) { |
|
nfs4_acl *base = nfs4_acl_list->items; |
|
if (nfs4_acl_equal(base + *match, nacl)) |
|
return *match; |
|
if (!(*match)--) |
|
*match = nfs4_acl_list->count - 1; |
|
} |
|
|
|
*match = -1; |
|
return *match; |
|
} |
|
|
|
static int get_rsync_acl(const char *fname, rsync_acl *racl, |
static int get_rsync_acl(const char *fname, rsync_acl *racl, |
SMB_ACL_TYPE_T type, mode_t mode) |
SMB_ACL_TYPE_T type, mode_t mode) |
{ |
{ |
Line 570 static int get_rsync_acl(const char *fname, rsync_acl
|
Line 502 static int get_rsync_acl(const char *fname, rsync_acl
|
|
|
if (cnt) { |
if (cnt) { |
char *bp = buf + 4*4; |
char *bp = buf + 4*4; |
id_access *ida; | id_access *ida = racl->names.idas = new_array(id_access, cnt); |
if (!(ida = racl->names.idas = new_array(id_access, cnt))) | |
out_of_memory("get_rsync_acl"); | |
racl->names.count = cnt; |
racl->names.count = cnt; |
for ( ; cnt--; ida++, bp += 4+4) { |
for ( ; cnt--; ida++, bp += 4+4) { |
ida->id = IVAL(bp, 0); |
ida->id = IVAL(bp, 0); |
Line 607 static int get_rsync_acl(const char *fname, rsync_acl
|
Line 537 static int get_rsync_acl(const char *fname, rsync_acl
|
/* Return the Access Control List for the given filename. */ |
/* Return the Access Control List for the given filename. */ |
int get_acl(const char *fname, stat_x *sxp) |
int get_acl(const char *fname, stat_x *sxp) |
{ |
{ |
if (sys_acl_get_brand_file(fname, &sxp->brand) < 0) |
|
return -1; |
|
|
|
if (sxp->brand == SMB_ACL_BRAND_NFS4) { |
|
SMB_ACL_T sacl; |
|
if ((sacl = sys_acl_get_file(fname, SMB_ACL_TYPE_NFS4)) == NULL) |
|
return -1; |
|
|
|
sxp->nfs4_acl = create_nfs4_acl(); |
|
sxp->nfs4_acl->nfs4_acl_text = acl_to_text(sacl, &sxp->nfs4_acl->nfs4_acl_len); |
|
|
|
sys_acl_free_acl(sacl); |
|
return 0; |
|
} |
|
|
|
sxp->acc_acl = create_racl(); |
sxp->acc_acl = create_racl(); |
|
|
if (S_ISREG(sxp->st.st_mode) || S_ISDIR(sxp->st.st_mode)) { |
if (S_ISREG(sxp->st.st_mode) || S_ISDIR(sxp->st.st_mode)) { |
Line 730 static void send_rsync_acl(int f, rsync_acl *racl, SMB
|
Line 645 static void send_rsync_acl(int f, rsync_acl *racl, SMB
|
} |
} |
} |
} |
|
|
static void send_nfs4_acl(int f, nfs4_acl *nacl, item_list *nfs4_list) |
|
{ |
|
int ndx = find_matching_nfs4_acl(nacl, nfs4_list); |
|
|
|
/* Send 0 (-1 + 1) to indicate that literal ACL data follows. */ |
|
write_varint(f, ndx + 1); |
|
|
|
if (ndx < 0) { |
|
nfs4_acl *new_nacl = EXPAND_ITEM_LIST(&nfs4_acl_list, nfs4_acl, 1000); |
|
|
|
write_varint(f, nacl->nfs4_acl_len); |
|
write_buf(f, nacl->nfs4_acl_text, nacl->nfs4_acl_len); |
|
|
|
*new_nacl = *nacl; |
|
*nacl = empty_nfs4_acl; |
|
} |
|
} |
|
|
|
|
|
/* Send the ACL from the stat_x structure down the indicated file descriptor. |
/* Send the ACL from the stat_x structure down the indicated file descriptor. |
* This also frees the ACL data. */ |
* This also frees the ACL data. */ |
void send_acl(int f, stat_x *sxp) |
void send_acl(int f, stat_x *sxp) |
Line 760 void send_acl(int f, stat_x *sxp)
|
Line 656 void send_acl(int f, stat_x *sxp)
|
/* Avoid sending values that can be inferred from other data. */ |
/* Avoid sending values that can be inferred from other data. */ |
rsync_acl_strip_perms(sxp); |
rsync_acl_strip_perms(sxp); |
|
|
write_varint(f, SMB_ACL_TYPE_ACCESS); |
|
send_rsync_acl(f, sxp->acc_acl, SMB_ACL_TYPE_ACCESS, &access_acl_list); |
send_rsync_acl(f, sxp->acc_acl, SMB_ACL_TYPE_ACCESS, &access_acl_list); |
|
|
if (S_ISDIR(sxp->st.st_mode)) { |
if (S_ISDIR(sxp->st.st_mode)) { |
if (!sxp->def_acl) |
if (!sxp->def_acl) |
sxp->def_acl = create_racl(); |
sxp->def_acl = create_racl(); |
|
|
write_varint(f, SMB_ACL_TYPE_DEFAULT); |
|
send_rsync_acl(f, sxp->def_acl, SMB_ACL_TYPE_DEFAULT, &default_acl_list); |
send_rsync_acl(f, sxp->def_acl, SMB_ACL_TYPE_DEFAULT, &default_acl_list); |
} |
} |
} |
} |
Line 804 static uchar recv_ida_entries(int f, ida_entries *ent)
|
Line 698 static uchar recv_ida_entries(int f, ida_entries *ent)
|
uchar computed_mask_bits = 0; |
uchar computed_mask_bits = 0; |
int i, count = read_varint(f); |
int i, count = read_varint(f); |
|
|
if (count) { | ent->idas = count ? new_array(id_access, count) : NULL; |
if (!(ent->idas = new_array(id_access, count))) | |
out_of_memory("recv_ida_entries"); | |
} else | |
ent->idas = NULL; | |
| |
ent->count = count; |
ent->count = count; |
|
|
for (i = 0; i < count; i++) { |
for (i = 0; i < count; i++) { |
Line 917 static int cache_rsync_acl(rsync_acl *racl, SMB_ACL_TY
|
Line 806 static int cache_rsync_acl(rsync_acl *racl, SMB_ACL_TY
|
return ndx; |
return ndx; |
} |
} |
|
|
static int cache_nfs4_acl(nfs4_acl *nacl, item_list *nfs4_list) |
|
{ |
|
int ndx; |
|
|
|
if (!nacl) |
|
ndx = -1; |
|
else if ((ndx = find_matching_nfs4_acl(nacl, nfs4_list)) == -1) { |
|
nfs4_duo *new_duo; |
|
ndx = nfs4_list->count; |
|
new_duo = EXPAND_ITEM_LIST(nfs4_list, nfs4_duo, 1000); |
|
new_duo->nacl = *nacl; |
|
new_duo->sacl = NULL; |
|
*nacl = empty_nfs4_acl; |
|
} |
|
|
|
return ndx; |
|
} |
|
|
|
|
|
/* Turn the ACL data in stat_x into cached ACL data, setting the index |
/* Turn the ACL data in stat_x into cached ACL data, setting the index |
* values in the file struct. */ |
* values in the file struct. */ |
void cache_tmp_acl(struct file_struct *file, stat_x *sxp) |
void cache_tmp_acl(struct file_struct *file, stat_x *sxp) |
{ |
{ |
if (sxp->brand == SMB_ACL_BRAND_NFS4) { |
|
if (prior_nfs4_count == (size_t)-1) |
|
prior_nfs4_count = nfs4_acl_list.count; |
|
|
|
F_ACL(file) = cache_nfs4_acl(sxp->nfs4_acl, &nfs4_acl_list); |
|
return; |
|
} |
|
|
|
if (prior_access_count == (size_t)-1) |
if (prior_access_count == (size_t)-1) |
prior_access_count = access_acl_list.count; |
prior_access_count = access_acl_list.count; |
|
|
F_ACL(file) = cache_rsync_acl(sxp->acc_acl, | F_ACL(file) = cache_rsync_acl(sxp->acc_acl, SMB_ACL_TYPE_ACCESS, &access_acl_list); |
SMB_ACL_TYPE_ACCESS, &access_acl_list); | |
|
|
if (S_ISDIR(sxp->st.st_mode)) { |
if (S_ISDIR(sxp->st.st_mode)) { |
if (prior_default_count == (size_t)-1) |
if (prior_default_count == (size_t)-1) |
prior_default_count = default_acl_list.count; |
prior_default_count = default_acl_list.count; |
F_DIR_DEFACL(file) = cache_rsync_acl(sxp->def_acl, | F_DIR_DEFACL(file) = cache_rsync_acl(sxp->def_acl, SMB_ACL_TYPE_DEFAULT, &default_acl_list); |
SMB_ACL_TYPE_DEFAULT, &default_acl_list); | |
} |
} |
} |
} |
|
|
Line 977 static void uncache_duo_acls(item_list *duo_list, size
|
Line 837 static void uncache_duo_acls(item_list *duo_list, size
|
} |
} |
} |
} |
|
|
static void uncache_nfs4_acls(item_list *nfs4_list, size_t start) |
|
{ |
|
nfs4_duo *nfs4_item = nfs4_list->items; |
|
nfs4_duo *nfs4_start = nfs4_item + start; |
|
|
|
nfs4_item += nfs4_list->count; |
|
nfs4_list->count = start; |
|
|
|
while (nfs4_item-- > nfs4_start) { |
|
nfs4_acl_free(&nfs4_item->nacl); |
|
if (nfs4_item->sacl) |
|
sys_acl_free_acl(nfs4_item->sacl); |
|
} |
|
} |
|
|
|
void uncache_tmp_acls(void) |
void uncache_tmp_acls(void) |
{ |
{ |
if (prior_access_count != (size_t)-1) { |
if (prior_access_count != (size_t)-1) { |
Line 1003 void uncache_tmp_acls(void)
|
Line 848 void uncache_tmp_acls(void)
|
uncache_duo_acls(&default_acl_list, prior_default_count); |
uncache_duo_acls(&default_acl_list, prior_default_count); |
prior_default_count = (size_t)-1; |
prior_default_count = (size_t)-1; |
} |
} |
if (prior_nfs4_count != (size_t)-1) { |
|
uncache_nfs4_acls(&nfs4_acl_list, prior_nfs4_count); |
|
prior_nfs4_count = (size_t)-1; |
|
} |
|
} |
} |
|
|
#ifndef HAVE_OSX_ACLS |
#ifndef HAVE_OSX_ACLS |
Line 1141 static int set_rsync_acl(const char *fname, acl_duo *d
|
Line 982 static int set_rsync_acl(const char *fname, acl_duo *d
|
mode = 0; /* eliminate compiler warning */ |
mode = 0; /* eliminate compiler warning */ |
#else |
#else |
if (type == SMB_ACL_TYPE_ACCESS) { |
if (type == SMB_ACL_TYPE_ACCESS) { |
cur_mode = change_sacl_perms(duo_item->sacl, &duo_item->racl, | cur_mode = change_sacl_perms(duo_item->sacl, &duo_item->racl, cur_mode, mode); |
cur_mode, mode); | |
if (cur_mode == (mode_t)-1) |
if (cur_mode == (mode_t)-1) |
return 0; |
return 0; |
} |
} |
Line 1159 static int set_rsync_acl(const char *fname, acl_duo *d
|
Line 999 static int set_rsync_acl(const char *fname, acl_duo *d
|
return 0; |
return 0; |
} |
} |
|
|
|
|
/* Given a fname, this sets extended access ACL entries, the default ACL (for a |
/* Given a fname, this sets extended access ACL entries, the default ACL (for a |
* dir), and the regular mode bits on the file. Call this with fname set to |
* dir), and the regular mode bits on the file. Call this with fname set to |
* NULL to just check if the ACL is different. |
* NULL to just check if the ACL is different. |
Line 1179 int set_acl(const char *fname, const struct file_struc
|
Line 1018 int set_acl(const char *fname, const struct file_struc
|
return -1; |
return -1; |
} |
} |
|
|
if (sxp->brand == SMB_ACL_BRAND_NFS4) { |
|
ndx = F_ACL(file); |
|
if (ndx >= 0 && (size_t)ndx < nfs4_acl_list.count) { |
|
nfs4_duo *duo_item = nfs4_acl_list.items; |
|
duo_item += ndx; |
|
changed = 1; |
|
|
|
if (!duo_item->sacl) { |
|
duo_item->sacl = acl_from_text(duo_item->nacl.nfs4_acl_text); |
|
if (!duo_item->sacl) |
|
return -1; |
|
} |
|
|
|
if (!dry_run && fname) { |
|
if (sys_acl_set_file(fname, SMB_ACL_TYPE_NFS4, duo_item->sacl) < 0) { |
|
rsyserr(FERROR_XFER, errno, "set_acl: sys_acl_set_file(%s, %s)", |
|
fname, str_acl_type(SMB_ACL_TYPE_NFS4)); |
|
return -1; |
|
} |
|
|
|
return changed; |
|
} |
|
} |
|
} |
|
|
|
|
|
ndx = F_ACL(file); |
ndx = F_ACL(file); |
if (ndx >= 0 && (size_t)ndx < access_acl_list.count) { |
if (ndx >= 0 && (size_t)ndx < access_acl_list.count) { |
acl_duo *duo_item = access_acl_list.items; |
acl_duo *duo_item = access_acl_list.items; |
Line 1289 int default_perms_for_dir(const char *dir)
|
Line 1102 int default_perms_for_dir(const char *dir)
|
case ENOSYS: |
case ENOSYS: |
/* No ACLs are available. */ |
/* No ACLs are available. */ |
break; |
break; |
case ENOENT: | default: |
if (dry_run) { | if (dry_run && errno == ENOENT) { |
/* We're doing a dry run, so the containing directory |
/* We're doing a dry run, so the containing directory |
* wasn't actually created. Don't worry about it. */ |
* wasn't actually created. Don't worry about it. */ |
break; |
break; |
} |
} |
/* Otherwise fall through. */ |
|
default: |
|
rprintf(FWARNING, |
rprintf(FWARNING, |
"default_perms_for_dir: sys_acl_get_file(%s, %s): %s, falling back on umask\n", |
"default_perms_for_dir: sys_acl_get_file(%s, %s): %s, falling back on umask\n", |
dir, str_acl_type(SMB_ACL_TYPE_DEFAULT), strerror(errno)); |
dir, str_acl_type(SMB_ACL_TYPE_DEFAULT), strerror(errno)); |