Annotation of embedaddon/rsync/acls.c, revision 1.1.1.1

1.1       misho       1: /*
                      2:  * Handle passing Access Control Lists between systems.
                      3:  *
                      4:  * Copyright (C) 1996 Andrew Tridgell
                      5:  * Copyright (C) 1996 Paul Mackerras
                      6:  * Copyright (C) 2006-2009 Wayne Davison
                      7:  *
                      8:  * This program is free software; you can redistribute it and/or modify
                      9:  * it under the terms of the GNU General Public License as published by
                     10:  * the Free Software Foundation; either version 3 of the License, or
                     11:  * (at your option) any later version.
                     12:  *
                     13:  * This program is distributed in the hope that it will be useful,
                     14:  * but WITHOUT ANY WARRANTY; without even the implied warranty of
                     15:  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
                     16:  * GNU General Public License for more details.
                     17:  *
                     18:  * You should have received a copy of the GNU General Public License along
                     19:  * with this program; if not, visit the http://fsf.org website.
                     20:  */
                     21: 
                     22: #include "rsync.h"
                     23: #include "lib/sysacls.h"
                     24: 
                     25: #ifdef SUPPORT_ACLS
                     26: 
                     27: extern int dry_run;
                     28: extern int am_root;
                     29: extern int read_only;
                     30: extern int list_only;
                     31: extern int orig_umask;
                     32: extern int numeric_ids;
                     33: extern int inc_recurse;
                     34: extern int preserve_devices;
                     35: extern int preserve_specials;
                     36: 
                     37: /* Flags used to indicate what items are being transmitted for an entry. */
                     38: #define XMIT_USER_OBJ (1<<0)
                     39: #define XMIT_GROUP_OBJ (1<<1)
                     40: #define XMIT_MASK_OBJ (1<<2)
                     41: #define XMIT_OTHER_OBJ (1<<3)
                     42: #define XMIT_NAME_LIST (1<<4)
                     43: 
                     44: #define NO_ENTRY ((uchar)0x80) /* Default value of a NON-name-list entry. */
                     45: 
                     46: #define NAME_IS_USER (1u<<31) /* Bit used only on a name-list entry. */
                     47: 
                     48: /* When we send the access bits over the wire, we shift them 2 bits to the
                     49:  * left and use the lower 2 bits as flags (relevant only to a name entry).
                     50:  * This makes the protocol more efficient than sending a value that would
                     51:  * be likely to have its hightest bits set. */
                     52: #define XFLAG_NAME_FOLLOWS 0x0001u
                     53: #define XFLAG_NAME_IS_USER 0x0002u
                     54: 
                     55: /* === ACL structures === */
                     56: 
                     57: typedef struct {
                     58:        id_t id;
                     59:        uint32 access;
                     60: } id_access;
                     61: 
                     62: typedef struct {
                     63:        id_access *idas;
                     64:        int count;
                     65: } ida_entries;
                     66: 
                     67: typedef struct {
                     68:        char *name;
                     69:        uchar len;
                     70: } idname;
                     71: 
                     72: typedef struct rsync_acl {
                     73:        ida_entries names;
                     74:        /* These will be NO_ENTRY if there's no such entry. */
                     75:        uchar user_obj;
                     76:        uchar group_obj;
                     77:        uchar mask_obj;
                     78:        uchar other_obj;
                     79: } rsync_acl;
                     80: 
                     81: typedef struct {
                     82:        rsync_acl racl;
                     83:        SMB_ACL_T sacl;
                     84: } acl_duo;
                     85: 
                     86: static const rsync_acl empty_rsync_acl = {
                     87:        {NULL, 0}, NO_ENTRY, NO_ENTRY, NO_ENTRY, NO_ENTRY
                     88: };
                     89: 
                     90: static item_list access_acl_list = EMPTY_ITEM_LIST;
                     91: static item_list default_acl_list = EMPTY_ITEM_LIST;
                     92: 
                     93: static size_t prior_access_count = (size_t)-1;
                     94: static size_t prior_default_count = (size_t)-1;
                     95: 
                     96: /* === Calculations on ACL types === */
                     97: 
                     98: static const char *str_acl_type(SMB_ACL_TYPE_T type)
                     99: {
                    100:        switch (type) {
                    101:        case SMB_ACL_TYPE_ACCESS:
                    102: #ifdef HAVE_OSX_ACLS
                    103:                return "ACL_TYPE_EXTENDED";
                    104: #else
                    105:                return "ACL_TYPE_ACCESS";
                    106: #endif
                    107:        case SMB_ACL_TYPE_DEFAULT:
                    108:                return "ACL_TYPE_DEFAULT";
                    109:        default:
                    110:                break;
                    111:        }
                    112:        return "unknown ACL type!";
                    113: }
                    114: 
                    115: static int calc_sacl_entries(const rsync_acl *racl)
                    116: {
                    117:        /* A System ACL always gets user/group/other permission entries. */
                    118:        return racl->names.count
                    119: #ifdef ACLS_NEED_MASK
                    120:             + 1
                    121: #else
                    122:             + (racl->mask_obj != NO_ENTRY)
                    123: #endif
                    124:             + 3;
                    125: }
                    126: 
                    127: /* Extracts and returns the permission bits from the ACL.  This cannot be
                    128:  * called on an rsync_acl that has NO_ENTRY in any spot but the mask. */
                    129: static int rsync_acl_get_perms(const rsync_acl *racl)
                    130: {
                    131:        return (racl->user_obj << 6)
                    132:             + ((racl->mask_obj != NO_ENTRY ? racl->mask_obj : racl->group_obj) << 3)
                    133:             + racl->other_obj;
                    134: }
                    135: 
                    136: /* Removes the permission-bit entries from the ACL because these
                    137:  * can be reconstructed from the file's mode. */
                    138: static void rsync_acl_strip_perms(stat_x *sxp)
                    139: {
                    140:        rsync_acl *racl = sxp->acc_acl;
                    141: 
                    142:        racl->user_obj = NO_ENTRY;
                    143:        if (racl->mask_obj == NO_ENTRY)
                    144:                racl->group_obj = NO_ENTRY;
                    145:        else {
                    146:                int group_perms = (sxp->st.st_mode >> 3) & 7;
                    147:                if (racl->group_obj == group_perms)
                    148:                        racl->group_obj = NO_ENTRY;
                    149: #ifndef HAVE_SOLARIS_ACLS
                    150:                if (racl->names.count != 0 && racl->mask_obj == group_perms)
                    151:                        racl->mask_obj = NO_ENTRY;
                    152: #endif
                    153:        }
                    154:        racl->other_obj = NO_ENTRY;
                    155: }
                    156: 
                    157: /* Given an empty rsync_acl, fake up the permission bits. */
                    158: static void rsync_acl_fake_perms(rsync_acl *racl, mode_t mode)
                    159: {
                    160:        racl->user_obj = (mode >> 6) & 7;
                    161:        racl->group_obj = (mode >> 3) & 7;
                    162:        racl->other_obj = mode & 7;
                    163: }
                    164: 
                    165: /* === Rsync ACL functions === */
                    166: 
                    167: static rsync_acl *create_racl(void)
                    168: {
                    169:        rsync_acl *racl = new(rsync_acl);
                    170: 
                    171:        if (!racl)
                    172:                out_of_memory("create_racl");
                    173:        *racl = empty_rsync_acl;
                    174: 
                    175:        return racl;
                    176: }
                    177: 
                    178: static BOOL ida_entries_equal(const ida_entries *ial1, const ida_entries *ial2)
                    179: {
                    180:        id_access *ida1, *ida2;
                    181:        int count = ial1->count;
                    182:        if (count != ial2->count)
                    183:                return False;
                    184:        ida1 = ial1->idas;
                    185:        ida2 = ial2->idas;
                    186:        for (; count--; ida1++, ida2++) {
                    187:                if (ida1->access != ida2->access || ida1->id != ida2->id)
                    188:                        return False;
                    189:        }
                    190:        return True;
                    191: }
                    192: 
                    193: static BOOL rsync_acl_equal(const rsync_acl *racl1, const rsync_acl *racl2)
                    194: {
                    195:        return racl1->user_obj == racl2->user_obj
                    196:            && racl1->group_obj == racl2->group_obj
                    197:            && racl1->mask_obj == racl2->mask_obj
                    198:            && racl1->other_obj == racl2->other_obj
                    199:            && ida_entries_equal(&racl1->names, &racl2->names);
                    200: }
                    201: 
                    202: /* Are the extended (non-permission-bit) entries equal?  If so, the rest of
                    203:  * the ACL will be handled by the normal mode-preservation code.  This is
                    204:  * only meaningful for access ACLs!  Note: the 1st arg is a fully-populated
                    205:  * rsync_acl, but the 2nd parameter can be a condensed rsync_acl, which means
                    206:  * that it might have several of its permission objects set to NO_ENTRY. */
                    207: static BOOL rsync_acl_equal_enough(const rsync_acl *racl1,
                    208:                                   const rsync_acl *racl2, mode_t m)
                    209: {
                    210:        if ((racl1->mask_obj ^ racl2->mask_obj) & NO_ENTRY)
                    211:                return False; /* One has a mask and the other doesn't */
                    212: 
                    213:        /* When there's a mask, the group_obj becomes an extended entry. */
                    214:        if (racl1->mask_obj != NO_ENTRY) {
                    215:                /* A condensed rsync_acl with a mask can only have no
                    216:                 * group_obj when it was identical to the mask.  This
                    217:                 * means that it was also identical to the group attrs
                    218:                 * from the mode. */
                    219:                if (racl2->group_obj == NO_ENTRY) {
                    220:                        if (racl1->group_obj != ((m >> 3) & 7))
                    221:                                return False;
                    222:                } else if (racl1->group_obj != racl2->group_obj)
                    223:                        return False;
                    224:        }
                    225:        return ida_entries_equal(&racl1->names, &racl2->names);
                    226: }
                    227: 
                    228: static void rsync_acl_free(rsync_acl *racl)
                    229: {
                    230:        if (racl->names.idas)
                    231:                free(racl->names.idas);
                    232:        *racl = empty_rsync_acl;
                    233: }
                    234: 
                    235: void free_acl(stat_x *sxp)
                    236: {
                    237:        if (sxp->acc_acl) {
                    238:                rsync_acl_free(sxp->acc_acl);
                    239:                free(sxp->acc_acl);
                    240:                sxp->acc_acl = NULL;
                    241:        }
                    242:        if (sxp->def_acl) {
                    243:                rsync_acl_free(sxp->def_acl);
                    244:                free(sxp->def_acl);
                    245:                sxp->def_acl = NULL;
                    246:        }
                    247: }
                    248: 
                    249: #ifdef SMB_ACL_NEED_SORT
                    250: static int id_access_sorter(const void *r1, const void *r2)
                    251: {
                    252:        id_access *ida1 = (id_access *)r1;
                    253:        id_access *ida2 = (id_access *)r2;
                    254:        id_t rid1 = ida1->id, rid2 = ida2->id;
                    255:        if ((ida1->access ^ ida2->access) & NAME_IS_USER)
                    256:                return ida1->access & NAME_IS_USER ? -1 : 1;
                    257:        return rid1 == rid2 ? 0 : rid1 < rid2 ? -1 : 1;
                    258: }
                    259: #endif
                    260: 
                    261: /* === System ACLs === */
                    262: 
                    263: /* Unpack system ACL -> rsync ACL verbatim.  Return whether we succeeded. */
                    264: static BOOL unpack_smb_acl(SMB_ACL_T sacl, rsync_acl *racl)
                    265: {
                    266:        static item_list temp_ida_list = EMPTY_ITEM_LIST;
                    267:        SMB_ACL_ENTRY_T entry;
                    268:        const char *errfun;
                    269:        int rc;
                    270: 
                    271:        errfun = "sys_acl_get_entry";
                    272:        for (rc = sys_acl_get_entry(sacl, SMB_ACL_FIRST_ENTRY, &entry);
                    273:             rc == 1;
                    274:             rc = sys_acl_get_entry(sacl, SMB_ACL_NEXT_ENTRY, &entry)) {
                    275:                SMB_ACL_TAG_T tag_type;
                    276:                uint32 access;
                    277:                id_t g_u_id;
                    278:                id_access *ida;
                    279:                if ((rc = sys_acl_get_info(entry, &tag_type, &access, &g_u_id)) != 0) {
                    280:                        errfun = "sys_acl_get_info";
                    281:                        break;
                    282:                }
                    283:                /* continue == done with entry; break == store in temporary ida list */
                    284:                switch (tag_type) {
                    285: #ifndef HAVE_OSX_ACLS
                    286:                case SMB_ACL_USER_OBJ:
                    287:                        if (racl->user_obj == NO_ENTRY)
                    288:                                racl->user_obj = access;
                    289:                        else
                    290:                                rprintf(FINFO, "unpack_smb_acl: warning: duplicate USER_OBJ entry ignored\n");
                    291:                        continue;
                    292:                case SMB_ACL_GROUP_OBJ:
                    293:                        if (racl->group_obj == NO_ENTRY)
                    294:                                racl->group_obj = access;
                    295:                        else
                    296:                                rprintf(FINFO, "unpack_smb_acl: warning: duplicate GROUP_OBJ entry ignored\n");
                    297:                        continue;
                    298:                case SMB_ACL_MASK:
                    299:                        if (racl->mask_obj == NO_ENTRY)
                    300:                                racl->mask_obj = access;
                    301:                        else
                    302:                                rprintf(FINFO, "unpack_smb_acl: warning: duplicate MASK entry ignored\n");
                    303:                        continue;
                    304:                case SMB_ACL_OTHER:
                    305:                        if (racl->other_obj == NO_ENTRY)
                    306:                                racl->other_obj = access;
                    307:                        else
                    308:                                rprintf(FINFO, "unpack_smb_acl: warning: duplicate OTHER entry ignored\n");
                    309:                        continue;
                    310: #endif
                    311:                case SMB_ACL_USER:
                    312:                        access |= NAME_IS_USER;
                    313:                        break;
                    314:                case SMB_ACL_GROUP:
                    315:                        break;
                    316:                default:
                    317:                        rprintf(FINFO, "unpack_smb_acl: warning: entry with unrecognized tag type ignored\n");
                    318:                        continue;
                    319:                }
                    320:                ida = EXPAND_ITEM_LIST(&temp_ida_list, id_access, -10);
                    321:                ida->id = g_u_id;
                    322:                ida->access = access;
                    323:        }
                    324:        if (rc) {
                    325:                rsyserr(FERROR_XFER, errno, "unpack_smb_acl: %s()", errfun);
                    326:                rsync_acl_free(racl);
                    327:                return False;
                    328:        }
                    329: 
                    330:        /* Transfer the count id_access items out of the temp_ida_list
                    331:         * into the names ida_entries list in racl. */
                    332:        if (temp_ida_list.count) {
                    333: #ifdef SMB_ACL_NEED_SORT
                    334:                if (temp_ida_list.count > 1) {
                    335:                        qsort(temp_ida_list.items, temp_ida_list.count,
                    336:                              sizeof (id_access), id_access_sorter);
                    337:                }
                    338: #endif
                    339:                if (!(racl->names.idas = new_array(id_access, temp_ida_list.count)))
                    340:                        out_of_memory("unpack_smb_acl");
                    341:                memcpy(racl->names.idas, temp_ida_list.items,
                    342:                       temp_ida_list.count * sizeof (id_access));
                    343:        } else
                    344:                racl->names.idas = NULL;
                    345: 
                    346:        racl->names.count = temp_ida_list.count;
                    347: 
                    348:        /* Truncate the temporary list now that its idas have been saved. */
                    349:        temp_ida_list.count = 0;
                    350: 
                    351:        return True;
                    352: }
                    353: 
                    354: /* Synactic sugar for system calls */
                    355: 
                    356: #define CALL_OR_ERROR(func,args,str) \
                    357:        do { \
                    358:                if (func args) { \
                    359:                        errfun = str; \
                    360:                        goto error_exit; \
                    361:                } \
                    362:        } while (0)
                    363: 
                    364: #define COE(func,args) CALL_OR_ERROR(func,args,#func)
                    365: #define COE2(func,args) CALL_OR_ERROR(func,args,NULL)
                    366: 
                    367: #ifndef HAVE_OSX_ACLS
                    368: /* Store the permissions in the system ACL entry. */
                    369: static int store_access_in_entry(uint32 access, SMB_ACL_ENTRY_T entry)
                    370: {
                    371:        if (sys_acl_set_access_bits(entry, access)) {
                    372:                rsyserr(FERROR_XFER, errno, "store_access_in_entry sys_acl_set_access_bits()");
                    373:                return -1;
                    374:        }
                    375:        return 0;
                    376: }
                    377: #endif
                    378: 
                    379: /* Pack rsync ACL -> system ACL verbatim.  Return whether we succeeded. */
                    380: static BOOL pack_smb_acl(SMB_ACL_T *smb_acl, const rsync_acl *racl)
                    381: {
                    382: #ifdef ACLS_NEED_MASK
                    383:        uchar mask_bits;
                    384: #endif
                    385:        size_t count;
                    386:        id_access *ida;
                    387:        const char *errfun = NULL;
                    388:        SMB_ACL_ENTRY_T entry;
                    389: 
                    390:        if (!(*smb_acl = sys_acl_init(calc_sacl_entries(racl)))) {
                    391:                rsyserr(FERROR_XFER, errno, "pack_smb_acl: sys_acl_init()");
                    392:                return False;
                    393:        }
                    394: 
                    395: #ifndef HAVE_OSX_ACLS
                    396:        COE( sys_acl_create_entry,(smb_acl, &entry) );
                    397:        COE( sys_acl_set_info,(entry, SMB_ACL_USER_OBJ, racl->user_obj & ~NO_ENTRY, 0) );
                    398: #endif
                    399: 
                    400:        for (ida = racl->names.idas, count = racl->names.count; count; ida++, count--) {
                    401: #ifdef SMB_ACL_NEED_SORT
                    402:                if (!(ida->access & NAME_IS_USER))
                    403:                        break;
                    404: #endif
                    405:                COE( sys_acl_create_entry,(smb_acl, &entry) );
                    406:                COE( sys_acl_set_info,
                    407:                    (entry,
                    408:                     ida->access & NAME_IS_USER ? SMB_ACL_USER : SMB_ACL_GROUP,
                    409:                     ida->access & ~NAME_IS_USER, ida->id) );
                    410:        }
                    411: 
                    412: #ifndef HAVE_OSX_ACLS
                    413:        COE( sys_acl_create_entry,(smb_acl, &entry) );
                    414:        COE( sys_acl_set_info,(entry, SMB_ACL_GROUP_OBJ, racl->group_obj & ~NO_ENTRY, 0) );
                    415: 
                    416: #ifdef SMB_ACL_NEED_SORT
                    417:        for ( ; count; ida++, count--) {
                    418:                COE( sys_acl_create_entry,(smb_acl, &entry) );
                    419:                COE( sys_acl_set_info,(entry, SMB_ACL_GROUP, ida->access, ida->id) );
                    420:        }
                    421: #endif
                    422: 
                    423: #ifdef ACLS_NEED_MASK
                    424:        mask_bits = racl->mask_obj == NO_ENTRY ? racl->group_obj & ~NO_ENTRY : racl->mask_obj;
                    425:        COE( sys_acl_create_entry,(smb_acl, &entry) );
                    426:        COE( sys_acl_set_info,(entry, SMB_ACL_MASK, mask_bits, NULL) );
                    427: #else
                    428:        if (racl->mask_obj != NO_ENTRY) {
                    429:                COE( sys_acl_create_entry,(smb_acl, &entry) );
                    430:                COE( sys_acl_set_info,(entry, SMB_ACL_MASK, racl->mask_obj, 0) );
                    431:        }
                    432: #endif
                    433: 
                    434:        COE( sys_acl_create_entry,(smb_acl, &entry) );
                    435:        COE( sys_acl_set_info,(entry, SMB_ACL_OTHER, racl->other_obj & ~NO_ENTRY, 0) );
                    436: #endif
                    437: 
                    438: #ifdef DEBUG
                    439:        if (sys_acl_valid(*smb_acl) < 0)
                    440:                rprintf(FERROR_XFER, "pack_smb_acl: warning: system says the ACL I packed is invalid\n");
                    441: #endif
                    442: 
                    443:        return True;
                    444: 
                    445:   error_exit:
                    446:        if (errfun) {
                    447:                rsyserr(FERROR_XFER, errno, "pack_smb_acl %s()", errfun);
                    448:        }
                    449:        sys_acl_free_acl(*smb_acl);
                    450:        return False;
                    451: }
                    452: 
                    453: static int find_matching_rsync_acl(const rsync_acl *racl, SMB_ACL_TYPE_T type,
                    454:                                   const item_list *racl_list)
                    455: {
                    456:        static int access_match = -1, default_match = -1;
                    457:        int *match = type == SMB_ACL_TYPE_ACCESS ? &access_match : &default_match;
                    458:        size_t count = racl_list->count;
                    459: 
                    460:        /* If this is the first time through or we didn't match the last
                    461:         * time, then start at the end of the list, which should be the
                    462:         * best place to start hunting. */
                    463:        if (*match == -1)
                    464:                *match = racl_list->count - 1;
                    465:        while (count--) {
                    466:                rsync_acl *base = racl_list->items;
                    467:                if (rsync_acl_equal(base + *match, racl))
                    468:                        return *match;
                    469:                if (!(*match)--)
                    470:                        *match = racl_list->count - 1;
                    471:        }
                    472: 
                    473:        *match = -1;
                    474:        return *match;
                    475: }
                    476: 
                    477: static int get_rsync_acl(const char *fname, rsync_acl *racl,
                    478:                         SMB_ACL_TYPE_T type, mode_t mode)
                    479: {
                    480:        SMB_ACL_T sacl;
                    481: 
                    482: #ifdef SUPPORT_XATTRS
                    483:        /* --fake-super support: load ACLs from an xattr. */
                    484:        if (am_root < 0) {
                    485:                char *buf;
                    486:                size_t len;
                    487:                int cnt;
                    488: 
                    489:                if ((buf = get_xattr_acl(fname, type == SMB_ACL_TYPE_ACCESS, &len)) == NULL)
                    490:                        return 0;
                    491:                cnt = (len - 4*4) / (4+4);
                    492:                if (len < 4*4 || len != (size_t)cnt*(4+4) + 4*4) {
                    493:                        free(buf);
                    494:                        return -1;
                    495:                }
                    496: 
                    497:                racl->user_obj = IVAL(buf, 0);
                    498:                if (racl->user_obj == NO_ENTRY)
                    499:                        racl->user_obj = (mode >> 6) & 7;
                    500:                racl->group_obj = IVAL(buf, 4);
                    501:                if (racl->group_obj == NO_ENTRY)
                    502:                        racl->group_obj = (mode >> 3) & 7;
                    503:                racl->mask_obj = IVAL(buf, 8);
                    504:                racl->other_obj = IVAL(buf, 12);
                    505:                if (racl->other_obj == NO_ENTRY)
                    506:                        racl->other_obj = mode & 7;
                    507: 
                    508:                if (cnt) {
                    509:                        char *bp = buf + 4*4;
                    510:                        id_access *ida;
                    511:                        if (!(ida = racl->names.idas = new_array(id_access, cnt)))
                    512:                                out_of_memory("get_rsync_acl");
                    513:                        racl->names.count = cnt;
                    514:                        for ( ; cnt--; ida++, bp += 4+4) {
                    515:                                ida->id = IVAL(bp, 0);
                    516:                                ida->access = IVAL(bp, 4);
                    517:                        }
                    518:                }
                    519:                free(buf);
                    520:                return 0;
                    521:        }
                    522: #endif
                    523: 
                    524:        if ((sacl = sys_acl_get_file(fname, type)) != 0) {
                    525:                BOOL ok = unpack_smb_acl(sacl, racl);
                    526: 
                    527:                sys_acl_free_acl(sacl);
                    528:                if (!ok) {
                    529:                        return -1;
                    530:                }
                    531:        } else if (no_acl_syscall_error(errno)) {
                    532:                /* ACLs are not supported, so pretend we have a basic ACL. */
                    533:                if (type == SMB_ACL_TYPE_ACCESS)
                    534:                        rsync_acl_fake_perms(racl, mode);
                    535:        } else {
                    536:                rsyserr(FERROR_XFER, errno, "get_acl: sys_acl_get_file(%s, %s)",
                    537:                        fname, str_acl_type(type));
                    538:                return -1;
                    539:        }
                    540: 
                    541:        return 0;
                    542: }
                    543: 
                    544: /* Return the Access Control List for the given filename. */
                    545: int get_acl(const char *fname, stat_x *sxp)
                    546: {
                    547:        sxp->acc_acl = create_racl();
                    548: 
                    549:        if (S_ISREG(sxp->st.st_mode) || S_ISDIR(sxp->st.st_mode)) {
                    550:                /* Everyone supports this. */
                    551:        } else if (S_ISLNK(sxp->st.st_mode)) {
                    552:                return 0;
                    553:        } else if (IS_SPECIAL(sxp->st.st_mode)) {
                    554: #ifndef NO_SPECIAL_ACLS
                    555:                if (!preserve_specials)
                    556: #endif
                    557:                        return 0;
                    558:        } else if (IS_DEVICE(sxp->st.st_mode)) {
                    559: #ifndef NO_DEVICE_ACLS
                    560:                if (!preserve_devices)
                    561: #endif
                    562:                        return 0;
                    563:        }
                    564: 
                    565:        if (get_rsync_acl(fname, sxp->acc_acl, SMB_ACL_TYPE_ACCESS,
                    566:                          sxp->st.st_mode) < 0) {
                    567:                free_acl(sxp);
                    568:                return -1;
                    569:        }
                    570: 
                    571:        if (S_ISDIR(sxp->st.st_mode)) {
                    572:                sxp->def_acl = create_racl();
                    573:                if (get_rsync_acl(fname, sxp->def_acl, SMB_ACL_TYPE_DEFAULT,
                    574:                                  sxp->st.st_mode) < 0) {
                    575:                        free_acl(sxp);
                    576:                        return -1;
                    577:                }
                    578:        }
                    579: 
                    580:        return 0;
                    581: }
                    582: 
                    583: /* === Send functions === */
                    584: 
                    585: /* Send the ida list over the file descriptor. */
                    586: static void send_ida_entries(int f, const ida_entries *idal)
                    587: {
                    588:        id_access *ida;
                    589:        size_t count = idal->count;
                    590: 
                    591:        write_varint(f, idal->count);
                    592: 
                    593:        for (ida = idal->idas; count--; ida++) {
                    594:                uint32 xbits = ida->access << 2;
                    595:                const char *name;
                    596:                if (ida->access & NAME_IS_USER) {
                    597:                        xbits |= XFLAG_NAME_IS_USER;
                    598:                        name = numeric_ids ? NULL : add_uid(ida->id);
                    599:                } else
                    600:                        name = numeric_ids ? NULL : add_gid(ida->id);
                    601:                write_varint(f, ida->id);
                    602:                if (inc_recurse && name) {
                    603:                        int len = strlen(name);
                    604:                        write_varint(f, xbits | XFLAG_NAME_FOLLOWS);
                    605:                        write_byte(f, len);
                    606:                        write_buf(f, name, len);
                    607:                } else
                    608:                        write_varint(f, xbits);
                    609:        }
                    610: }
                    611: 
                    612: static void send_rsync_acl(int f, rsync_acl *racl, SMB_ACL_TYPE_T type,
                    613:                           item_list *racl_list)
                    614: {
                    615:        int ndx = find_matching_rsync_acl(racl, type, racl_list);
                    616: 
                    617:        /* Send 0 (-1 + 1) to indicate that literal ACL data follows. */
                    618:        write_varint(f, ndx + 1);
                    619: 
                    620:        if (ndx < 0) {
                    621:                rsync_acl *new_racl = EXPAND_ITEM_LIST(racl_list, rsync_acl, 1000);
                    622:                uchar flags = 0;
                    623: 
                    624:                if (racl->user_obj != NO_ENTRY)
                    625:                        flags |= XMIT_USER_OBJ;
                    626:                if (racl->group_obj != NO_ENTRY)
                    627:                        flags |= XMIT_GROUP_OBJ;
                    628:                if (racl->mask_obj != NO_ENTRY)
                    629:                        flags |= XMIT_MASK_OBJ;
                    630:                if (racl->other_obj != NO_ENTRY)
                    631:                        flags |= XMIT_OTHER_OBJ;
                    632:                if (racl->names.count)
                    633:                        flags |= XMIT_NAME_LIST;
                    634: 
                    635:                write_byte(f, flags);
                    636: 
                    637:                if (flags & XMIT_USER_OBJ)
                    638:                        write_varint(f, racl->user_obj);
                    639:                if (flags & XMIT_GROUP_OBJ)
                    640:                        write_varint(f, racl->group_obj);
                    641:                if (flags & XMIT_MASK_OBJ)
                    642:                        write_varint(f, racl->mask_obj);
                    643:                if (flags & XMIT_OTHER_OBJ)
                    644:                        write_varint(f, racl->other_obj);
                    645:                if (flags & XMIT_NAME_LIST)
                    646:                        send_ida_entries(f, &racl->names);
                    647: 
                    648:                /* Give the allocated data to the new list object. */
                    649:                *new_racl = *racl;
                    650:                *racl = empty_rsync_acl;
                    651:        }
                    652: }
                    653: 
                    654: /* Send the ACL from the stat_x structure down the indicated file descriptor.
                    655:  * This also frees the ACL data. */
                    656: void send_acl(int f, stat_x *sxp)
                    657: {
                    658:        if (!sxp->acc_acl) {
                    659:                sxp->acc_acl = create_racl();
                    660:                rsync_acl_fake_perms(sxp->acc_acl, sxp->st.st_mode);
                    661:        }
                    662:        /* Avoid sending values that can be inferred from other data. */
                    663:        rsync_acl_strip_perms(sxp);
                    664: 
                    665:        send_rsync_acl(f, sxp->acc_acl, SMB_ACL_TYPE_ACCESS, &access_acl_list);
                    666: 
                    667:        if (S_ISDIR(sxp->st.st_mode)) {
                    668:                if (!sxp->def_acl)
                    669:                        sxp->def_acl = create_racl();
                    670: 
                    671:                send_rsync_acl(f, sxp->def_acl, SMB_ACL_TYPE_DEFAULT, &default_acl_list);
                    672:        }
                    673: }
                    674: 
                    675: /* === Receive functions === */
                    676: 
                    677: static uint32 recv_acl_access(int f, uchar *name_follows_ptr)
                    678: {
                    679:        uint32 access = read_varint(f);
                    680: 
                    681:        if (name_follows_ptr) {
                    682:                int flags = access & 3;
                    683:                access >>= 2;
                    684:                if (am_root >= 0 && access & ~SMB_ACL_VALID_NAME_BITS)
                    685:                        goto value_error;
                    686:                if (flags & XFLAG_NAME_FOLLOWS)
                    687:                        *name_follows_ptr = 1;
                    688:                else
                    689:                        *name_follows_ptr = 0;
                    690:                if (flags & XFLAG_NAME_IS_USER)
                    691:                        access |= NAME_IS_USER;
                    692:        } else if (am_root >= 0 && access & ~SMB_ACL_VALID_OBJ_BITS) {
                    693:          value_error:
                    694:                rprintf(FERROR_XFER, "recv_acl_access: value out of range: %x\n",
                    695:                        access);
                    696:                exit_cleanup(RERR_STREAMIO);
                    697:        }
                    698: 
                    699:        return access;
                    700: }
                    701: 
                    702: static uchar recv_ida_entries(int f, ida_entries *ent)
                    703: {
                    704:        uchar computed_mask_bits = 0;
                    705:        int i, count = read_varint(f);
                    706: 
                    707:        if (count) {
                    708:                if (!(ent->idas = new_array(id_access, count)))
                    709:                        out_of_memory("recv_ida_entries");
                    710:        } else
                    711:                ent->idas = NULL;
                    712: 
                    713:        ent->count = count;
                    714: 
                    715:        for (i = 0; i < count; i++) {
                    716:                uchar has_name;
                    717:                id_t id = read_varint(f);
                    718:                uint32 access = recv_acl_access(f, &has_name);
                    719: 
                    720:                if (has_name) {
                    721:                        if (access & NAME_IS_USER)
                    722:                                id = recv_user_name(f, id);
                    723:                        else
                    724:                                id = recv_group_name(f, id, NULL);
                    725:                } else if (access & NAME_IS_USER) {
                    726:                        if (inc_recurse && am_root && !numeric_ids)
                    727:                                id = match_uid(id);
                    728:                } else {
                    729:                        if (inc_recurse && (!am_root || !numeric_ids))
                    730:                                id = match_gid(id, NULL);
                    731:                }
                    732: 
                    733:                ent->idas[i].id = id;
                    734:                ent->idas[i].access = access;
                    735:                computed_mask_bits |= access;
                    736:        }
                    737: 
                    738:        return computed_mask_bits & ~NO_ENTRY;
                    739: }
                    740: 
                    741: static int recv_rsync_acl(int f, item_list *racl_list, SMB_ACL_TYPE_T type, mode_t mode)
                    742: {
                    743:        uchar computed_mask_bits = 0;
                    744:        acl_duo *duo_item;
                    745:        uchar flags;
                    746:        int ndx = read_varint(f);
                    747: 
                    748:        if (ndx < 0 || (size_t)ndx > racl_list->count) {
                    749:                rprintf(FERROR_XFER, "recv_acl_index: %s ACL index %d > %d\n",
                    750:                        str_acl_type(type), ndx, (int)racl_list->count);
                    751:                exit_cleanup(RERR_STREAMIO);
                    752:        }
                    753: 
                    754:        if (ndx != 0)
                    755:                return ndx - 1;
                    756: 
                    757:        ndx = racl_list->count;
                    758:        duo_item = EXPAND_ITEM_LIST(racl_list, acl_duo, 1000);
                    759:        duo_item->racl = empty_rsync_acl;
                    760: 
                    761:        flags = read_byte(f);
                    762: 
                    763:        if (flags & XMIT_USER_OBJ)
                    764:                duo_item->racl.user_obj = recv_acl_access(f, NULL);
                    765:        if (flags & XMIT_GROUP_OBJ)
                    766:                duo_item->racl.group_obj = recv_acl_access(f, NULL);
                    767:        if (flags & XMIT_MASK_OBJ)
                    768:                duo_item->racl.mask_obj = recv_acl_access(f, NULL);
                    769:        if (flags & XMIT_OTHER_OBJ)
                    770:                duo_item->racl.other_obj = recv_acl_access(f, NULL);
                    771:        if (flags & XMIT_NAME_LIST)
                    772:                computed_mask_bits |= recv_ida_entries(f, &duo_item->racl.names);
                    773: 
                    774: #ifdef HAVE_OSX_ACLS
                    775:        /* If we received a superfluous mask, throw it away. */
                    776:        duo_item->racl.mask_obj = NO_ENTRY;
                    777: #else
                    778:        if (duo_item->racl.names.count && duo_item->racl.mask_obj == NO_ENTRY) {
                    779:                /* Mask must be non-empty with lists. */
                    780:                if (type == SMB_ACL_TYPE_ACCESS)
                    781:                        computed_mask_bits = (mode >> 3) & 7;
                    782:                else
                    783:                        computed_mask_bits |= duo_item->racl.group_obj & ~NO_ENTRY;
                    784:                duo_item->racl.mask_obj = computed_mask_bits;
                    785:        }
                    786: #endif
                    787: 
                    788:        duo_item->sacl = NULL;
                    789: 
                    790:        return ndx;
                    791: }
                    792: 
                    793: /* Receive the ACL info the sender has included for this file-list entry. */
                    794: void receive_acl(int f, struct file_struct *file)
                    795: {
                    796:        F_ACL(file) = recv_rsync_acl(f, &access_acl_list, SMB_ACL_TYPE_ACCESS, file->mode);
                    797: 
                    798:        if (S_ISDIR(file->mode))
                    799:                F_DIR_DEFACL(file) = recv_rsync_acl(f, &default_acl_list, SMB_ACL_TYPE_DEFAULT, 0);
                    800: }
                    801: 
                    802: static int cache_rsync_acl(rsync_acl *racl, SMB_ACL_TYPE_T type, item_list *racl_list)
                    803: {
                    804:        int ndx;
                    805: 
                    806:        if (!racl)
                    807:                ndx = -1;
                    808:        else if ((ndx = find_matching_rsync_acl(racl, type, racl_list)) == -1) {
                    809:                acl_duo *new_duo;
                    810:                ndx = racl_list->count;
                    811:                new_duo = EXPAND_ITEM_LIST(racl_list, acl_duo, 1000);
                    812:                new_duo->racl = *racl;
                    813:                new_duo->sacl = NULL;
                    814:                *racl = empty_rsync_acl;
                    815:        }
                    816: 
                    817:        return ndx;
                    818: }
                    819: 
                    820: /* Turn the ACL data in stat_x into cached ACL data, setting the index
                    821:  * values in the file struct. */
                    822: void cache_tmp_acl(struct file_struct *file, stat_x *sxp)
                    823: {
                    824:        if (prior_access_count == (size_t)-1)
                    825:                prior_access_count = access_acl_list.count;
                    826: 
                    827:        F_ACL(file) = cache_rsync_acl(sxp->acc_acl,
                    828:                                      SMB_ACL_TYPE_ACCESS, &access_acl_list);
                    829: 
                    830:        if (S_ISDIR(sxp->st.st_mode)) {
                    831:                if (prior_default_count == (size_t)-1)
                    832:                        prior_default_count = default_acl_list.count;
                    833:                F_DIR_DEFACL(file) = cache_rsync_acl(sxp->def_acl,
                    834:                                      SMB_ACL_TYPE_DEFAULT, &default_acl_list);
                    835:        }
                    836: }
                    837: 
                    838: static void uncache_duo_acls(item_list *duo_list, size_t start)
                    839: {
                    840:        acl_duo *duo_item = duo_list->items;
                    841:        acl_duo *duo_start = duo_item + start;
                    842: 
                    843:        duo_item += duo_list->count;
                    844:        duo_list->count = start;
                    845: 
                    846:        while (duo_item-- > duo_start) {
                    847:                rsync_acl_free(&duo_item->racl);
                    848:                if (duo_item->sacl)
                    849:                        sys_acl_free_acl(duo_item->sacl);
                    850:        }
                    851: }
                    852: 
                    853: void uncache_tmp_acls(void)
                    854: {
                    855:        if (prior_access_count != (size_t)-1) {
                    856:                uncache_duo_acls(&access_acl_list, prior_access_count);
                    857:                prior_access_count = (size_t)-1;
                    858:        }
                    859: 
                    860:        if (prior_default_count != (size_t)-1) {
                    861:                uncache_duo_acls(&default_acl_list, prior_default_count);
                    862:                prior_default_count = (size_t)-1;
                    863:        }
                    864: }
                    865: 
                    866: #ifndef HAVE_OSX_ACLS
                    867: static mode_t change_sacl_perms(SMB_ACL_T sacl, rsync_acl *racl, mode_t old_mode, mode_t mode)
                    868: {
                    869:        SMB_ACL_ENTRY_T entry;
                    870:        const char *errfun;
                    871:        int rc;
                    872: 
                    873:        if (S_ISDIR(mode)) {
                    874:                /* If the sticky bit is going on, it's not safe to allow all
                    875:                 * the new ACL to go into effect before it gets set. */
                    876: #ifdef SMB_ACL_LOSES_SPECIAL_MODE_BITS
                    877:                if (mode & S_ISVTX)
                    878:                        mode &= ~0077;
                    879: #else
                    880:                if (mode & S_ISVTX && !(old_mode & S_ISVTX))
                    881:                        mode &= ~0077;
                    882:        } else {
                    883:                /* If setuid or setgid is going off, it's not safe to allow all
                    884:                 * the new ACL to go into effect before they get cleared. */
                    885:                if ((old_mode & S_ISUID && !(mode & S_ISUID))
                    886:                 || (old_mode & S_ISGID && !(mode & S_ISGID)))
                    887:                        mode &= ~0077;
                    888: #endif
                    889:        }
                    890: 
                    891:        errfun = "sys_acl_get_entry";
                    892:        for (rc = sys_acl_get_entry(sacl, SMB_ACL_FIRST_ENTRY, &entry);
                    893:             rc == 1;
                    894:             rc = sys_acl_get_entry(sacl, SMB_ACL_NEXT_ENTRY, &entry)) {
                    895:                SMB_ACL_TAG_T tag_type;
                    896:                if ((rc = sys_acl_get_tag_type(entry, &tag_type)) != 0) {
                    897:                        errfun = "sys_acl_get_tag_type";
                    898:                        break;
                    899:                }
                    900:                switch (tag_type) {
                    901:                case SMB_ACL_USER_OBJ:
                    902:                        COE2( store_access_in_entry,((mode >> 6) & 7, entry) );
                    903:                        break;
                    904:                case SMB_ACL_GROUP_OBJ:
                    905:                        /* group is only empty when identical to group perms. */
                    906:                        if (racl->group_obj != NO_ENTRY)
                    907:                                break;
                    908:                        COE2( store_access_in_entry,((mode >> 3) & 7, entry) );
                    909:                        break;
                    910:                case SMB_ACL_MASK:
                    911: #ifndef HAVE_SOLARIS_ACLS
                    912: #ifndef ACLS_NEED_MASK
                    913:                        /* mask is only empty when we don't need it. */
                    914:                        if (racl->mask_obj == NO_ENTRY)
                    915:                                break;
                    916: #endif
                    917:                        COE2( store_access_in_entry,((mode >> 3) & 7, entry) );
                    918: #endif
                    919:                        break;
                    920:                case SMB_ACL_OTHER:
                    921:                        COE2( store_access_in_entry,(mode & 7, entry) );
                    922:                        break;
                    923:                }
                    924:        }
                    925:        if (rc) {
                    926:          error_exit:
                    927:                if (errfun) {
                    928:                        rsyserr(FERROR_XFER, errno, "change_sacl_perms: %s()",
                    929:                                errfun);
                    930:                }
                    931:                return (mode_t)-1;
                    932:        }
                    933: 
                    934: #ifdef SMB_ACL_LOSES_SPECIAL_MODE_BITS
                    935:        /* Ensure that chmod() will be called to restore any lost setid bits. */
                    936:        if (old_mode & (S_ISUID | S_ISGID | S_ISVTX)
                    937:         && BITS_EQUAL(old_mode, mode, CHMOD_BITS))
                    938:                old_mode &= ~(S_ISUID | S_ISGID | S_ISVTX);
                    939: #endif
                    940: 
                    941:        /* Return the mode of the file on disk, as we will set them. */
                    942:        return (old_mode & ~ACCESSPERMS) | (mode & ACCESSPERMS);
                    943: }
                    944: #endif
                    945: 
                    946: static int set_rsync_acl(const char *fname, acl_duo *duo_item,
                    947:                         SMB_ACL_TYPE_T type, stat_x *sxp, mode_t mode)
                    948: {
                    949:        if (type == SMB_ACL_TYPE_DEFAULT
                    950:         && duo_item->racl.user_obj == NO_ENTRY) {
                    951:                int rc;
                    952: #ifdef SUPPORT_XATTRS
                    953:                /* --fake-super support: delete default ACL from xattrs. */
                    954:                if (am_root < 0)
                    955:                        rc = del_def_xattr_acl(fname);
                    956:                else
                    957: #endif
                    958:                        rc = sys_acl_delete_def_file(fname);
                    959:                if (rc < 0) {
                    960:                        rsyserr(FERROR_XFER, errno, "set_acl: sys_acl_delete_def_file(%s)",
                    961:                                fname);
                    962:                        return -1;
                    963:                }
                    964: #ifdef SUPPORT_XATTRS
                    965:        } else if (am_root < 0) {
                    966:                /* --fake-super support: store ACLs in an xattr. */
                    967:                int cnt = duo_item->racl.names.count;
                    968:                size_t len = 4*4 + cnt * (4+4);
                    969:                char *buf = new_array(char, len);
                    970:                int rc;
                    971: 
                    972:                SIVAL(buf, 0, duo_item->racl.user_obj);
                    973:                SIVAL(buf, 4, duo_item->racl.group_obj);
                    974:                SIVAL(buf, 8, duo_item->racl.mask_obj);
                    975:                SIVAL(buf, 12, duo_item->racl.other_obj);
                    976: 
                    977:                if (cnt) {
                    978:                        char *bp = buf + 4*4;
                    979:                        id_access *ida = duo_item->racl.names.idas;
                    980:                        for ( ; cnt--; ida++, bp += 4+4) {
                    981:                                SIVAL(bp, 0, ida->id);
                    982:                                SIVAL(bp, 4, ida->access);
                    983:                        }
                    984:                }
                    985:                rc = set_xattr_acl(fname, type == SMB_ACL_TYPE_ACCESS, buf, len);
                    986:                free(buf);
                    987:                return rc;
                    988: #endif
                    989:        } else {
                    990:                mode_t cur_mode = sxp->st.st_mode;
                    991:                if (!duo_item->sacl
                    992:                 && !pack_smb_acl(&duo_item->sacl, &duo_item->racl))
                    993:                        return -1;
                    994: #ifdef HAVE_OSX_ACLS
                    995:                mode = 0; /* eliminate compiler warning */
                    996: #else
                    997:                if (type == SMB_ACL_TYPE_ACCESS) {
                    998:                        cur_mode = change_sacl_perms(duo_item->sacl, &duo_item->racl,
                    999:                                                     cur_mode, mode);
                   1000:                        if (cur_mode == (mode_t)-1)
                   1001:                                return 0;
                   1002:                }
                   1003: #endif
                   1004:                if (sys_acl_set_file(fname, type, duo_item->sacl) < 0) {
                   1005:                        rsyserr(FERROR_XFER, errno, "set_acl: sys_acl_set_file(%s, %s)",
                   1006:                                fname, str_acl_type(type));
                   1007:                        return -1;
                   1008:                }
                   1009:                if (type == SMB_ACL_TYPE_ACCESS)
                   1010:                        sxp->st.st_mode = cur_mode;
                   1011:        }
                   1012: 
                   1013:        return 0;
                   1014: }
                   1015: 
                   1016: /* Given a fname, this sets extended access ACL entries, the default ACL (for a
                   1017:  * dir), and the regular mode bits on the file.  Call this with fname set to
                   1018:  * NULL to just check if the ACL is different.
                   1019:  *
                   1020:  * If the ACL operation has a side-effect of changing the file's mode, the
                   1021:  * sxp->st.st_mode value will be changed to match.
                   1022:  *
                   1023:  * Returns 0 for an unchanged ACL, 1 for changed, -1 for failed. */
                   1024: int set_acl(const char *fname, const struct file_struct *file, stat_x *sxp, mode_t new_mode)
                   1025: {
                   1026:        int changed = 0;
                   1027:        int32 ndx;
                   1028:        BOOL eq;
                   1029: 
                   1030:        if (!dry_run && (read_only || list_only)) {
                   1031:                errno = EROFS;
                   1032:                return -1;
                   1033:        }
                   1034: 
                   1035:        ndx = F_ACL(file);
                   1036:        if (ndx >= 0 && (size_t)ndx < access_acl_list.count) {
                   1037:                acl_duo *duo_item = access_acl_list.items;
                   1038:                duo_item += ndx;
                   1039:                eq = sxp->acc_acl
                   1040:                  && rsync_acl_equal_enough(sxp->acc_acl, &duo_item->racl, new_mode);
                   1041:                if (!eq) {
                   1042:                        changed = 1;
                   1043:                        if (!dry_run && fname
                   1044:                         && set_rsync_acl(fname, duo_item, SMB_ACL_TYPE_ACCESS,
                   1045:                                          sxp, new_mode) < 0)
                   1046:                                return -1;
                   1047:                }
                   1048:        }
                   1049: 
                   1050:        if (!S_ISDIR(new_mode))
                   1051:                return changed;
                   1052: 
                   1053:        ndx = F_DIR_DEFACL(file);
                   1054:        if (ndx >= 0 && (size_t)ndx < default_acl_list.count) {
                   1055:                acl_duo *duo_item = default_acl_list.items;
                   1056:                duo_item += ndx;
                   1057:                eq = sxp->def_acl && rsync_acl_equal(sxp->def_acl, &duo_item->racl);
                   1058:                if (!eq) {
                   1059:                        changed = 1;
                   1060:                        if (!dry_run && fname
                   1061:                         && set_rsync_acl(fname, duo_item, SMB_ACL_TYPE_DEFAULT,
                   1062:                                          sxp, new_mode) < 0)
                   1063:                                return -1;
                   1064:                }
                   1065:        }
                   1066: 
                   1067:        return changed;
                   1068: }
                   1069: 
                   1070: /* Non-incremental recursion needs to convert all the received IDs.
                   1071:  * This is done in a single pass after receiving the whole file-list. */
                   1072: static void match_racl_ids(const item_list *racl_list)
                   1073: {
                   1074:        int list_cnt, name_cnt;
                   1075:        acl_duo *duo_item = racl_list->items;
                   1076:        for (list_cnt = racl_list->count; list_cnt--; duo_item++) {
                   1077:                ida_entries *idal = &duo_item->racl.names;
                   1078:                id_access *ida = idal->idas;
                   1079:                for (name_cnt = idal->count; name_cnt--; ida++) {
                   1080:                        if (ida->access & NAME_IS_USER)
                   1081:                                ida->id = match_uid(ida->id);
                   1082:                        else
                   1083:                                ida->id = match_gid(ida->id, NULL);
                   1084:                }
                   1085:        }
                   1086: }
                   1087: 
                   1088: void match_acl_ids(void)
                   1089: {
                   1090:        match_racl_ids(&access_acl_list);
                   1091:        match_racl_ids(&default_acl_list);
                   1092: }
                   1093: 
                   1094: /* This is used by dest_mode(). */
                   1095: int default_perms_for_dir(const char *dir)
                   1096: {
                   1097:        rsync_acl racl;
                   1098:        SMB_ACL_T sacl;
                   1099:        BOOL ok;
                   1100:        int perms;
                   1101: 
                   1102:        if (dir == NULL)
                   1103:                dir = ".";
                   1104:        perms = ACCESSPERMS & ~orig_umask;
                   1105:        /* Read the directory's default ACL.  If it has none, this will successfully return an empty ACL. */
                   1106:        sacl = sys_acl_get_file(dir, SMB_ACL_TYPE_DEFAULT);
                   1107:        if (sacl == NULL) {
                   1108:                /* Couldn't get an ACL.  Darn. */
                   1109:                switch (errno) {
                   1110:                case EINVAL:
                   1111:                        /* If SMB_ACL_TYPE_DEFAULT isn't valid, then the ACLs must be non-POSIX. */
                   1112:                        break;
                   1113: #ifdef ENOTSUP
                   1114:                case ENOTSUP:
                   1115: #endif
                   1116:                case ENOSYS:
                   1117:                        /* No ACLs are available. */
                   1118:                        break;
                   1119:                case ENOENT:
                   1120:                        if (dry_run) {
                   1121:                                /* We're doing a dry run, so the containing directory
                   1122:                                 * wasn't actually created.  Don't worry about it. */
                   1123:                                break;
                   1124:                        }
                   1125:                        /* Otherwise fall through. */
                   1126:                default:
                   1127:                        rprintf(FWARNING,
                   1128:                                "default_perms_for_dir: sys_acl_get_file(%s, %s): %s, falling back on umask\n",
                   1129:                                dir, str_acl_type(SMB_ACL_TYPE_DEFAULT), strerror(errno));
                   1130:                }
                   1131:                return perms;
                   1132:        }
                   1133: 
                   1134:        /* Convert it. */
                   1135:        racl = empty_rsync_acl;
                   1136:        ok = unpack_smb_acl(sacl, &racl);
                   1137:        sys_acl_free_acl(sacl);
                   1138:        if (!ok) {
                   1139:                rprintf(FWARNING, "default_perms_for_dir: unpack_smb_acl failed, falling back on umask\n");
                   1140:                return perms;
                   1141:        }
                   1142: 
                   1143:        /* Apply the permission-bit entries of the default ACL, if any. */
                   1144:        if (racl.user_obj != NO_ENTRY) {
                   1145:                perms = rsync_acl_get_perms(&racl);
                   1146:                if (verbose > 2)
                   1147:                        rprintf(FINFO, "got ACL-based default perms %o for directory %s\n", perms, dir);
                   1148:        }
                   1149: 
                   1150:        rsync_acl_free(&racl);
                   1151:        return perms;
                   1152: }
                   1153: 
                   1154: #endif /* SUPPORT_ACLS */

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