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

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

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