acls.c

説明を見る。
00001 /* -*- c-file-style: "linux" -*-
00002    Copyright (C) Andrew Tridgell 1996
00003    Copyright (C) Paul Mackerras 1996
00004    Copyright (C) Matt McCutchen 2006
00005    Copyright (C) Wayne Davison 2006
00006 
00007    This program is free software; you can redistribute it and/or modify
00008    it under the terms of the GNU General Public License as published by
00009    the Free Software Foundation; either version 2 of the License, or
00010    (at your option) any later version.
00011 
00012    This program is distributed in the hope that it will be useful,
00013    but WITHOUT ANY WARRANTY; without even the implied warranty of
00014    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00015    GNU General Public License for more details.
00016 
00017    You should have received a copy of the GNU General Public License
00018    along with this program; if not, write to the Free Software
00019    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
00020 */
00021 
00022 /* handle passing ACLs between systems */
00023 
00024 #include "rsync.h"
00025 #include "lib/sysacls.h"
00026 
00027 #ifdef SUPPORT_ACLS
00028 
00029 extern int am_root;
00030 extern int dry_run;
00031 extern int orig_umask;
00032 extern int preserve_acls;
00033 
00034 typedef struct {
00035         id_t id;
00036         uchar access;
00037 } id_access;
00038 
00039 typedef struct {
00040         size_t count;
00041         size_t malloced;
00042         id_access *idas;
00043 } ida_list;
00044 
00045 #define ACL_NO_ENTRY ((uchar)0x80)
00046 typedef struct {
00047         ida_list users;
00048         ida_list groups;
00049         /* These will be ACL_NO_ENTRY if there's no such entry. */
00050         uchar user_obj;
00051         uchar group_obj;
00052         uchar mask;
00053         uchar other;
00054 } rsync_acl;
00055 
00056 static const rsync_acl rsync_acl_initializer = {
00057         {0, 0, NULL}, {0, 0, NULL},
00058         ACL_NO_ENTRY, ACL_NO_ENTRY, ACL_NO_ENTRY, ACL_NO_ENTRY
00059 };
00060 
00061 #define OTHER_TYPE(t) (SMB_ACL_TYPE_ACCESS+SMB_ACL_TYPE_DEFAULT-(t))
00062 #define BUMP_TYPE(t) ((t = OTHER_TYPE(t)) == SMB_ACL_TYPE_DEFAULT)
00063 
00064 /* a few useful calculations */
00065 
00066 static int count_racl_entries(const rsync_acl *racl)
00067 {
00068         return racl->users.count + racl->groups.count
00069              + (racl->user_obj != ACL_NO_ENTRY)
00070              + (racl->group_obj != ACL_NO_ENTRY)
00071              + (racl->mask != ACL_NO_ENTRY)
00072              + (racl->other != ACL_NO_ENTRY);
00073 }
00074 
00075 static int calc_sacl_entries(const rsync_acl *racl)
00076 {
00077         return racl->users.count + racl->groups.count
00078 #ifdef ACLS_NEED_MASK
00079              + 4;
00080 #else
00081              + (racl->mask != ACL_NO_ENTRY) + 3;
00082 #endif
00083 }
00084 
00085 static int rsync_acl_get_perms(const rsync_acl *racl)
00086 {
00087         /* Note that (ACL_NO_ENTRY & 7) is 0. */
00088         return ((racl->user_obj & 7) << 6)
00089              + (((racl->mask != ACL_NO_ENTRY ? racl->mask : racl->group_obj) & 7) << 3)
00090              + (racl->other & 7);
00091 }
00092 
00093 static void rsync_acl_strip_perms(rsync_acl *racl)
00094 {
00095         racl->user_obj = ACL_NO_ENTRY;
00096         if (racl->mask == ACL_NO_ENTRY)
00097                 racl->group_obj = ACL_NO_ENTRY;
00098         else
00099                 racl->mask = ACL_NO_ENTRY;
00100         racl->other = ACL_NO_ENTRY;
00101 }
00102 
00103 static void expand_ida_list(ida_list *idal)
00104 {
00105         /* First time through, 0 <= 0, so list is expanded. */
00106         if (idal->malloced <= idal->count) {
00107                 id_access *new_ptr;
00108                 size_t new_size = idal->malloced + 10;
00109                 new_ptr = realloc_array(idal->idas, id_access, new_size);
00110                 if (verbose >= 4) {
00111                         rprintf(FINFO, "expand rsync_acl to %.0f bytes, did%s move\n",
00112                                 (double) new_size * sizeof idal->idas[0],
00113                                 idal->idas ? "" : " not");
00114                 }
00115 
00116                 idal->idas = new_ptr;
00117                 idal->malloced = new_size;
00118 
00119                 if (!idal->idas)
00120                         out_of_memory("expand_ida_list");
00121         }
00122 }
00123 
00124 static void ida_list_free(ida_list *idal)
00125 {
00126         free(idal->idas);
00127         idal->idas = NULL;
00128         idal->count = 0;
00129         idal->malloced = 0;
00130 }
00131 
00132 static void rsync_acl_free(rsync_acl *racl)
00133 {
00134         ida_list_free(&racl->users);
00135         ida_list_free(&racl->groups);
00136 }
00137 
00138 static int id_access_sorter(const void *r1, const void *r2)
00139 {
00140         id_access *ida1 = (id_access *)r1;
00141         id_access *ida2 = (id_access *)r2;
00142         id_t rid1 = ida1->id, rid2 = ida2->id;
00143         return rid1 == rid2 ? 0 : rid1 < rid2 ? -1 : 1;
00144 }
00145 
00146 static void sort_ida_list(ida_list *idal)
00147 {
00148         if (!idal->count)
00149                 return;
00150         qsort((void **)idal->idas, idal->count, sizeof idal->idas[0],
00151               &id_access_sorter);
00152 }
00153 
00154 static BOOL unpack_smb_acl(rsync_acl *racl, SMB_ACL_T sacl)
00155 {
00156         SMB_ACL_ENTRY_T entry;
00157         const char *errfun;
00158         int rc;
00159 
00160         *racl = rsync_acl_initializer;
00161         errfun = "sys_acl_get_entry";
00162         for (rc = sys_acl_get_entry(sacl, SMB_ACL_FIRST_ENTRY, &entry);
00163              rc == 1;
00164              rc = sys_acl_get_entry(sacl, SMB_ACL_NEXT_ENTRY, &entry)) {
00165                 SMB_ACL_TAG_T tag_type;
00166                 SMB_ACL_PERMSET_T permset;
00167                 uchar access;
00168                 void *qualifier;
00169                 id_access *ida;
00170                 ida_list *idal;
00171                 if ((rc = sys_acl_get_tag_type(entry, &tag_type))) {
00172                         errfun = "sys_acl_get_tag_type";
00173                         break;
00174                 }
00175                 if ((rc = sys_acl_get_permset(entry, &permset))) {
00176                         errfun = "sys_acl_get_tag_type";
00177                         break;
00178                 }
00179                 access = (sys_acl_get_perm(permset, SMB_ACL_READ) ? 4 : 0)
00180                        | (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? 2 : 0)
00181                        | (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? 1 : 0);
00182                 /* continue == done with entry; break == store in given idal */
00183                 switch (tag_type) {
00184                 case SMB_ACL_USER_OBJ:
00185                         if (racl->user_obj == ACL_NO_ENTRY)
00186                                 racl->user_obj = access;
00187                         else
00188                                 rprintf(FINFO, "unpack_smb_acl: warning: duplicate USER_OBJ entry ignored\n");
00189                         continue;
00190                 case SMB_ACL_USER:
00191                         idal = &racl->users;
00192                         break;
00193                 case SMB_ACL_GROUP_OBJ:
00194                         if (racl->group_obj == ACL_NO_ENTRY)
00195                                 racl->group_obj = access;
00196                         else
00197                                 rprintf(FINFO, "unpack_smb_acl: warning: duplicate GROUP_OBJ entry ignored\n");
00198                         continue;
00199                 case SMB_ACL_GROUP:
00200                         idal = &racl->groups;
00201                         break;
00202                 case SMB_ACL_MASK:
00203                         if (racl->mask == ACL_NO_ENTRY)
00204                                 racl->mask = access;
00205                         else
00206                                 rprintf(FINFO, "unpack_smb_acl: warning: duplicate MASK entry ignored\n");
00207                         continue;
00208                 case SMB_ACL_OTHER:
00209                         if (racl->other == ACL_NO_ENTRY)
00210                                 racl->other = access;
00211                         else
00212                                 rprintf(FINFO, "unpack_smb_acl: warning: duplicate OTHER entry ignored\n");
00213                         continue;
00214                 default:
00215                         rprintf(FINFO, "unpack_smb_acl: warning: entry with unrecognized tag type ignored\n");
00216                         continue;
00217                 }
00218                 if (!(qualifier = sys_acl_get_qualifier(entry))) {
00219                         errfun = "sys_acl_get_tag_type";
00220                         rc = EINVAL;
00221                         break;
00222                 }
00223                 expand_ida_list(idal);
00224                 ida = &idal->idas[idal->count++];
00225                 ida->id = *((id_t *)qualifier);
00226                 ida->access = access;
00227                 sys_acl_free_qualifier(qualifier, tag_type);
00228         }
00229         if (rc) {
00230                 rprintf(FERROR, "unpack_smb_acl: %s(): %s\n",
00231                         errfun, strerror(errno));
00232                 rsync_acl_free(racl);
00233                 return False;
00234         }
00235 
00236         sort_ida_list(&racl->users);
00237         sort_ida_list(&racl->groups);
00238 
00239         return True;
00240 }
00241 
00242 static BOOL ida_lists_equal(const ida_list *ial1, const ida_list *ial2)
00243 {
00244         id_access *ida1, *ida2;
00245         size_t count = ial1->count;
00246         if (count != ial2->count)
00247                 return False;
00248         ida1 = ial1->idas;
00249         ida2 = ial2->idas;
00250         for (; count--; ida1++, ida2++) {
00251                 if (ida1->access != ida2->access || ida1->id != ida2->id)
00252                         return False;
00253         }
00254         return True;
00255 }
00256 
00257 static BOOL rsync_acls_equal(const rsync_acl *racl1, const rsync_acl *racl2)
00258 {
00259         return (racl1->user_obj == racl2->user_obj
00260              && racl1->group_obj == racl2->group_obj
00261              && racl1->mask == racl2->mask
00262              && racl1->other == racl2->other
00263              && ida_lists_equal(&racl1->users, &racl2->users)
00264              && ida_lists_equal(&racl1->groups, &racl2->groups));
00265 }
00266 
00267 static BOOL rsync_acl_extended_parts_equal(const rsync_acl *racl1, const rsync_acl *racl2)
00268 {
00269         /* We ignore any differences that chmod() can take care of. */
00270         if ((racl1->mask ^ racl2->mask) & ACL_NO_ENTRY)
00271                 return False;
00272         if (racl1->mask != ACL_NO_ENTRY && racl1->group_obj != racl2->group_obj)
00273                 return False;
00274         return ida_lists_equal(&racl1->users, &racl2->users)
00275             && ida_lists_equal(&racl1->groups, &racl2->groups);
00276 }
00277 
00278 typedef struct {
00279         size_t count;
00280         size_t malloced;
00281         rsync_acl *racls;
00282 } rsync_acl_list;
00283 
00284 static rsync_acl_list _rsync_acl_lists[] = {
00285         { 0, 0, NULL }, /* SMB_ACL_TYPE_ACCESS */
00286         { 0, 0, NULL }  /* SMB_ACL_TYPE_DEFAULT */
00287 };
00288 
00289 static inline rsync_acl_list *rsync_acl_lists(SMB_ACL_TYPE_T type)
00290 {
00291         return &_rsync_acl_lists[type != SMB_ACL_TYPE_ACCESS];
00292 }
00293 
00294 static void expand_rsync_acl_list(rsync_acl_list *racl_list)
00295 {
00296         /* First time through, 0 <= 0, so list is expanded. */
00297         if (racl_list->malloced <= racl_list->count) {
00298                 rsync_acl *new_ptr;
00299                 size_t new_size;
00300                 if (racl_list->malloced < 1000)
00301                         new_size = racl_list->malloced + 1000;
00302                 else
00303                         new_size = racl_list->malloced * 2;
00304                 new_ptr = realloc_array(racl_list->racls, rsync_acl, new_size);
00305                 if (verbose >= 3) {
00306                         rprintf(FINFO, "expand_rsync_acl_list to %.0f bytes, did%s move\n",
00307                                 (double) new_size * sizeof racl_list->racls[0],
00308                                 racl_list->racls ? "" : " not");
00309                 }
00310 
00311                 racl_list->racls = new_ptr;
00312                 racl_list->malloced = new_size;
00313 
00314                 if (!racl_list->racls)
00315                         out_of_memory("expand_rsync_acl_list");
00316         }
00317 }
00318 
00319 static int find_matching_rsync_acl(SMB_ACL_TYPE_T type,
00320                                    const rsync_acl_list *racl_list,
00321                                    const rsync_acl *racl)
00322 {
00323         static int access_match = -1, default_match = -1;
00324         int *match = type == SMB_ACL_TYPE_ACCESS ? &access_match : &default_match;
00325         size_t count = racl_list->count;
00326 
00327         /* If this is the first time through or we didn't match the last
00328          * time, then start at the end of the list, which should be the
00329          * best place to start hunting. */
00330         if (*match == -1)
00331                 *match = racl_list->count - 1;
00332         while (count--) {
00333                 if (rsync_acls_equal(&racl_list->racls[*match], racl))
00334                         return *match;
00335                 if (!(*match)--)
00336                         *match = racl_list->count - 1;
00337         }
00338 
00339         *match = -1;
00340         return *match;
00341 }
00342 
00343 /* The general strategy with the tag_type <-> character mapping is that
00344  * lowercase implies that no qualifier follows, where uppercase does.
00345  * A similar idiom for the acl type (access or default) itself, but
00346  * lowercase in this instance means there's no ACL following, so the
00347  * ACL is a repeat, so the receiver should reuse the last of the same
00348  * type ACL. */
00349 static void send_ida_list(int f, const ida_list *idal, char tag_char)
00350 {
00351         id_access *ida;
00352         size_t count = idal->count;
00353         for (ida = idal->idas; count--; ida++) {
00354                 write_byte(f, tag_char);
00355                 write_byte(f, ida->access);
00356                 write_int(f, ida->id);
00357                 /* FIXME: sorta wasteful: we should maybe buffer as
00358                  * many ids as max(ACL_USER + ACL_GROUP) objects to
00359                  * keep from making so many calls. */
00360                 if (tag_char == 'U')
00361                         add_uid(ida->id);
00362                 else
00363                         add_gid(ida->id);
00364         }
00365 }
00366 
00367 static void send_rsync_acl(int f, const rsync_acl *racl)
00368 {
00369         size_t count = count_racl_entries(racl);
00370         write_int(f, count);
00371         if (racl->user_obj != ACL_NO_ENTRY) {
00372                 write_byte(f, 'u');
00373                 write_byte(f, racl->user_obj);
00374         }
00375         send_ida_list(f, &racl->users, 'U');
00376         if (racl->group_obj != ACL_NO_ENTRY) {
00377                 write_byte(f, 'g');
00378                 write_byte(f, racl->group_obj);
00379         }
00380         send_ida_list(f, &racl->groups, 'G');
00381         if (racl->mask != ACL_NO_ENTRY) {
00382                 write_byte(f, 'm');
00383                 write_byte(f, racl->mask);
00384         }
00385         if (racl->other != ACL_NO_ENTRY) {
00386                 write_byte(f, 'o');
00387                 write_byte(f, racl->other);
00388         }
00389 }
00390 
00391 static rsync_acl _curr_rsync_acls[2];
00392 
00393 static const char *str_acl_type(SMB_ACL_TYPE_T type)
00394 {
00395         return type == SMB_ACL_TYPE_ACCESS ? "SMB_ACL_TYPE_ACCESS"
00396              : type == SMB_ACL_TYPE_DEFAULT ? "SMB_ACL_TYPE_DEFAULT"
00397              : "unknown SMB_ACL_TYPE_T";
00398 }
00399 
00400 /* Generate the ACL(s) for this flist entry;
00401  * ACL(s) are either sent or cleaned-up by send_acl() below. */
00402 int make_acl(const struct file_struct *file, const char *fname)
00403 {
00404         SMB_ACL_TYPE_T type;
00405         rsync_acl *curr_racl;
00406 
00407         if (S_ISLNK(file->mode))
00408                 return 1;
00409 
00410         curr_racl = &_curr_rsync_acls[0];
00411         type = SMB_ACL_TYPE_ACCESS;
00412         do {
00413                 SMB_ACL_T sacl;
00414                 BOOL ok;
00415                 if ((sacl = sys_acl_get_file(fname, type)) != 0) {
00416                         ok = unpack_smb_acl(curr_racl, sacl);
00417                         sys_acl_free_acl(sacl);
00418                         if (!ok)
00419                                 return -1;
00420                         /* Avoid sending a redundant group/mask value. */
00421                         if (curr_racl->group_obj == curr_racl->mask
00422                          && (preserve_acls == 1
00423                           || (!curr_racl->users.count
00424                            && !curr_racl->groups.count)))
00425                                 curr_racl->mask = ACL_NO_ENTRY;
00426                         /* Strip access ACLs of permission-bit entries. */
00427                         if (type == SMB_ACL_TYPE_ACCESS && preserve_acls == 1)
00428                                 rsync_acl_strip_perms(curr_racl);
00429                 } else if (errno == ENOTSUP) {
00430                         /* ACLs are not supported. Leave list empty. */
00431                         *curr_racl = rsync_acl_initializer;
00432                 } else {
00433                         rprintf(FERROR, "send_acl: sys_acl_get_file(%s, %s): %s\n",
00434                                 fname, str_acl_type(type), strerror(errno));
00435                         return -1;
00436                 }
00437                 curr_racl++;
00438         } while (BUMP_TYPE(type) && S_ISDIR(file->mode));
00439 
00440         return 0;
00441 }
00442 
00443 /* Send the make_acl()-generated ACLs for this flist entry,
00444  * or clean up after an flist entry that's not being sent (f == -1). */
00445 void send_acl(const struct file_struct *file, int f)
00446 {
00447         SMB_ACL_TYPE_T type;
00448         rsync_acl *curr_racl;
00449 
00450         if (S_ISLNK(file->mode))
00451                 return;
00452 
00453         curr_racl = &_curr_rsync_acls[0];
00454         type = SMB_ACL_TYPE_ACCESS;
00455         do {
00456                 int index;
00457                 rsync_acl_list *racl_list = rsync_acl_lists(type);
00458                 if (f == -1) {
00459                         rsync_acl_free(curr_racl);
00460                         continue;
00461                 }
00462                 if ((index = find_matching_rsync_acl(type, racl_list, curr_racl))
00463                     != -1) {
00464                         write_byte(f, type == SMB_ACL_TYPE_ACCESS ? 'a' : 'd');
00465                         write_int(f, index);
00466                         rsync_acl_free(curr_racl);
00467                 } else {
00468                         write_byte(f, type == SMB_ACL_TYPE_ACCESS ? 'A' : 'D');
00469                         send_rsync_acl(f, curr_racl);
00470                         expand_rsync_acl_list(racl_list);
00471                         racl_list->racls[racl_list->count++] = *curr_racl;
00472                 }
00473                 curr_racl++;
00474         } while (BUMP_TYPE(type) && S_ISDIR(file->mode));
00475 }
00476 
00477 /* The below stuff is only used by the receiver: */
00478 
00479 /* structure to hold index to rsync_acl_list member corresponding to
00480  * flist->files[i] */
00481 
00482 typedef struct {
00483         const struct file_struct *file;
00484         int aclidx;
00485 } file_acl_index;
00486 
00487 typedef struct {
00488         size_t count;
00489         size_t malloced;
00490         file_acl_index *fais;
00491 } file_acl_index_list;
00492 
00493 static file_acl_index_list _file_acl_index_lists[] = {
00494         {0, 0, NULL }, /* SMB_ACL_TYPE_ACCESS */
00495         {0, 0, NULL }  /* SMB_ACL_TYPE_DEFAULT */
00496 };
00497 
00498 static inline file_acl_index_list *file_acl_index_lists(SMB_ACL_TYPE_T type)
00499 {
00500         return &_file_acl_index_lists[type != SMB_ACL_TYPE_ACCESS];
00501 }
00502 
00503 static void expand_file_acl_index_list(file_acl_index_list *flst)
00504 {
00505         /* First time through, 0 <= 0, so list is expanded. */
00506         if (flst->malloced <= flst->count) {
00507                 file_acl_index *new_ptr;
00508                 size_t new_size;
00509 
00510                 if (flst->malloced < 1000)
00511                         new_size = flst->malloced + 1000;
00512                 else
00513                         new_size = flst->malloced * 2;
00514                 new_ptr = realloc_array(flst->fais, file_acl_index, new_size);
00515                 if (verbose >= 3) {
00516                         rprintf(FINFO, "expand_file_acl_index_list to %.0f bytes, did%s move\n",
00517                                 (double) new_size * sizeof flst->fais[0],
00518                                 flst->fais ? "" : " not");
00519                 }
00520 
00521                 flst->fais = new_ptr;
00522                 flst->malloced = new_size;
00523 
00524                 if (!flst->fais)
00525                         out_of_memory("expand_file_acl_index_list");
00526         }
00527 }
00528 
00529 /* lists to hold the SMB_ACL_Ts corresponding to the rsync_acl_list entries */
00530 
00531 typedef struct {
00532         size_t count;
00533         size_t malloced;
00534         SMB_ACL_T *sacls;
00535 } smb_acl_list;
00536 
00537 static smb_acl_list _smb_acl_lists[] = {
00538         { 0, 0, NULL }, /* SMB_ACL_TYPE_ACCESS */
00539         { 0, 0, NULL }  /* SMB_ACL_TYPE_DEFAULT */
00540 };
00541 
00542 static inline smb_acl_list *smb_acl_lists(SMB_ACL_TYPE_T type)
00543 {
00544         return &_smb_acl_lists[type != SMB_ACL_TYPE_ACCESS];
00545 }
00546 
00547 static void expand_smb_acl_list(smb_acl_list *sacl_list)
00548 {
00549         /* First time through, 0 <= 0, so list is expanded. */
00550         if (sacl_list->malloced <= sacl_list->count) {
00551                 SMB_ACL_T *new_ptr;
00552                 size_t new_size;
00553                 if (sacl_list->malloced < 1000)
00554                         new_size = sacl_list->malloced + 1000;
00555                 else
00556                         new_size = sacl_list->malloced * 2;
00557                 new_ptr = realloc_array(sacl_list->sacls, SMB_ACL_T, new_size);
00558                 if (verbose >= 3) {
00559                         rprintf(FINFO, "expand_smb_acl_list to %.0f bytes, did%s move\n",
00560                                 (double) new_size * sizeof sacl_list->sacls[0],
00561                                 sacl_list->sacls ? "" : " not");
00562                 }
00563 
00564                 sacl_list->sacls = new_ptr;
00565                 sacl_list->malloced = new_size;
00566 
00567                 if (!sacl_list->sacls)
00568                         out_of_memory("expand_smb_acl_list");
00569         }
00570 }
00571 
00572 #define CALL_OR_ERROR(func,args,str) \
00573         do { \
00574                 if (func args) { \
00575                         errfun = str; \
00576                         goto error_exit; \
00577                 } \
00578         } while (0)
00579 
00580 #define COE(func,args) CALL_OR_ERROR(func,args,#func)
00581 #define COE2(func,args) CALL_OR_ERROR(func,args,NULL)
00582 
00583 static int store_access_in_entry(uchar access, SMB_ACL_ENTRY_T entry)
00584 {
00585         const char *errfun = NULL;
00586         SMB_ACL_PERMSET_T permset;
00587 
00588         COE( sys_acl_get_permset,(entry, &permset) );
00589         COE( sys_acl_clear_perms,(permset) );
00590         if (access & 4)
00591                 COE( sys_acl_add_perm,(permset, SMB_ACL_READ) );
00592         if (access & 2)
00593                 COE( sys_acl_add_perm,(permset, SMB_ACL_WRITE) );
00594         if (access & 1)
00595                 COE( sys_acl_add_perm,(permset, SMB_ACL_EXECUTE) );
00596         COE( sys_acl_set_permset,(entry, permset) );
00597 
00598         return 0;
00599 
00600   error_exit:
00601         rprintf(FERROR, "store_access_in_entry %s(): %s\n", errfun,
00602                 strerror(errno));
00603         return -1;
00604 }
00605 
00606 /* build an SMB_ACL_T corresponding to an rsync_acl */
00607 static BOOL pack_smb_acl(SMB_ACL_T *smb_acl, const rsync_acl *racl)
00608 {
00609         size_t count;
00610         id_access *ida;
00611         const char *errfun = NULL;
00612         SMB_ACL_ENTRY_T entry;
00613 
00614         if (!(*smb_acl = sys_acl_init(calc_sacl_entries(racl)))) {
00615                 rprintf(FERROR, "pack_smb_acl: sys_acl_init(): %s\n",
00616                         strerror(errno));
00617                 return False;
00618         }
00619 
00620         COE( sys_acl_create_entry,(smb_acl, &entry) );
00621         COE( sys_acl_set_tag_type,(entry, SMB_ACL_USER_OBJ) );
00622         COE2( store_access_in_entry,(racl->user_obj & 7, entry) );
00623 
00624         for (ida = racl->users.idas, count = racl->users.count;
00625              count--; ida++) {
00626                 COE( sys_acl_create_entry,(smb_acl, &entry) );
00627                 COE( sys_acl_set_tag_type,(entry, SMB_ACL_USER) );
00628                 COE( sys_acl_set_qualifier,(entry, (void*)&ida->id) );
00629                 COE2( store_access_in_entry,(ida->access, entry) );
00630         }
00631 
00632         COE( sys_acl_create_entry,(smb_acl, &entry) );
00633         COE( sys_acl_set_tag_type,(entry, SMB_ACL_GROUP_OBJ) );
00634         COE2( store_access_in_entry,(racl->group_obj & 7, entry) );
00635 
00636         for (ida = racl->groups.idas, count = racl->groups.count;
00637              count--; ida++) {
00638                 COE( sys_acl_create_entry,(smb_acl, &entry) );
00639                 COE( sys_acl_set_tag_type,(entry, SMB_ACL_GROUP) );
00640                 COE( sys_acl_set_qualifier,(entry, (void*)&ida->id) );
00641                 COE2( store_access_in_entry,(ida->access, entry) );
00642         }
00643 #ifndef ACLS_NEED_MASK
00644         if (racl->mask != ACL_NO_ENTRY) {
00645 #endif
00646                 COE( sys_acl_create_entry,(smb_acl, &entry) );
00647                 COE( sys_acl_set_tag_type,(entry, SMB_ACL_MASK) );
00648                 COE2( store_access_in_entry,(racl->mask, entry) );
00649 #ifndef ACLS_NEED_MASK
00650         }
00651 #endif
00652 
00653         COE( sys_acl_create_entry,(smb_acl, &entry) );
00654         COE( sys_acl_set_tag_type,(entry, SMB_ACL_OTHER) );
00655         COE2( store_access_in_entry,(racl->other & 7, entry) );
00656 
00657 #ifdef DEBUG
00658         if (sys_acl_valid(*smb_acl) < 0)
00659                 rprintf(FINFO, "pack_smb_acl: warning: system says the ACL I packed is invalid\n");
00660 #endif
00661 
00662         return True;
00663 
00664   error_exit:
00665         if (errfun) {
00666                 rprintf(FERROR, "pack_smb_acl %s(): %s\n", errfun,
00667                         strerror(errno));
00668         }
00669         sys_acl_free_acl(*smb_acl);
00670         return False;
00671 }
00672 
00673 static mode_t change_sacl_perms(SMB_ACL_T sacl, rsync_acl *racl, mode_t old_mode, mode_t mode)
00674 {
00675         SMB_ACL_ENTRY_T entry;
00676         const char *errfun;
00677         int rc;
00678 
00679         if (S_ISDIR(mode)) {
00680                 /* If the sticky bit is going on, it's not safe to allow all
00681                  * the new ACLs to go into effect before it gets set. */
00682 #ifdef SMB_ACL_LOSES_SPECIAL_MODE_BITS
00683                 if (mode & S_ISVTX)
00684                         mode &= ~0077;
00685 #else
00686                 if (mode & S_ISVTX && !(old_mode & S_ISVTX))
00687                         mode &= ~0077;
00688         } else {
00689                 /* If setuid or setgid is going off, it's not safe to allow all
00690                  * the new ACLs to go into effect before they get cleared. */
00691                 if ((old_mode & S_ISUID && !(mode & S_ISUID))
00692                  || (old_mode & S_ISGID && !(mode & S_ISGID)))
00693                         mode &= ~0077;
00694 #endif
00695         }
00696 
00697         errfun = "sys_acl_get_entry";
00698         for (rc = sys_acl_get_entry(sacl, SMB_ACL_FIRST_ENTRY, &entry);
00699              rc == 1;
00700              rc = sys_acl_get_entry(sacl, SMB_ACL_NEXT_ENTRY, &entry)) {
00701                 SMB_ACL_TAG_T tag_type;
00702                 if ((rc = sys_acl_get_tag_type(entry, &tag_type))) {
00703                         errfun = "sys_acl_get_tag_type";
00704                         break;
00705                 }
00706                 switch (tag_type) {
00707                 case SMB_ACL_USER_OBJ:
00708                         COE2( store_access_in_entry,((mode >> 6) & 7, entry) );
00709                         break;
00710                 case SMB_ACL_GROUP_OBJ:
00711                         /* group is only empty when identical to group perms. */
00712                         if (racl->group_obj != ACL_NO_ENTRY)
00713                                 break;
00714                         COE2( store_access_in_entry,((mode >> 3) & 7, entry) );
00715                         break;
00716                 case SMB_ACL_MASK:
00717 #ifndef ACLS_NEED_MASK
00718                         /* mask is only empty when we don't need it. */
00719                         if (racl->mask == ACL_NO_ENTRY)
00720                                 break;
00721 #endif
00722                         COE2( store_access_in_entry,((mode >> 3) & 7, entry) );
00723                         break;
00724                 case SMB_ACL_OTHER:
00725                         COE2( store_access_in_entry,(mode & 7, entry) );
00726                         break;
00727                 }
00728         }
00729         if (rc) {
00730           error_exit:
00731                 if (errfun) {
00732                         rprintf(FERROR, "change_sacl_perms: %s(): %s\n",
00733                                 errfun, strerror(errno));
00734                 }
00735                 return ~0u;
00736         }
00737 
00738 #ifdef SMB_ACL_LOSES_SPECIAL_MODE_BITS
00739         /* Ensure that chmod() will be called to restore any lost setid bits. */
00740         if (old_mode & (S_ISUID | S_ISGID | S_ISVTX)
00741          && (old_mode & CHMOD_BITS) == (mode & CHMOD_BITS))
00742                 old_mode &= ~(S_ISUID | S_ISGID | S_ISVTX);
00743 #endif
00744 
00745         /* Return the mode of the file on disk, as we will set them. */
00746         return (old_mode & ~ACCESSPERMS) | (mode & ACCESSPERMS);
00747 }
00748 
00749 static void receive_rsync_acl(rsync_acl *racl, int f, SMB_ACL_TYPE_T type)
00750 {
00751         uchar computed_mask_bits = 0;
00752         ida_list *idal = NULL;
00753         id_access *ida;
00754         size_t count;
00755 
00756         *racl = rsync_acl_initializer;
00757 
00758         if (!(count = read_int(f)))
00759                 return;
00760 
00761         while (count--) {
00762                 char tag = read_byte(f);
00763                 uchar access = read_byte(f);
00764                 if (access & ~ (4 | 2 | 1)) {
00765                         rprintf(FERROR, "receive_rsync_acl: bogus permset %o\n",
00766                                 access);
00767                         exit_cleanup(RERR_STREAMIO);
00768                 }
00769                 switch (tag) {
00770                 case 'u':
00771                         if (racl->user_obj != ACL_NO_ENTRY) {
00772                                 rprintf(FERROR, "receive_rsync_acl: error: duplicate USER_OBJ entry\n");
00773                                 exit_cleanup(RERR_STREAMIO);
00774                         }
00775                         racl->user_obj = access;
00776                         continue;
00777                 case 'U':
00778                         idal = &racl->users;
00779                         break;
00780                 case 'g':
00781                         if (racl->group_obj != ACL_NO_ENTRY) {
00782                                 rprintf(FERROR, "receive_rsync_acl: error: duplicate GROUP_OBJ entry\n");
00783                                 exit_cleanup(RERR_STREAMIO);
00784                         }
00785                         racl->group_obj = access;
00786                         continue;
00787                 case 'G':
00788                         idal = &racl->groups;
00789                         break;
00790                 case 'm':
00791                         if (racl->mask != ACL_NO_ENTRY) {
00792                                 rprintf(FERROR, "receive_rsync_acl: error: duplicate MASK entry\n");
00793                                 exit_cleanup(RERR_STREAMIO);
00794                         }
00795                         racl->mask = access;
00796                         continue;
00797                 case 'o':
00798                         if (racl->other != ACL_NO_ENTRY) {
00799                                 rprintf(FERROR, "receive_rsync_acl: error: duplicate OTHER entry\n");
00800                                 exit_cleanup(RERR_STREAMIO);
00801                         }
00802                         racl->other = access;
00803                         continue;
00804                 default:
00805                         rprintf(FERROR, "receive_rsync_acl: unknown tag %c\n",
00806                                 tag);
00807                         exit_cleanup(RERR_STREAMIO);
00808                 }
00809                 expand_ida_list(idal);
00810                 ida = &idal->idas[idal->count++];
00811                 ida->access = access;
00812                 ida->id = read_int(f);
00813                 computed_mask_bits |= access;
00814         }
00815 
00816         if (type == SMB_ACL_TYPE_DEFAULT) {
00817                 /* Ensure that these are never unset. */
00818                 if (racl->user_obj == ACL_NO_ENTRY)
00819                         racl->user_obj = 7;
00820                 if (racl->group_obj == ACL_NO_ENTRY)
00821                         racl->group_obj = 0;
00822                 if (racl->other == ACL_NO_ENTRY)
00823                         racl->other = 0;
00824         }
00825 #ifndef ACLS_NEED_MASK
00826         if (!racl->users.count && !racl->groups.count) {
00827                 /* If we, a system without ACLS_NEED_MASK, received a
00828                  * superfluous mask, throw it away. */
00829                 if (racl->mask != ACL_NO_ENTRY) {
00830                         /* mask off group perms with it first */
00831                         racl->group_obj &= racl->mask | ACL_NO_ENTRY;
00832                         racl->mask = ACL_NO_ENTRY;
00833                 }
00834         } else
00835 #endif
00836         if (racl->mask == ACL_NO_ENTRY) /* Always non-empty when needed. */
00837                 racl->mask = computed_mask_bits | (racl->group_obj & 7);
00838 }
00839 
00840 /* receive and build the rsync_acl_lists */
00841 void receive_acl(struct file_struct *file, int f)
00842 {
00843         SMB_ACL_TYPE_T type;
00844         char *fname;
00845 
00846         if (S_ISLNK(file->mode))
00847                 return;
00848 
00849         fname = f_name(file, NULL);
00850         type = SMB_ACL_TYPE_ACCESS;
00851         do {
00852                 char tag;
00853                 file_acl_index_list *flst = file_acl_index_lists(type);
00854 
00855                 expand_file_acl_index_list(flst);
00856 
00857                 tag = read_byte(f);
00858                 if (tag == 'A' || tag == 'a') {
00859                         if (type != SMB_ACL_TYPE_ACCESS) {
00860                                 rprintf(FERROR, "receive_acl %s: duplicate access ACL\n",
00861                                         fname);
00862                                 exit_cleanup(RERR_STREAMIO);
00863                         }
00864                 } else if (tag == 'D' || tag == 'd') {
00865                         if (type == SMB_ACL_TYPE_ACCESS) {
00866                                 rprintf(FERROR, "receive_acl %s: expecting access ACL; got default\n",
00867                                         fname);
00868                                 exit_cleanup(RERR_STREAMIO);
00869                         }
00870                 } else {
00871                         rprintf(FERROR, "receive_acl %s: unknown ACL type tag: %c\n",
00872                                 fname, tag);
00873                         exit_cleanup(RERR_STREAMIO);
00874                 }
00875                 if (tag == 'A' || tag == 'D') {
00876                         rsync_acl racl;
00877                         rsync_acl_list *racl_list = rsync_acl_lists(type);
00878                         smb_acl_list *sacl_list = smb_acl_lists(type);
00879                         flst->fais[flst->count].aclidx = racl_list->count;
00880                         flst->fais[flst->count++].file = file;
00881                         receive_rsync_acl(&racl, f, type);
00882                         expand_rsync_acl_list(racl_list);
00883                         racl_list->racls[racl_list->count++] = racl;
00884                         expand_smb_acl_list(sacl_list);
00885                         sacl_list->sacls[sacl_list->count++] = NULL;
00886                 } else {
00887                         int index = read_int(f);
00888                         rsync_acl_list *racl_list = rsync_acl_lists(type);
00889                         if ((size_t) index >= racl_list->count) {
00890                                 rprintf(FERROR, "receive_acl %s: %s ACL index %d out of range\n",
00891                                         fname,
00892                                         str_acl_type(type),
00893                                         index);
00894                                 exit_cleanup(RERR_STREAMIO);
00895                         }
00896                         flst->fais[flst->count].aclidx = index;
00897                         flst->fais[flst->count++].file = file;
00898                 }
00899         } while (BUMP_TYPE(type) && S_ISDIR(file->mode));
00900 }
00901 
00902 static int file_acl_index_list_sorter(const void *f1, const void *f2)
00903 {
00904         const file_acl_index *fileaclidx1 = (const file_acl_index *)f1;
00905         const file_acl_index *fileaclidx2 = (const file_acl_index *)f2;
00906         return fileaclidx1->file == fileaclidx2->file ? 0
00907              : fileaclidx1->file < fileaclidx2->file ? -1 : 1;
00908 }
00909 
00910 void sort_file_acl_index_lists()
00911 {
00912         SMB_ACL_TYPE_T type;
00913 
00914         type = SMB_ACL_TYPE_ACCESS;
00915         do {
00916                 file_acl_index_list *flst = file_acl_index_lists(type);
00917 
00918                 if (!flst->count)
00919                         continue;
00920 
00921                 qsort(flst->fais, flst->count, sizeof flst->fais[0],
00922                       &file_acl_index_list_sorter);
00923         } while (BUMP_TYPE(type));
00924 }
00925 
00926 static int find_file_acl_index(const file_acl_index_list *flst,
00927                                const struct file_struct *file)
00928 {
00929         int low = 0, high = flst->count;
00930         const struct file_struct *file_mid;
00931 
00932         if (!high--)
00933                 return -1;
00934         do {
00935                 int mid = (high + low) / 2;
00936                 file_mid = flst->fais[mid].file;
00937                 if (file_mid == file)
00938                         return flst->fais[mid].aclidx;
00939                 if (file_mid > file)
00940                         high = mid - 1;
00941                 else
00942                         low = mid + 1;
00943         } while (low < high);
00944         if (low == high) {
00945                 file_mid = flst->fais[low].file;
00946                 if (file_mid == file)
00947                         return flst->fais[low].aclidx;
00948         }
00949         rprintf(FERROR,
00950                 "find_file_acl_index: can't find entry for file in list\n");
00951         exit_cleanup(RERR_STREAMIO);
00952         return -1;
00953 }
00954 
00955 /* for duplicating ACLs on backups when using backup_dir */
00956 int dup_acl(const char *orig, const char *bak, mode_t mode)
00957 {
00958         SMB_ACL_TYPE_T type;
00959         int ret = 0;
00960 
00961         type = SMB_ACL_TYPE_ACCESS;
00962         do {
00963                 SMB_ACL_T sacl_orig, sacl_bak;
00964                 rsync_acl racl_orig, racl_bak;
00965                 if (!(sacl_orig = sys_acl_get_file(orig, type))) {
00966                         rprintf(FERROR, "dup_acl: sys_acl_get_file(%s, %s): %s\n",
00967                                 orig, str_acl_type(type), strerror(errno));
00968                         ret = -1;
00969                         continue;
00970                 }
00971                 if (!(sacl_bak = sys_acl_get_file(orig, type))) {
00972                         rprintf(FERROR, "dup_acl: sys_acl_get_file(%s, %s): %s. ignoring\n",
00973                                 bak, str_acl_type(type), strerror(errno));
00974                         ret = -1;
00975                         /* try to forge on through */
00976                 }
00977                 if (!unpack_smb_acl(&racl_orig, sacl_orig)) {
00978                         ret = -1;
00979                         goto out_with_sacls;
00980                 }
00981                 if (sacl_bak) {
00982                         if (!unpack_smb_acl(&racl_bak, sacl_bak)) {
00983                                 ret = -1;
00984                                 goto out_with_one_racl;
00985                         }
00986                         if (rsync_acls_equal(&racl_orig, &racl_bak))
00987                                 goto out_with_all;
00988                 } else {
00989                         ; /* presume they're unequal */
00990                 }
00991                 if (type == SMB_ACL_TYPE_DEFAULT
00992                  && racl_orig.user_obj == ACL_NO_ENTRY) {
00993                         if (sys_acl_delete_def_file(bak) < 0) {
00994                                 rprintf(FERROR, "dup_acl: sys_acl_delete_def_file(%s): %s\n",
00995                                         bak, strerror(errno));
00996                                 ret = -1;
00997                         }
00998                 } else if (sys_acl_set_file(bak, type, sacl_bak) < 0) {
00999                         rprintf(FERROR, "dup_acl: sys_acl_set_file(%s, %s): %s\n",
01000                                 bak, str_acl_type(type), strerror(errno));
01001                         ret = -1;
01002                 }
01003                 out_with_all:
01004                         if (sacl_bak)
01005                                 rsync_acl_free(&racl_bak);
01006                 out_with_one_racl:
01007                         rsync_acl_free(&racl_orig);
01008                 out_with_sacls:
01009                         if (sacl_bak)
01010                                 sys_acl_free_acl(sacl_bak);
01011                 /* out_with_one_sacl: */
01012                         if (sacl_orig)
01013                                 sys_acl_free_acl(sacl_orig);
01014         } while (BUMP_TYPE(type) && S_ISDIR(mode));
01015 
01016         return ret;
01017 }
01018 
01019 /* Stuff for redirecting calls to set_acl() from set_file_attrs()
01020  * for keep_backup(). */
01021 static const struct file_struct *backup_orig_file = NULL;
01022 static const char null_string[] = "";
01023 static const char *backup_orig_fname = null_string;
01024 static const char *backup_dest_fname = null_string;
01025 static SMB_ACL_T _backup_sacl[] = { NULL, NULL };
01026 
01027 void push_keep_backup_acl(const struct file_struct *file,
01028                           const char *orig, const char *dest)
01029 {
01030         SMB_ACL_TYPE_T type;
01031         SMB_ACL_T *sacl;
01032 
01033         backup_orig_file = file;
01034         backup_orig_fname = orig;
01035         backup_dest_fname = dest;
01036 
01037         sacl = &_backup_sacl[0];
01038         type = SMB_ACL_TYPE_ACCESS;
01039         do {
01040                 if (type == SMB_ACL_TYPE_DEFAULT && !S_ISDIR(file->mode)) {
01041                         *sacl = NULL;
01042                         break;
01043                 }
01044                 if (!(*sacl = sys_acl_get_file(orig, type))) {
01045                         rprintf(FERROR,
01046                                 "push_keep_backup_acl: sys_acl_get_file(%s, %s): %s\n",
01047                                 orig, str_acl_type(type),
01048                                 strerror(errno));
01049                 }
01050         } while (BUMP_TYPE(type));
01051 }
01052 
01053 static int set_keep_backup_acl()
01054 {
01055         SMB_ACL_TYPE_T type;
01056         SMB_ACL_T *sacl;
01057         int ret = 0;
01058 
01059         sacl = &_backup_sacl[0];
01060         type = SMB_ACL_TYPE_ACCESS;
01061         do {
01062                 if (*sacl
01063                  && sys_acl_set_file(backup_dest_fname, type, *sacl) < 0) {
01064                         rprintf(FERROR,
01065                                 "push_keep_backup_acl: sys_acl_get_file(%s, %s): %s\n",
01066                                 backup_dest_fname,
01067                                 str_acl_type(type),
01068                                 strerror(errno));
01069                         ret = -1;
01070                 }
01071         } while (BUMP_TYPE(type));
01072 
01073         return ret;
01074 }
01075 
01076 void cleanup_keep_backup_acl()
01077 {
01078         SMB_ACL_TYPE_T type;
01079         SMB_ACL_T *sacl;
01080 
01081         backup_orig_file = NULL;
01082         backup_orig_fname = null_string;
01083         backup_dest_fname = null_string;
01084 
01085         sacl = &_backup_sacl[0];
01086         type = SMB_ACL_TYPE_ACCESS;
01087         do {
01088                 if (*sacl) {
01089                         sys_acl_free_acl(*sacl);
01090                         *sacl = NULL;
01091                 }
01092         } while (BUMP_TYPE(type));
01093 }
01094 
01095 /* set ACL on rsync-ed or keep_backup-ed file
01096  *
01097  * This sets extended access ACL entries and default ACLs.  If convenient,
01098  * it sets permission bits along with the access ACLs and signals having
01099  * done so by modifying mode_p, which should point into the stat buffer.
01100  *
01101  * returns: 1 for unchanged, 0 for changed, -1 for failed
01102  * Pass NULL for mode_p to get the return code without changing anything. */
01103 int set_acl(const char *fname, const struct file_struct *file, mode_t *mode_p)
01104 {
01105         int unchanged = 1;
01106         SMB_ACL_TYPE_T type;
01107 
01108         if (S_ISLNK(file->mode))
01109                 return 1;
01110 
01111         if (file == backup_orig_file) {
01112                 if (!strcmp(fname, backup_dest_fname))
01113                         return set_keep_backup_acl();
01114         }
01115         type = SMB_ACL_TYPE_ACCESS;
01116         do {
01117                 BOOL ok;
01118                 SMB_ACL_T sacl_orig, *sacl_new;
01119                 rsync_acl racl_orig, *racl_new;
01120                 int aclidx = find_file_acl_index(file_acl_index_lists(type), file);
01121 
01122                 racl_new = &(rsync_acl_lists(type)->racls[aclidx]);
01123                 sacl_new = &(smb_acl_lists(type)->sacls[aclidx]);
01124                 sacl_orig = sys_acl_get_file(fname, type);
01125                 if (!sacl_orig) {
01126                         rprintf(FERROR, "set_acl: sys_acl_get_file(%s, %s): %s\n",
01127                                 fname, str_acl_type(type), strerror(errno));
01128                         unchanged = -1;
01129                         continue;
01130                 }
01131                 ok = unpack_smb_acl(&racl_orig, sacl_orig);
01132                 sys_acl_free_acl(sacl_orig);
01133                 if (!ok) {
01134                         unchanged = -1;
01135                         continue;
01136                 }
01137                 if (type == SMB_ACL_TYPE_ACCESS)
01138                         ok = rsync_acl_extended_parts_equal(&racl_orig, racl_new);
01139                 else
01140                         ok = rsync_acls_equal(&racl_orig, racl_new);
01141                 rsync_acl_free(&racl_orig);
01142                 if (ok)
01143                         continue;
01144                 if (!dry_run && mode_p) {
01145                         if (type == SMB_ACL_TYPE_DEFAULT
01146                          && racl_new->user_obj == ACL_NO_ENTRY) {
01147                                 if (sys_acl_delete_def_file(fname) < 0) {
01148                                         rprintf(FERROR, "set_acl: sys_acl_delete_def_file(%s): %s\n",
01149                                                 fname, strerror(errno));
01150                                         unchanged = -1;
01151                                         continue;
01152                                 }
01153                         } else {
01154                                 mode_t cur_mode = *mode_p;
01155                                 if (!*sacl_new
01156                                  && !pack_smb_acl(sacl_new, racl_new)) {
01157                                         unchanged = -1;
01158                                         continue;
01159                                 }
01160                                 if (type == SMB_ACL_TYPE_ACCESS) {
01161                                         cur_mode = change_sacl_perms(*sacl_new, racl_new,
01162                                                                      cur_mode, file->mode);
01163                                         if (cur_mode == ~0u)
01164                                                 continue;
01165                                 }
01166                                 if (sys_acl_set_file(fname, type, *sacl_new) < 0) {
01167                                         rprintf(FERROR, "set_acl: sys_acl_set_file(%s, %s): %s\n",
01168                                                 fname, str_acl_type(type),
01169                                                 strerror(errno));
01170                                         unchanged = -1;
01171                                         continue;
01172                                 }
01173                                 if (type == SMB_ACL_TYPE_ACCESS)
01174                                         *mode_p = cur_mode;
01175                         }
01176                 }
01177                 if (unchanged == 1)
01178                         unchanged = 0;
01179         } while (BUMP_TYPE(type) && S_ISDIR(file->mode));
01180 
01181         return unchanged;
01182 }
01183 
01184 /* Enumeration functions for uid mapping: */
01185 
01186 /* Context -- one and only one.  Should be cycled through once on uid
01187  * mapping and once on gid mapping. */
01188 static rsync_acl_list *_enum_racl_lists[] = {
01189         &_rsync_acl_lists[0], &_rsync_acl_lists[1], NULL
01190 };
01191 
01192 static rsync_acl_list **enum_racl_list = &_enum_racl_lists[0];
01193 static size_t enum_racl_index = 0;
01194 static size_t enum_ida_index = 0;
01195 
01196 /* This returns the next tag_type id from the given acl for the next entry,
01197  * or it returns 0 if there are no more tag_type ids in the acl. */
01198 static id_t *next_ace_id(SMB_ACL_TAG_T tag_type, const rsync_acl *racl)
01199 {
01200         const ida_list *idal = tag_type == SMB_ACL_USER ? &racl->users : &racl->groups;
01201         if (enum_ida_index < idal->count) {
01202                 id_access *ida = &idal->idas[enum_ida_index++];
01203                 return &ida->id;
01204         }
01205         enum_ida_index = 0;
01206         return NULL;
01207 }
01208 
01209 static id_t *next_acl_id(SMB_ACL_TAG_T tag_type, const rsync_acl_list *racl_list)
01210 {
01211         for (; enum_racl_index < racl_list->count; enum_racl_index++) {
01212                 rsync_acl *racl = &racl_list->racls[enum_racl_index];
01213                 id_t *id = next_ace_id(tag_type, racl);
01214                 if (id)
01215                         return id;
01216         }
01217         enum_racl_index = 0;
01218         return NULL;
01219 }
01220 
01221 static id_t *next_acl_list_id(SMB_ACL_TAG_T tag_type)
01222 {
01223         for (; *enum_racl_list; enum_racl_list++) {
01224                 id_t *id = next_acl_id(tag_type, *enum_racl_list);
01225                 if (id)
01226                         return id;
01227         }
01228         enum_racl_list = &_enum_racl_lists[0];
01229         return NULL;
01230 }
01231 
01232 id_t *next_acl_uid()
01233 {
01234         return next_acl_list_id(SMB_ACL_USER);
01235 }
01236 
01237 id_t *next_acl_gid()
01238 {
01239         return next_acl_list_id(SMB_ACL_GROUP);
01240 }
01241 
01242 int default_perms_for_dir(const char *dir)
01243 {
01244         rsync_acl racl;
01245         SMB_ACL_T sacl;
01246         BOOL ok;
01247         int perms;
01248 
01249         if (dir == NULL)
01250                 dir = ".";
01251         perms = ACCESSPERMS & ~orig_umask;
01252         /* Read the directory's default ACL.  If it has none, this will successfully return an empty ACL. */
01253         sacl = sys_acl_get_file(dir, SMB_ACL_TYPE_DEFAULT);
01254         if (sacl == NULL) {
01255                 /* Couldn't get an ACL.  Darn. */
01256                 switch (errno) {
01257                 case ENOTSUP:
01258                         /* ACLs are disabled.  We could yell at the user to turn them on, but... */
01259                         break;
01260                 case ENOENT:
01261                         if (dry_run) {
01262                                 /* We're doing a dry run, so the containing directory
01263                                  * wasn't actually created.  Don't worry about it. */
01264                                 break;
01265                         }
01266                         /* Otherwise fall through. */
01267                 default:
01268                         rprintf(FERROR, "default_perms_for_dir: sys_acl_get_file(%s, %s): %s, falling back on umask\n",
01269                                 dir, str_acl_type(SMB_ACL_TYPE_DEFAULT), strerror(errno));
01270                 }
01271                 return perms;
01272         }
01273 
01274         /* Convert it. */
01275         ok = unpack_smb_acl(&racl, sacl);
01276         sys_acl_free_acl(sacl);
01277         if (!ok) {
01278                 rprintf(FERROR, "default_perms_for_dir: unpack_smb_acl failed, falling back on umask\n");
01279                 return perms;
01280         }
01281 
01282         /* Apply the permission-bit entries of the default ACL, if any. */
01283         if (racl.user_obj != ACL_NO_ENTRY) {
01284                 perms = rsync_acl_get_perms(&racl);
01285                 if (verbose > 2)
01286                         rprintf(FINFO, "got ACL-based default perms %o for directory %s\n", perms, dir);
01287         }
01288 
01289         rsync_acl_free(&racl);
01290         return perms;
01291 }
01292 
01293 #endif /* SUPPORT_ACLS */

rsyncに対してSat Dec 5 19:45:40 2009に生成されました。  doxygen 1.4.7