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>