|
|
| version 1.1, 2012/02/17 15:09:30 | version 1.1.1.3, 2016/11/01 09:54:32 |
|---|---|
| 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-2009 Wayne Davison | * Copyright (C) 2006-2015 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 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 175 static rsync_acl *create_racl(void) | Line 190 static rsync_acl *create_racl(void) |
| 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 199 static BOOL rsync_acl_equal(const rsync_acl *racl1, co | Line 225 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 232 static void rsync_acl_free(rsync_acl *racl) | Line 263 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 244 void free_acl(stat_x *sxp) | Line 282 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 423 static BOOL pack_smb_acl(SMB_ACL_T *smb_acl, const rsy | Line 466 static BOOL pack_smb_acl(SMB_ACL_T *smb_acl, const rsy |
| #ifdef ACLS_NEED_MASK | #ifdef ACLS_NEED_MASK |
| mask_bits = racl->mask_obj == NO_ENTRY ? racl->group_obj & ~NO_ENTRY : racl->mask_obj; | mask_bits = racl->mask_obj == NO_ENTRY ? racl->group_obj & ~NO_ENTRY : racl->mask_obj; |
| COE( sys_acl_create_entry,(smb_acl, &entry) ); | COE( sys_acl_create_entry,(smb_acl, &entry) ); |
| COE( sys_acl_set_info,(entry, SMB_ACL_MASK, mask_bits, NULL) ); | COE( sys_acl_set_info,(entry, SMB_ACL_MASK, mask_bits, 0) ); |
| #else | #else |
| if (racl->mask_obj != NO_ENTRY) { | if (racl->mask_obj != NO_ENTRY) { |
| COE( sys_acl_create_entry,(smb_acl, &entry) ); | COE( sys_acl_create_entry,(smb_acl, &entry) ); |
| Line 474 static int find_matching_rsync_acl(const rsync_acl *ra | Line 517 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 544 static int get_rsync_acl(const char *fname, rsync_acl | Line 607 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 560 int get_acl(const char *fname, stat_x *sxp) | Line 638 int get_acl(const char *fname, stat_x *sxp) |
| if (!preserve_devices) | if (!preserve_devices) |
| #endif | #endif |
| return 0; | return 0; |
| } | } else if (IS_MISSING_FILE(sxp->st)) |
| return 0; | |
| if (get_rsync_acl(fname, sxp->acc_acl, SMB_ACL_TYPE_ACCESS, | if (get_rsync_acl(fname, sxp->acc_acl, SMB_ACL_TYPE_ACCESS, |
| sxp->st.st_mode) < 0) { | sxp->st.st_mode) < 0) { |
| Line 651 static void send_rsync_acl(int f, rsync_acl *racl, SMB | Line 730 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 662 void send_acl(int f, stat_x *sxp) | Line 760 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 817 static int cache_rsync_acl(rsync_acl *racl, SMB_ACL_TY | Line 917 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; |
| Line 850 static void uncache_duo_acls(item_list *duo_list, size | Line 977 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 861 void uncache_tmp_acls(void) | Line 1003 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 1013 static int set_rsync_acl(const char *fname, acl_duo *d | Line 1159 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 1032 int set_acl(const char *fname, const struct file_struc | Line 1179 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 1143 int default_perms_for_dir(const char *dir) | Line 1316 int default_perms_for_dir(const char *dir) |
| /* Apply the permission-bit entries of the default ACL, if any. */ | /* Apply the permission-bit entries of the default ACL, if any. */ |
| if (racl.user_obj != NO_ENTRY) { | if (racl.user_obj != NO_ENTRY) { |
| perms = rsync_acl_get_perms(&racl); | perms = rsync_acl_get_perms(&racl); |
| if (verbose > 2) | if (DEBUG_GTE(ACL, 1)) |
| rprintf(FINFO, "got ACL-based default perms %o for directory %s\n", perms, dir); | rprintf(FINFO, "got ACL-based default perms %o for directory %s\n", perms, dir); |
| } | } |