Diff for /embedaddon/rsync/acls.c between versions 1.1.1.3 and 1.1.1.4

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));

Removed from v.1.1.1.3  
changed lines
  Added in v.1.1.1.4


FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>