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

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

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