Fixed failing hunks.
[rsync/rsync-patches.git] / acls.diff
CommitLineData
03019e41 1To use this patch, run these commands for a successful build:
fa26e11c 2
03019e41 3 patch -p1 <patches/acls.diff
27e96866 4 ./prepare-source
f787c90c 5 ./configure --enable-acl-support
fa26e11c
WD
6 make
7
a5e3a4cc
WD
8See the --acls (-A) option in the revised man page for a note on using this
9latest ACL-enabling patch to send files to an older ACL-enabled rsync.
10
9a7eef96
WD
11--- old/Makefile.in
12+++ new/Makefile.in
bdf1eee8 13@@ -26,15 +26,15 @@ VERSION=@VERSION@
fa26e11c
WD
14 .SUFFIXES:
15 .SUFFIXES: .c .o
16
17-HEADERS=byteorder.h config.h errcode.h proto.h rsync.h lib/pool_alloc.h
18+HEADERS=byteorder.h config.h errcode.h proto.h rsync.h smb_acls.h lib/pool_alloc.h
19 LIBOBJ=lib/wildmatch.o lib/compat.o lib/snprintf.o lib/mdfour.o \
0f6733d8
WD
20- lib/permstring.o lib/pool_alloc.o @LIBOBJS@
21+ lib/permstring.o lib/pool_alloc.o lib/sysacls.o @LIBOBJS@
4bf6f8c7
WD
22 ZLIBOBJ=zlib/deflate.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o \
23 zlib/trees.o zlib/zutil.o zlib/adler32.o zlib/compress.o zlib/crc32.o
590329e5
WD
24 OBJS1=flist.o rsync.o generator.o receiver.o cleanup.o sender.o exclude.o \
25 util.o main.o checksum.o match.o syscall.o log.o backup.o
26 OBJS2=options.o io.o compat.o hlink.o token.o uidlist.o socket.o \
610969d1
WD
27- fileio.o batch.o clientname.o chmod.o
28+ fileio.o batch.o clientname.o chmod.o acls.o
fa26e11c
WD
29 OBJS3=progress.o pipe.o
30 DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o
31 popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \
9a7eef96
WD
32--- old/acls.c
33+++ new/acls.c
3b3650bb 34@@ -0,0 +1,1093 @@
c32e843a
WD
35+/*
36+ * Handle passing Access Control Lists between systems.
37+ *
38+ * Copyright (C) 1996 Andrew Tridgell
39+ * Copyright (C) 1996 Paul Mackerras
c32e843a
WD
40+ * Copyright (C) 2006 Wayne Davison
41+ *
42+ * This program is free software; you can redistribute it and/or modify
43+ * it under the terms of the GNU General Public License as published by
44+ * the Free Software Foundation; either version 2 of the License, or
45+ * (at your option) any later version.
46+ *
47+ * This program is distributed in the hope that it will be useful,
48+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
49+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
50+ * GNU General Public License for more details.
51+ *
52+ * You should have received a copy of the GNU General Public License along
53+ * with this program; if not, write to the Free Software Foundation, Inc.,
54+ * 51 Franklin Street - Fifth Floor, Boston, MA 02110-1301, USA.
55+ */
fa26e11c
WD
56+
57+#include "rsync.h"
0f6733d8 58+#include "lib/sysacls.h"
fa26e11c 59+
4df546eb 60+#ifdef SUPPORT_ACLS
fa26e11c 61+
fa26e11c 62+extern int dry_run;
0909ae28
WD
63+extern int read_only;
64+extern int list_only;
90fa6d68 65+extern int orig_umask;
0870c22a
WD
66+
67+/* === ACL structures === */
fa26e11c
WD
68+
69+typedef struct {
70+ id_t id;
71+ uchar access;
c6437996 72+} id_access;
fa26e11c
WD
73+
74+typedef struct {
c6437996 75+ id_access *idas;
0870c22a
WD
76+ int count;
77+} ida_entries;
c6437996 78+
0870c22a
WD
79+#define NO_ENTRY ((uchar)0x80)
80+typedef struct rsync_acl {
81+ ida_entries users;
82+ ida_entries groups;
83+ /* These will be NO_ENTRY if there's no such entry. */
c6437996
WD
84+ uchar user_obj;
85+ uchar group_obj;
86+ uchar mask;
87+ uchar other;
fa26e11c
WD
88+} rsync_acl;
89+
0870c22a
WD
90+typedef struct {
91+ rsync_acl racl;
92+ SMB_ACL_T sacl;
93+} acl_duo;
94+
cd1d1a9d 95+static const rsync_acl empty_rsync_acl = {
0870c22a 96+ {NULL, 0}, {NULL, 0}, NO_ENTRY, NO_ENTRY, NO_ENTRY, NO_ENTRY
56294981 97+};
8db8e7d2 98+
6250eb3e
WD
99+static item_list access_acl_list = EMPTY_ITEM_LIST;
100+static item_list default_acl_list = EMPTY_ITEM_LIST;
0870c22a
WD
101+
102+/* === Calculations on ACL types === */
103+
104+static const char *str_acl_type(SMB_ACL_TYPE_T type)
105+{
106+ return type == SMB_ACL_TYPE_ACCESS ? "SMB_ACL_TYPE_ACCESS"
107+ : type == SMB_ACL_TYPE_DEFAULT ? "SMB_ACL_TYPE_DEFAULT"
108+ : "unknown SMB_ACL_TYPE_T";
109+}
110+
8db8e7d2
WD
111+#define OTHER_TYPE(t) (SMB_ACL_TYPE_ACCESS+SMB_ACL_TYPE_DEFAULT-(t))
112+#define BUMP_TYPE(t) ((t = OTHER_TYPE(t)) == SMB_ACL_TYPE_DEFAULT)
fa26e11c 113+
56294981
WD
114+static int count_racl_entries(const rsync_acl *racl)
115+{
116+ return racl->users.count + racl->groups.count
0870c22a
WD
117+ + (racl->user_obj != NO_ENTRY)
118+ + (racl->group_obj != NO_ENTRY)
119+ + (racl->mask != NO_ENTRY)
120+ + (racl->other != NO_ENTRY);
56294981
WD
121+}
122+
123+static int calc_sacl_entries(const rsync_acl *racl)
9a7b72b5 124+{
0870c22a 125+ /* A System ACL always gets user/group/other permission entries. */
c6437996 126+ return racl->users.count + racl->groups.count
56294981
WD
127+#ifdef ACLS_NEED_MASK
128+ + 4;
129+#else
0870c22a 130+ + (racl->mask != NO_ENTRY) + 3;
56294981 131+#endif
c6437996
WD
132+}
133+
0870c22a
WD
134+/* Extracts and returns the permission bits from the ACL. This cannot be
135+ * called on an rsync_acl that has NO_ENTRY in any spot but the mask. */
9a7b72b5
WD
136+static int rsync_acl_get_perms(const rsync_acl *racl)
137+{
8eb3e3ae 138+ return (racl->user_obj << 6)
0870c22a 139+ + ((racl->mask != NO_ENTRY ? racl->mask : racl->group_obj) << 3)
8eb3e3ae 140+ + racl->other;
c6437996
WD
141+}
142+
0870c22a
WD
143+/* Removes the permission-bit entries from the ACL because these
144+ * can be reconstructed from the file's mode. */
9a7b72b5
WD
145+static void rsync_acl_strip_perms(rsync_acl *racl)
146+{
0870c22a
WD
147+ racl->user_obj = NO_ENTRY;
148+ if (racl->mask == NO_ENTRY)
149+ racl->group_obj = NO_ENTRY;
150+ else {
151+ if (racl->group_obj == racl->mask)
152+ racl->group_obj = NO_ENTRY;
153+ racl->mask = NO_ENTRY;
154+ }
155+ racl->other = NO_ENTRY;
c6437996 156+}
34a409bc 157+
0870c22a
WD
158+/* Given an empty rsync_acl, fake up the permission bits. */
159+static void rsync_acl_fake_perms(rsync_acl *racl, mode_t mode)
fa26e11c 160+{
0870c22a
WD
161+ racl->user_obj = (mode >> 6) & 7;
162+ racl->group_obj = (mode >> 3) & 7;
0870c22a
WD
163+ racl->other = mode & 7;
164+}
165+
166+/* === Rsync ACL functions === */
167+
168+static BOOL ida_entries_equal(const ida_entries *ial1, const ida_entries *ial2)
169+{
170+ id_access *ida1, *ida2;
171+ int count = ial1->count;
172+ if (count != ial2->count)
173+ return False;
174+ ida1 = ial1->idas;
175+ ida2 = ial2->idas;
176+ for (; count--; ida1++, ida2++) {
177+ if (ida1->access != ida2->access || ida1->id != ida2->id)
178+ return False;
179+ }
180+ return True;
181+}
fa26e11c 182+
98ccc74a 183+static BOOL rsync_acl_equal(const rsync_acl *racl1, const rsync_acl *racl2)
0870c22a 184+{
adabede5
WD
185+ return racl1->user_obj == racl2->user_obj
186+ && racl1->group_obj == racl2->group_obj
187+ && racl1->mask == racl2->mask
188+ && racl1->other == racl2->other
189+ && ida_entries_equal(&racl1->users, &racl2->users)
190+ && ida_entries_equal(&racl1->groups, &racl2->groups);
0870c22a
WD
191+}
192+
193+/* Are the extended (non-permission-bit) entries equal? If so, the rest of
194+ * the ACL will be handled by the normal mode-preservation code. This is
195+ * only meaningful for access ACLs! Note: the 1st arg is a fully-populated
196+ * rsync_acl, but the 2nd parameter can be a condensed rsync_acl, which means
adabede5 197+ * that it might have several of its permission objects set to NO_ENTRY. */
98ccc74a
WD
198+static BOOL rsync_acl_equal_enough(const rsync_acl *racl1,
199+ const rsync_acl *racl2, mode_t m)
0870c22a
WD
200+{
201+ if ((racl1->mask ^ racl2->mask) & NO_ENTRY)
202+ return False; /* One has a mask and the other doesn't */
fa26e11c 203+
0870c22a
WD
204+ /* When there's a mask, the group_obj becomes an extended entry. */
205+ if (racl1->mask != NO_ENTRY) {
206+ /* A condensed rsync_acl with a mask can only have no
207+ * group_obj when it was identical to the mask. This
208+ * means that it was also identical to the group attrs
209+ * from the mode. */
210+ if (racl2->group_obj == NO_ENTRY) {
211+ if (racl1->group_obj != ((m >> 3) & 7))
212+ return False;
213+ } else if (racl1->group_obj != racl2->group_obj)
214+ return False;
fa26e11c 215+ }
0870c22a
WD
216+ return ida_entries_equal(&racl1->users, &racl2->users)
217+ && ida_entries_equal(&racl1->groups, &racl2->groups);
fa26e11c
WD
218+}
219+
220+static void rsync_acl_free(rsync_acl *racl)
221+{
8eb3e3ae
WD
222+ if (racl->users.idas)
223+ free(racl->users.idas);
224+ if (racl->groups.idas)
225+ free(racl->groups.idas);
226+ *racl = empty_rsync_acl;
fa26e11c
WD
227+}
228+
98ccc74a 229+void free_acl(statx *sxp)
0870c22a
WD
230+{
231+ if (sxp->acc_acl) {
232+ rsync_acl_free(sxp->acc_acl);
233+ free(sxp->acc_acl);
234+ sxp->acc_acl = NULL;
235+ }
236+ if (sxp->def_acl) {
237+ rsync_acl_free(sxp->def_acl);
238+ free(sxp->def_acl);
239+ sxp->def_acl = NULL;
240+ }
241+}
242+
c6437996 243+static int id_access_sorter(const void *r1, const void *r2)
fa26e11c 244+{
c6437996
WD
245+ id_access *ida1 = (id_access *)r1;
246+ id_access *ida2 = (id_access *)r2;
247+ id_t rid1 = ida1->id, rid2 = ida2->id;
fa26e11c
WD
248+ return rid1 == rid2 ? 0 : rid1 < rid2 ? -1 : 1;
249+}
250+
0870c22a 251+static void sort_ida_entries(ida_entries *idal)
fa26e11c 252+{
c6437996 253+ if (!idal->count)
fa26e11c 254+ return;
0870c22a 255+ qsort(idal->idas, idal->count, sizeof idal->idas[0], id_access_sorter);
fa26e11c
WD
256+}
257+
0870c22a
WD
258+/* Transfer the count id_access items out of the temp_ida_list into either
259+ * the users or groups ida_entries list in racl. */
260+static void save_idas(item_list *temp_ida_list, rsync_acl *racl, SMB_ACL_TAG_T type)
261+{
262+ id_access *idas;
263+ ida_entries *ent;
264+
265+ if (temp_ida_list->count) {
266+ int cnt = temp_ida_list->count;
267+ id_access *temp_idas = temp_ida_list->items;
268+ if (!(idas = new_array(id_access, cnt)))
269+ out_of_memory("save_idas");
270+ memcpy(idas, temp_idas, cnt * sizeof *temp_idas);
271+ } else
272+ idas = NULL;
273+
274+ ent = type == SMB_ACL_USER ? &racl->users : &racl->groups;
275+
276+ if (ent->count) {
277+ rprintf(FERROR, "save_idas: disjoint list found for type %d\n", type);
278+ exit_cleanup(RERR_UNSUPPORTED);
279+ }
280+ ent->count = temp_ida_list->count;
281+ ent->idas = idas;
282+
283+ /* Truncate the temporary list now that its idas have been saved. */
284+ temp_ida_list->count = 0;
285+}
286+
287+/* === System ACLs === */
288+
adabede5 289+/* Unpack system ACL -> rsync ACL verbatim. Return whether we succeeded. */
fa26e11c
WD
290+static BOOL unpack_smb_acl(rsync_acl *racl, SMB_ACL_T sacl)
291+{
6250eb3e 292+ static item_list temp_ida_list = EMPTY_ITEM_LIST;
0870c22a 293+ SMB_ACL_TAG_T prior_list_type = 0;
fa26e11c 294+ SMB_ACL_ENTRY_T entry;
fa26e11c 295+ const char *errfun;
c6437996
WD
296+ int rc;
297+
fa26e11c
WD
298+ errfun = "sys_acl_get_entry";
299+ for (rc = sys_acl_get_entry(sacl, SMB_ACL_FIRST_ENTRY, &entry);
300+ rc == 1;
301+ rc = sys_acl_get_entry(sacl, SMB_ACL_NEXT_ENTRY, &entry)) {
c6437996 302+ SMB_ACL_TAG_T tag_type;
fa26e11c 303+ SMB_ACL_PERMSET_T permset;
c6437996 304+ uchar access;
fa26e11c 305+ void *qualifier;
c6437996 306+ id_access *ida;
c6437996 307+ if ((rc = sys_acl_get_tag_type(entry, &tag_type))) {
fa26e11c
WD
308+ errfun = "sys_acl_get_tag_type";
309+ break;
310+ }
311+ if ((rc = sys_acl_get_permset(entry, &permset))) {
312+ errfun = "sys_acl_get_tag_type";
313+ break;
314+ }
c6437996
WD
315+ access = (sys_acl_get_perm(permset, SMB_ACL_READ) ? 4 : 0)
316+ | (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? 2 : 0)
317+ | (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? 1 : 0);
0870c22a 318+ /* continue == done with entry; break == store in temporary ida list */
c6437996
WD
319+ switch (tag_type) {
320+ case SMB_ACL_USER_OBJ:
0870c22a 321+ if (racl->user_obj == NO_ENTRY)
c6437996
WD
322+ racl->user_obj = access;
323+ else
324+ rprintf(FINFO, "unpack_smb_acl: warning: duplicate USER_OBJ entry ignored\n");
325+ continue;
fa26e11c 326+ case SMB_ACL_USER:
c6437996
WD
327+ break;
328+ case SMB_ACL_GROUP_OBJ:
0870c22a 329+ if (racl->group_obj == NO_ENTRY)
c6437996
WD
330+ racl->group_obj = access;
331+ else
332+ rprintf(FINFO, "unpack_smb_acl: warning: duplicate GROUP_OBJ entry ignored\n");
333+ continue;
fa26e11c
WD
334+ case SMB_ACL_GROUP:
335+ break;
c6437996 336+ case SMB_ACL_MASK:
0870c22a 337+ if (racl->mask == NO_ENTRY)
c6437996
WD
338+ racl->mask = access;
339+ else
340+ rprintf(FINFO, "unpack_smb_acl: warning: duplicate MASK entry ignored\n");
341+ continue;
342+ case SMB_ACL_OTHER:
0870c22a 343+ if (racl->other == NO_ENTRY)
c6437996
WD
344+ racl->other = access;
345+ else
346+ rprintf(FINFO, "unpack_smb_acl: warning: duplicate OTHER entry ignored\n");
347+ continue;
fa26e11c 348+ default:
c6437996 349+ rprintf(FINFO, "unpack_smb_acl: warning: entry with unrecognized tag type ignored\n");
fa26e11c
WD
350+ continue;
351+ }
352+ if (!(qualifier = sys_acl_get_qualifier(entry))) {
353+ errfun = "sys_acl_get_tag_type";
354+ rc = EINVAL;
355+ break;
356+ }
0870c22a
WD
357+ if (tag_type != prior_list_type) {
358+ if (prior_list_type)
359+ save_idas(&temp_ida_list, racl, prior_list_type);
360+ prior_list_type = tag_type;
361+ }
645e162c 362+ ida = EXPAND_ITEM_LIST(&temp_ida_list, id_access, -10);
c6437996
WD
363+ ida->id = *((id_t *)qualifier);
364+ ida->access = access;
365+ sys_acl_free_qualifier(qualifier, tag_type);
fa26e11c
WD
366+ }
367+ if (rc) {
0870c22a 368+ rsyserr(FERROR, errno, "unpack_smb_acl: %s()", errfun);
fa26e11c
WD
369+ rsync_acl_free(racl);
370+ return False;
371+ }
0870c22a
WD
372+ if (prior_list_type)
373+ save_idas(&temp_ida_list, racl, prior_list_type);
c6437996 374+
0870c22a
WD
375+ sort_ida_entries(&racl->users);
376+ sort_ida_entries(&racl->groups);
c6437996 377+
8eb3e3ae 378+#ifdef ACLS_NEED_MASK
aea6b054 379+ if (!racl->users.count && !racl->groups.count && racl->mask != NO_ENTRY) {
8eb3e3ae
WD
380+ /* Throw away a superfluous mask, but mask off the
381+ * group perms with it first. */
382+ racl->group_obj &= racl->mask;
0870c22a 383+ racl->mask = NO_ENTRY;
8eb3e3ae
WD
384+ }
385+#endif
386+
fa26e11c
WD
387+ return True;
388+}
389+
0870c22a 390+/* Synactic sugar for system calls */
fa26e11c 391+
0e879f7f 392+#define CALL_OR_ERROR(func,args,str) \
c6437996
WD
393+ do { \
394+ if (func args) { \
0e879f7f 395+ errfun = str; \
c6437996
WD
396+ goto error_exit; \
397+ } \
398+ } while (0)
399+
0e879f7f
WD
400+#define COE(func,args) CALL_OR_ERROR(func,args,#func)
401+#define COE2(func,args) CALL_OR_ERROR(func,args,NULL)
402+
0870c22a 403+/* Store the permissions in the system ACL entry. */
0e879f7f 404+static int store_access_in_entry(uchar access, SMB_ACL_ENTRY_T entry)
fa26e11c 405+{
c6437996
WD
406+ const char *errfun = NULL;
407+ SMB_ACL_PERMSET_T permset;
408+
409+ COE( sys_acl_get_permset,(entry, &permset) );
410+ COE( sys_acl_clear_perms,(permset) );
411+ if (access & 4)
412+ COE( sys_acl_add_perm,(permset, SMB_ACL_READ) );
413+ if (access & 2)
414+ COE( sys_acl_add_perm,(permset, SMB_ACL_WRITE) );
415+ if (access & 1)
416+ COE( sys_acl_add_perm,(permset, SMB_ACL_EXECUTE) );
417+ COE( sys_acl_set_permset,(entry, permset) );
418+
0e879f7f 419+ return 0;
c6437996 420+
0e879f7f 421+ error_exit:
0870c22a 422+ rsyserr(FERROR, errno, "store_access_in_entry %s()", errfun);
0e879f7f 423+ return -1;
fa26e11c 424+}
fa26e11c 425+
adabede5 426+/* Pack rsync ACL -> system ACL verbatim. Return whether we succeeded. */
c6437996 427+static BOOL pack_smb_acl(SMB_ACL_T *smb_acl, const rsync_acl *racl)
fa26e11c 428+{
8eb3e3ae
WD
429+#ifdef ACLS_NEED_MASK
430+ uchar mask_bits;
431+#endif
c6437996
WD
432+ size_t count;
433+ id_access *ida;
fa26e11c 434+ const char *errfun = NULL;
c6437996 435+ SMB_ACL_ENTRY_T entry;
69aaf170 436+
56294981 437+ if (!(*smb_acl = sys_acl_init(calc_sacl_entries(racl)))) {
0870c22a 438+ rsyserr(FERROR, errno, "pack_smb_acl: sys_acl_init()");
fa26e11c
WD
439+ return False;
440+ }
69aaf170 441+
c6437996
WD
442+ COE( sys_acl_create_entry,(smb_acl, &entry) );
443+ COE( sys_acl_set_tag_type,(entry, SMB_ACL_USER_OBJ) );
56294981 444+ COE2( store_access_in_entry,(racl->user_obj & 7, entry) );
c6437996 445+
8eb3e3ae 446+ for (ida = racl->users.idas, count = racl->users.count; count--; ida++) {
c6437996
WD
447+ COE( sys_acl_create_entry,(smb_acl, &entry) );
448+ COE( sys_acl_set_tag_type,(entry, SMB_ACL_USER) );
449+ COE( sys_acl_set_qualifier,(entry, (void*)&ida->id) );
0e879f7f 450+ COE2( store_access_in_entry,(ida->access, entry) );
c6437996
WD
451+ }
452+
453+ COE( sys_acl_create_entry,(smb_acl, &entry) );
454+ COE( sys_acl_set_tag_type,(entry, SMB_ACL_GROUP_OBJ) );
56294981 455+ COE2( store_access_in_entry,(racl->group_obj & 7, entry) );
c6437996 456+
8eb3e3ae 457+ for (ida = racl->groups.idas, count = racl->groups.count; count--; ida++) {
c6437996
WD
458+ COE( sys_acl_create_entry,(smb_acl, &entry) );
459+ COE( sys_acl_set_tag_type,(entry, SMB_ACL_GROUP) );
460+ COE( sys_acl_set_qualifier,(entry, (void*)&ida->id) );
0e879f7f 461+ COE2( store_access_in_entry,(ida->access, entry) );
c6437996 462+ }
8eb3e3ae
WD
463+
464+#ifdef ACLS_NEED_MASK
0870c22a 465+ mask_bits = racl->mask == NO_ENTRY ? racl->group_obj & 7 : racl->mask;
8eb3e3ae
WD
466+ COE( sys_acl_create_entry,(smb_acl, &entry) );
467+ COE( sys_acl_set_tag_type,(entry, SMB_ACL_MASK) );
468+ COE2( store_access_in_entry,(mask_bits, entry) );
469+#else
0870c22a 470+ if (racl->mask != NO_ENTRY) {
c6437996
WD
471+ COE( sys_acl_create_entry,(smb_acl, &entry) );
472+ COE( sys_acl_set_tag_type,(entry, SMB_ACL_MASK) );
0e879f7f 473+ COE2( store_access_in_entry,(racl->mask, entry) );
c6437996 474+ }
56294981 475+#endif
c6437996
WD
476+
477+ COE( sys_acl_create_entry,(smb_acl, &entry) );
478+ COE( sys_acl_set_tag_type,(entry, SMB_ACL_OTHER) );
56294981 479+ COE2( store_access_in_entry,(racl->other & 7, entry) );
c6437996
WD
480+
481+#ifdef DEBUG
482+ if (sys_acl_valid(*smb_acl) < 0)
0870c22a 483+ rprintf(FERROR, "pack_smb_acl: warning: system says the ACL I packed is invalid\n");
c6437996
WD
484+#endif
485+
486+ return True;
487+
0e879f7f
WD
488+ error_exit:
489+ if (errfun) {
0870c22a 490+ rsyserr(FERROR, errno, "pack_smb_acl %s()", errfun);
0e879f7f 491+ }
c6437996
WD
492+ sys_acl_free_acl(*smb_acl);
493+ return False;
494+}
495+
0870c22a
WD
496+static int find_matching_rsync_acl(SMB_ACL_TYPE_T type,
497+ const item_list *racl_list,
498+ const rsync_acl *racl)
c6437996 499+{
0870c22a
WD
500+ static int access_match = -1, default_match = -1;
501+ int *match = type == SMB_ACL_TYPE_ACCESS ? &access_match : &default_match;
502+ size_t count = racl_list->count;
c6437996 503+
0870c22a
WD
504+ /* If this is the first time through or we didn't match the last
505+ * time, then start at the end of the list, which should be the
506+ * best place to start hunting. */
507+ if (*match == -1)
508+ *match = racl_list->count - 1;
509+ while (count--) {
510+ rsync_acl *base = racl_list->items;
98ccc74a 511+ if (rsync_acl_equal(base + *match, racl))
0870c22a
WD
512+ return *match;
513+ if (!(*match)--)
514+ *match = racl_list->count - 1;
c6437996
WD
515+ }
516+
0870c22a
WD
517+ *match = -1;
518+ return *match;
519+}
520+
adabede5 521+/* Return the Access Control List for the given filename. */
98ccc74a 522+int get_acl(const char *fname, statx *sxp)
0870c22a
WD
523+{
524+ SMB_ACL_TYPE_T type;
525+
526+ if (S_ISLNK(sxp->st.st_mode))
527+ return 0;
528+
529+ type = SMB_ACL_TYPE_ACCESS;
530+ do {
531+ SMB_ACL_T sacl = sys_acl_get_file(fname, type);
532+ rsync_acl *racl = new(rsync_acl);
533+
534+ if (!racl)
98ccc74a 535+ out_of_memory("get_acl");
b6c2bb12 536+ *racl = empty_rsync_acl;
0870c22a
WD
537+ if (type == SMB_ACL_TYPE_ACCESS)
538+ sxp->acc_acl = racl;
539+ else
540+ sxp->def_acl = racl;
541+
542+ if (sacl) {
543+ BOOL ok = unpack_smb_acl(racl, sacl);
544+
545+ sys_acl_free_acl(sacl);
546+ if (!ok) {
98ccc74a 547+ free_acl(sxp);
0870c22a
WD
548+ return -1;
549+ }
70891d26 550+ } else if (errno == ENOTSUP || errno == ENOSYS) {
0870c22a 551+ /* ACLs are not supported, so pretend we have a basic ACL. */
0870c22a
WD
552+ if (type == SMB_ACL_TYPE_ACCESS)
553+ rsync_acl_fake_perms(racl, sxp->st.st_mode);
554+ } else {
98ccc74a 555+ rsyserr(FERROR, errno, "get_acl: sys_acl_get_file(%s, %s)",
0870c22a 556+ fname, str_acl_type(type));
98ccc74a 557+ free_acl(sxp);
0870c22a 558+ return -1;
56294981 559+ }
0870c22a
WD
560+ } while (BUMP_TYPE(type) && S_ISDIR(sxp->st.st_mode));
561+
562+ return 0;
563+}
564+
565+/* === Send functions === */
566+
567+/* The general strategy with the tag_type <-> character mapping is that
568+ * lowercase implies that no qualifier follows, where uppercase does.
adabede5 569+ * A similar idiom for the ACL type (access or default) itself, but
0870c22a
WD
570+ * lowercase in this instance means there's no ACL following, so the
571+ * ACL is a repeat, so the receiver should reuse the last of the same
572+ * type ACL. */
573+
574+/* Send the ida list over the file descriptor. */
575+static void send_ida_entries(int f, const ida_entries *idal, char tag_char)
576+{
577+ id_access *ida;
578+ size_t count = idal->count;
579+ for (ida = idal->idas; count--; ida++) {
580+ write_byte(f, tag_char);
581+ write_byte(f, ida->access);
582+ write_int(f, ida->id);
583+ /* FIXME: sorta wasteful: we should maybe buffer as
584+ * many ids as max(ACL_USER + ACL_GROUP) objects to
585+ * keep from making so many calls. */
586+ if (tag_char == 'U')
587+ add_uid(ida->id);
588+ else
589+ add_gid(ida->id);
fa26e11c 590+ }
0870c22a
WD
591+}
592+
adabede5 593+/* Send an rsync ACL over the file descriptor. */
0870c22a
WD
594+static void send_rsync_acl(int f, const rsync_acl *racl)
595+{
596+ size_t count = count_racl_entries(racl);
597+ write_int(f, count);
598+ if (racl->user_obj != NO_ENTRY) {
599+ write_byte(f, 'u');
600+ write_byte(f, racl->user_obj);
601+ }
602+ send_ida_entries(f, &racl->users, 'U');
603+ if (racl->group_obj != NO_ENTRY) {
604+ write_byte(f, 'g');
605+ write_byte(f, racl->group_obj);
fa26e11c 606+ }
0870c22a
WD
607+ send_ida_entries(f, &racl->groups, 'G');
608+ if (racl->mask != NO_ENTRY) {
609+ write_byte(f, 'm');
610+ write_byte(f, racl->mask);
611+ }
612+ if (racl->other != NO_ENTRY) {
613+ write_byte(f, 'o');
614+ write_byte(f, racl->other);
615+ }
616+}
c6437996 617+
98ccc74a 618+/* Send the ACL from the statx structure down the indicated file descriptor.
0870c22a 619+ * This also frees the ACL data. */
98ccc74a 620+void send_acl(statx *sxp, int f)
0870c22a
WD
621+{
622+ SMB_ACL_TYPE_T type;
623+ rsync_acl *racl, *new_racl;
624+ item_list *racl_list;
5d2612ca 625+ int ndx;
53c1073a 626+
0870c22a
WD
627+ if (S_ISLNK(sxp->st.st_mode))
628+ return;
629+
630+ type = SMB_ACL_TYPE_ACCESS;
631+ racl = sxp->acc_acl;
632+ racl_list = &access_acl_list;
633+ do {
5d2612ca
WD
634+ if (!racl) {
635+ racl = new(rsync_acl);
636+ if (!racl)
637+ out_of_memory("send_acl");
638+ *racl = empty_rsync_acl;
639+ if (type == SMB_ACL_TYPE_ACCESS) {
640+ rsync_acl_fake_perms(racl, sxp->st.st_mode);
641+ sxp->acc_acl = racl;
642+ } else
643+ sxp->def_acl = racl;
644+ }
0870c22a 645+
70891d26
WD
646+ /* Avoid sending values that can be inferred from other data. */
647+ if (type == SMB_ACL_TYPE_ACCESS)
0870c22a
WD
648+ rsync_acl_strip_perms(racl);
649+ if ((ndx = find_matching_rsync_acl(type, racl_list, racl)) != -1) {
650+ write_byte(f, type == SMB_ACL_TYPE_ACCESS ? 'a' : 'd');
651+ write_int(f, ndx);
0870c22a 652+ } else {
645e162c 653+ new_racl = EXPAND_ITEM_LIST(racl_list, rsync_acl, 1000);
0870c22a
WD
654+ write_byte(f, type == SMB_ACL_TYPE_ACCESS ? 'A' : 'D');
655+ send_rsync_acl(f, racl);
656+ *new_racl = *racl;
657+ *racl = empty_rsync_acl;
658+ }
659+ racl = sxp->def_acl;
660+ racl_list = &default_acl_list;
661+ } while (BUMP_TYPE(type) && S_ISDIR(sxp->st.st_mode));
662+
98ccc74a 663+ free_acl(sxp);
fa26e11c
WD
664+}
665+
0870c22a
WD
666+/* === Receive functions === */
667+
56294981 668+static void receive_rsync_acl(rsync_acl *racl, int f, SMB_ACL_TYPE_T type)
fa26e11c 669+{
6250eb3e 670+ static item_list temp_ida_list = EMPTY_ITEM_LIST;
0870c22a 671+ SMB_ACL_TAG_T tag_type = 0, prior_list_type = 0;
090d78e1 672+ uchar computed_mask_bits = 0;
c6437996 673+ id_access *ida;
ad625644
WD
674+ size_t count;
675+
676+ if (!(count = read_int(f)))
fa26e11c 677+ return;
ad625644 678+
fa26e11c 679+ while (count--) {
dfadc68a 680+ char tag = read_byte(f);
c6437996
WD
681+ uchar access = read_byte(f);
682+ if (access & ~ (4 | 2 | 1)) {
683+ rprintf(FERROR, "receive_rsync_acl: bogus permset %o\n",
684+ access);
685+ exit_cleanup(RERR_STREAMIO);
686+ }
fa26e11c
WD
687+ switch (tag) {
688+ case 'u':
0870c22a 689+ if (racl->user_obj != NO_ENTRY) {
c6437996
WD
690+ rprintf(FERROR, "receive_rsync_acl: error: duplicate USER_OBJ entry\n");
691+ exit_cleanup(RERR_STREAMIO);
692+ }
693+ racl->user_obj = access;
694+ continue;
fa26e11c 695+ case 'U':
0870c22a 696+ tag_type = SMB_ACL_USER;
fa26e11c
WD
697+ break;
698+ case 'g':
0870c22a 699+ if (racl->group_obj != NO_ENTRY) {
c6437996
WD
700+ rprintf(FERROR, "receive_rsync_acl: error: duplicate GROUP_OBJ entry\n");
701+ exit_cleanup(RERR_STREAMIO);
702+ }
703+ racl->group_obj = access;
704+ continue;
fa26e11c 705+ case 'G':
0870c22a 706+ tag_type = SMB_ACL_GROUP;
fa26e11c
WD
707+ break;
708+ case 'm':
0870c22a 709+ if (racl->mask != NO_ENTRY) {
c6437996
WD
710+ rprintf(FERROR, "receive_rsync_acl: error: duplicate MASK entry\n");
711+ exit_cleanup(RERR_STREAMIO);
712+ }
713+ racl->mask = access;
714+ continue;
715+ case 'o':
0870c22a 716+ if (racl->other != NO_ENTRY) {
c6437996
WD
717+ rprintf(FERROR, "receive_rsync_acl: error: duplicate OTHER entry\n");
718+ exit_cleanup(RERR_STREAMIO);
719+ }
720+ racl->other = access;
721+ continue;
fa26e11c
WD
722+ default:
723+ rprintf(FERROR, "receive_rsync_acl: unknown tag %c\n",
724+ tag);
725+ exit_cleanup(RERR_STREAMIO);
726+ }
0870c22a
WD
727+ if (tag_type != prior_list_type) {
728+ if (prior_list_type)
729+ save_idas(&temp_ida_list, racl, prior_list_type);
730+ prior_list_type = tag_type;
731+ }
645e162c 732+ ida = EXPAND_ITEM_LIST(&temp_ida_list, id_access, -10);
c6437996
WD
733+ ida->access = access;
734+ ida->id = read_int(f);
090d78e1 735+ computed_mask_bits |= access;
c6437996 736+ }
0870c22a
WD
737+ if (prior_list_type)
738+ save_idas(&temp_ida_list, racl, prior_list_type);
c6437996 739+
56294981
WD
740+ if (type == SMB_ACL_TYPE_DEFAULT) {
741+ /* Ensure that these are never unset. */
0870c22a 742+ if (racl->user_obj == NO_ENTRY)
56294981 743+ racl->user_obj = 7;
0870c22a 744+ if (racl->group_obj == NO_ENTRY)
56294981 745+ racl->group_obj = 0;
0870c22a 746+ if (racl->other == NO_ENTRY)
56294981
WD
747+ racl->other = 0;
748+ }
8eb3e3ae 749+
c6437996 750+ if (!racl->users.count && !racl->groups.count) {
8eb3e3ae 751+ /* If we received a superfluous mask, throw it away. */
0870c22a 752+ if (racl->mask != NO_ENTRY) {
8eb3e3ae 753+ /* Mask off the group perms with it first. */
0870c22a
WD
754+ racl->group_obj &= racl->mask | NO_ENTRY;
755+ racl->mask = NO_ENTRY;
fa26e11c 756+ }
0870c22a 757+ } else if (racl->mask == NO_ENTRY) /* Must be non-empty with lists. */
56294981 758+ racl->mask = computed_mask_bits | (racl->group_obj & 7);
fa26e11c
WD
759+}
760+
0870c22a 761+/* Receive the ACL info the sender has included for this file-list entry. */
98ccc74a 762+void receive_acl(struct file_struct *file, int f)
fa26e11c 763+{
8db8e7d2 764+ SMB_ACL_TYPE_T type;
0870c22a 765+ item_list *racl_list;
36aa3171 766+
162234a7 767+ if (S_ISLNK(file->mode))
fa26e11c 768+ return;
36aa3171 769+
8db8e7d2 770+ type = SMB_ACL_TYPE_ACCESS;
0870c22a 771+ racl_list = &access_acl_list;
8db8e7d2 772+ do {
0870c22a
WD
773+ char tag = read_byte(f);
774+ int ndx;
fa26e11c 775+
fa26e11c 776+ if (tag == 'A' || tag == 'a') {
8db8e7d2 777+ if (type != SMB_ACL_TYPE_ACCESS) {
fa26e11c 778+ rprintf(FERROR, "receive_acl %s: duplicate access ACL\n",
f4222aa5 779+ f_name(file, NULL));
fa26e11c
WD
780+ exit_cleanup(RERR_STREAMIO);
781+ }
782+ } else if (tag == 'D' || tag == 'd') {
8db8e7d2 783+ if (type == SMB_ACL_TYPE_ACCESS) {
fa26e11c 784+ rprintf(FERROR, "receive_acl %s: expecting access ACL; got default\n",
f4222aa5 785+ f_name(file, NULL));
fa26e11c
WD
786+ exit_cleanup(RERR_STREAMIO);
787+ }
788+ } else {
789+ rprintf(FERROR, "receive_acl %s: unknown ACL type tag: %c\n",
f4222aa5 790+ f_name(file, NULL), tag);
fa26e11c
WD
791+ exit_cleanup(RERR_STREAMIO);
792+ }
793+ if (tag == 'A' || tag == 'D') {
0870c22a
WD
794+ acl_duo *duo_item;
795+ ndx = racl_list->count;
645e162c 796+ duo_item = EXPAND_ITEM_LIST(racl_list, acl_duo, 1000);
b6c2bb12 797+ duo_item->racl = empty_rsync_acl;
0870c22a
WD
798+ receive_rsync_acl(&duo_item->racl, f, type);
799+ duo_item->sacl = NULL;
fa26e11c 800+ } else {
0870c22a 801+ ndx = read_int(f);
d4531ffb 802+ if (ndx < 0 || (size_t)ndx >= racl_list->count) {
fa26e11c 803+ rprintf(FERROR, "receive_acl %s: %s ACL index %d out of range\n",
0870c22a 804+ f_name(file, NULL), str_acl_type(type), ndx);
fa26e11c
WD
805+ exit_cleanup(RERR_STREAMIO);
806+ }
fa26e11c 807+ }
70891d26
WD
808+ if (type == SMB_ACL_TYPE_ACCESS)
809+ F_ACL(file) = ndx;
810+ else
81ecd8e0 811+ F_DEF_ACL(file) = ndx;
0870c22a 812+ racl_list = &default_acl_list;
8db8e7d2 813+ } while (BUMP_TYPE(type) && S_ISDIR(file->mode));
fa26e11c
WD
814+}
815+
5d2612ca
WD
816+/* Turn the ACL data in statx into cached ACL data, setting the index
817+ * values in the file struct. */
818+void cache_acl(struct file_struct *file, statx *sxp)
819+{
820+ SMB_ACL_TYPE_T type;
821+ rsync_acl *racl;
822+ item_list *racl_list;
5d2612ca
WD
823+ int ndx;
824+
825+ if (S_ISLNK(file->mode))
826+ return;
827+
828+ type = SMB_ACL_TYPE_ACCESS;
829+ racl = sxp->acc_acl;
830+ racl_list = &access_acl_list;
5d2612ca
WD
831+ do {
832+ if (!racl)
833+ ndx = -1;
834+ else if ((ndx = find_matching_rsync_acl(type, racl_list, racl)) == -1) {
835+ acl_duo *new_duo;
836+ ndx = racl_list->count;
837+ new_duo = EXPAND_ITEM_LIST(racl_list, acl_duo, 1000);
838+ new_duo->racl = *racl;
839+ new_duo->sacl = NULL;
840+ *racl = empty_rsync_acl;
841+ }
70891d26
WD
842+ if (type == SMB_ACL_TYPE_ACCESS)
843+ F_ACL(file) = ndx;
844+ else
81ecd8e0 845+ F_DEF_ACL(file) = ndx;
5d2612ca
WD
846+ racl = sxp->def_acl;
847+ racl_list = &default_acl_list;
5d2612ca
WD
848+ } while (BUMP_TYPE(type) && S_ISDIR(sxp->st.st_mode));
849+
850+ free_acl(sxp);
851+}
852+
0870c22a 853+static mode_t change_sacl_perms(SMB_ACL_T sacl, rsync_acl *racl, mode_t old_mode, mode_t mode)
fa26e11c 854+{
0870c22a
WD
855+ SMB_ACL_ENTRY_T entry;
856+ const char *errfun;
857+ int rc;
8db8e7d2 858+
0870c22a
WD
859+ if (S_ISDIR(mode)) {
860+ /* If the sticky bit is going on, it's not safe to allow all
adabede5 861+ * the new ACL to go into effect before it gets set. */
0870c22a
WD
862+#ifdef SMB_ACL_LOSES_SPECIAL_MODE_BITS
863+ if (mode & S_ISVTX)
864+ mode &= ~0077;
865+#else
866+ if (mode & S_ISVTX && !(old_mode & S_ISVTX))
867+ mode &= ~0077;
868+ } else {
869+ /* If setuid or setgid is going off, it's not safe to allow all
adabede5 870+ * the new ACL to go into effect before they get cleared. */
0870c22a
WD
871+ if ((old_mode & S_ISUID && !(mode & S_ISUID))
872+ || (old_mode & S_ISGID && !(mode & S_ISGID)))
873+ mode &= ~0077;
874+#endif
875+ }
8db8e7d2 876+
0870c22a
WD
877+ errfun = "sys_acl_get_entry";
878+ for (rc = sys_acl_get_entry(sacl, SMB_ACL_FIRST_ENTRY, &entry);
879+ rc == 1;
880+ rc = sys_acl_get_entry(sacl, SMB_ACL_NEXT_ENTRY, &entry)) {
881+ SMB_ACL_TAG_T tag_type;
882+ if ((rc = sys_acl_get_tag_type(entry, &tag_type))) {
883+ errfun = "sys_acl_get_tag_type";
8db8e7d2 884+ break;
fa26e11c 885+ }
0870c22a
WD
886+ switch (tag_type) {
887+ case SMB_ACL_USER_OBJ:
888+ COE2( store_access_in_entry,((mode >> 6) & 7, entry) );
889+ break;
890+ case SMB_ACL_GROUP_OBJ:
891+ /* group is only empty when identical to group perms. */
892+ if (racl->group_obj != NO_ENTRY)
893+ break;
894+ COE2( store_access_in_entry,((mode >> 3) & 7, entry) );
895+ break;
896+ case SMB_ACL_MASK:
897+#ifndef ACLS_NEED_MASK
898+ /* mask is only empty when we don't need it. */
899+ if (racl->mask == NO_ENTRY)
900+ break;
901+#endif
902+ COE2( store_access_in_entry,((mode >> 3) & 7, entry) );
903+ break;
904+ case SMB_ACL_OTHER:
905+ COE2( store_access_in_entry,(mode & 7, entry) );
906+ break;
8db8e7d2 907+ }
0870c22a
WD
908+ }
909+ if (rc) {
910+ error_exit:
911+ if (errfun) {
912+ rsyserr(FERROR, errno, "change_sacl_perms: %s()",
913+ errfun);
fa26e11c 914+ }
6e4c2d0c 915+ return (mode_t)~0;
0870c22a 916+ }
8db8e7d2 917+
0870c22a
WD
918+#ifdef SMB_ACL_LOSES_SPECIAL_MODE_BITS
919+ /* Ensure that chmod() will be called to restore any lost setid bits. */
920+ if (old_mode & (S_ISUID | S_ISGID | S_ISVTX)
3d3ad7f1 921+ && BITS_EQUAL(old_mode, mode, CHMOD_BITS))
0870c22a
WD
922+ old_mode &= ~(S_ISUID | S_ISGID | S_ISVTX);
923+#endif
8db8e7d2 924+
0870c22a
WD
925+ /* Return the mode of the file on disk, as we will set them. */
926+ return (old_mode & ~ACCESSPERMS) | (mode & ACCESSPERMS);
fa26e11c
WD
927+}
928+
0870c22a 929+/* Set ACL on indicated filename.
c6437996 930+ *
adabede5
WD
931+ * This sets extended access ACL entries and default ACL. If convenient,
932+ * it sets permission bits along with the access ACL and signals having
0870c22a 933+ * done so by modifying sxp->st.st_mode.
c6437996 934+ *
0870c22a 935+ * Returns 1 for unchanged, 0 for changed, -1 for failed. Call this
adabede5 936+ * with fname set to NULL to just check if the ACL is unchanged. */
98ccc74a 937+int set_acl(const char *fname, const struct file_struct *file, statx *sxp)
fa26e11c 938+{
81ddc4dc 939+ int unchanged = 1;
8db8e7d2 940+ SMB_ACL_TYPE_T type;
36aa3171 941+
0909ae28
WD
942+ if (!dry_run && (read_only || list_only)) {
943+ errno = EROFS;
944+ return -1;
945+ }
946+
c6437996
WD
947+ if (S_ISLNK(file->mode))
948+ return 1;
36aa3171 949+
8db8e7d2
WD
950+ type = SMB_ACL_TYPE_ACCESS;
951+ do {
0870c22a 952+ acl_duo *duo_item;
70891d26 953+ int32 ndx;
0870c22a 954+ BOOL eq;
0870c22a
WD
955+
956+ if (type == SMB_ACL_TYPE_ACCESS) {
70891d26 957+ ndx = F_ACL(file);
5d2612ca
WD
958+ if (ndx < 0 || (size_t)ndx >= access_acl_list.count)
959+ continue;
0870c22a
WD
960+ duo_item = access_acl_list.items;
961+ duo_item += ndx;
5d2612ca
WD
962+ eq = sxp->acc_acl
963+ && rsync_acl_equal_enough(sxp->acc_acl, &duo_item->racl, file->mode);
0870c22a 964+ } else {
81ecd8e0 965+ ndx = F_DEF_ACL(file);
5d2612ca
WD
966+ if (ndx < 0 || (size_t)ndx >= default_acl_list.count)
967+ continue;
0870c22a
WD
968+ duo_item = default_acl_list.items;
969+ duo_item += ndx;
5d2612ca
WD
970+ eq = sxp->def_acl
971+ && rsync_acl_equal(sxp->def_acl, &duo_item->racl);
fa26e11c 972+ }
0870c22a 973+ if (eq)
fa26e11c 974+ continue;
0870c22a 975+ if (!dry_run && fname) {
c6437996 976+ if (type == SMB_ACL_TYPE_DEFAULT
0870c22a 977+ && duo_item->racl.user_obj == NO_ENTRY) {
c6437996 978+ if (sys_acl_delete_def_file(fname) < 0) {
0870c22a
WD
979+ rsyserr(FERROR, errno, "set_acl: sys_acl_delete_def_file(%s)",
980+ fname);
c6437996
WD
981+ unchanged = -1;
982+ continue;
983+ }
984+ } else {
0870c22a
WD
985+ mode_t cur_mode = sxp->st.st_mode;
986+ if (!duo_item->sacl
987+ && !pack_smb_acl(&duo_item->sacl, &duo_item->racl)) {
c6437996
WD
988+ unchanged = -1;
989+ continue;
990+ }
991+ if (type == SMB_ACL_TYPE_ACCESS) {
0870c22a 992+ cur_mode = change_sacl_perms(duo_item->sacl, &duo_item->racl,
c6437996 993+ cur_mode, file->mode);
6e4c2d0c 994+ if (cur_mode == (mode_t)~0)
0e879f7f 995+ continue;
c6437996 996+ }
0870c22a
WD
997+ if (sys_acl_set_file(fname, type, duo_item->sacl) < 0) {
998+ rsyserr(FERROR, errno, "set_acl: sys_acl_set_file(%s, %s)",
999+ fname, str_acl_type(type));
c6437996
WD
1000+ unchanged = -1;
1001+ continue;
1002+ }
1003+ if (type == SMB_ACL_TYPE_ACCESS)
0870c22a 1004+ sxp->st.st_mode = cur_mode;
fa26e11c
WD
1005+ }
1006+ }
81ddc4dc
WD
1007+ if (unchanged == 1)
1008+ unchanged = 0;
8db8e7d2
WD
1009+ } while (BUMP_TYPE(type) && S_ISDIR(file->mode));
1010+
81ddc4dc 1011+ return unchanged;
fa26e11c
WD
1012+}
1013+
0870c22a 1014+/* === Enumeration functions for uid mapping === */
fa26e11c 1015+
4edb99c8
WD
1016+/* Context -- one and only one. Should be cycled through once on uid
1017+ * mapping and once on gid mapping. */
0870c22a
WD
1018+static item_list *_enum_racl_lists[] = {
1019+ &access_acl_list, &default_acl_list, NULL
fa26e11c
WD
1020+};
1021+
0870c22a
WD
1022+static item_list **enum_racl_list = &_enum_racl_lists[0];
1023+static int enum_ida_index = 0;
fa26e11c 1024+static size_t enum_racl_index = 0;
fa26e11c 1025+
adabede5 1026+/* This returns the next tag_type id from the given ACL for the next entry,
4edb99c8 1027+ * or it returns 0 if there are no more tag_type ids in the acl. */
c52977bc 1028+static id_t *next_ace_id(SMB_ACL_TAG_T tag_type, const rsync_acl *racl)
fa26e11c 1029+{
0870c22a 1030+ const ida_entries *idal = tag_type == SMB_ACL_USER ? &racl->users : &racl->groups;
c6437996
WD
1031+ if (enum_ida_index < idal->count) {
1032+ id_access *ida = &idal->idas[enum_ida_index++];
1033+ return &ida->id;
fa26e11c 1034+ }
c6437996 1035+ enum_ida_index = 0;
c52977bc 1036+ return NULL;
fa26e11c
WD
1037+}
1038+
0870c22a 1039+static id_t *next_acl_id(SMB_ACL_TAG_T tag_type, const item_list *racl_list)
fa26e11c
WD
1040+{
1041+ for (; enum_racl_index < racl_list->count; enum_racl_index++) {
0870c22a
WD
1042+ id_t *id;
1043+ acl_duo *duo_item = racl_list->items;
1044+ duo_item += enum_racl_index;
1045+ if ((id = next_ace_id(tag_type, &duo_item->racl)) != NULL)
fa26e11c
WD
1046+ return id;
1047+ }
1048+ enum_racl_index = 0;
c52977bc 1049+ return NULL;
fa26e11c
WD
1050+}
1051+
c52977bc 1052+static id_t *next_acl_list_id(SMB_ACL_TAG_T tag_type)
fa26e11c
WD
1053+{
1054+ for (; *enum_racl_list; enum_racl_list++) {
c52977bc 1055+ id_t *id = next_acl_id(tag_type, *enum_racl_list);
fa26e11c
WD
1056+ if (id)
1057+ return id;
1058+ }
1059+ enum_racl_list = &_enum_racl_lists[0];
c52977bc 1060+ return NULL;
fa26e11c
WD
1061+}
1062+
c52977bc 1063+id_t *next_acl_uid()
fa26e11c
WD
1064+{
1065+ return next_acl_list_id(SMB_ACL_USER);
1066+}
1067+
c52977bc 1068+id_t *next_acl_gid()
fa26e11c
WD
1069+{
1070+ return next_acl_list_id(SMB_ACL_GROUP);
1071+}
1072+
0870c22a 1073+/* This is used by dest_mode(). */
26c810d8 1074+int default_perms_for_dir(const char *dir)
90fa6d68
WD
1075+{
1076+ rsync_acl racl;
1077+ SMB_ACL_T sacl;
c6437996 1078+ BOOL ok;
26c810d8 1079+ int perms;
90fa6d68
WD
1080+
1081+ if (dir == NULL)
1082+ dir = ".";
26c810d8 1083+ perms = ACCESSPERMS & ~orig_umask;
90fa6d68
WD
1084+ /* Read the directory's default ACL. If it has none, this will successfully return an empty ACL. */
1085+ sacl = sys_acl_get_file(dir, SMB_ACL_TYPE_DEFAULT);
1086+ if (sacl == NULL) {
1087+ /* Couldn't get an ACL. Darn. */
1088+ switch (errno) {
1089+ case ENOTSUP:
70891d26
WD
1090+ case ENOSYS:
1091+ /* No ACLs are available. */
90fa6d68
WD
1092+ break;
1093+ case ENOENT:
1094+ if (dry_run) {
1095+ /* We're doing a dry run, so the containing directory
1096+ * wasn't actually created. Don't worry about it. */
1097+ break;
1098+ }
1099+ /* Otherwise fall through. */
1100+ default:
26c810d8 1101+ rprintf(FERROR, "default_perms_for_dir: sys_acl_get_file(%s, %s): %s, falling back on umask\n",
90fa6d68
WD
1102+ dir, str_acl_type(SMB_ACL_TYPE_DEFAULT), strerror(errno));
1103+ }
26c810d8 1104+ return perms;
90fa6d68
WD
1105+ }
1106+
1107+ /* Convert it. */
b6c2bb12 1108+ racl = empty_rsync_acl;
90fa6d68
WD
1109+ ok = unpack_smb_acl(&racl, sacl);
1110+ sys_acl_free_acl(sacl);
1111+ if (!ok) {
26c810d8
WD
1112+ rprintf(FERROR, "default_perms_for_dir: unpack_smb_acl failed, falling back on umask\n");
1113+ return perms;
90fa6d68
WD
1114+ }
1115+
c6437996 1116+ /* Apply the permission-bit entries of the default ACL, if any. */
0870c22a 1117+ if (racl.user_obj != NO_ENTRY) {
c6437996
WD
1118+ perms = rsync_acl_get_perms(&racl);
1119+ if (verbose > 2)
1120+ rprintf(FINFO, "got ACL-based default perms %o for directory %s\n", perms, dir);
90fa6d68 1121+ }
c6437996 1122+
90fa6d68 1123+ rsync_acl_free(&racl);
26c810d8 1124+ return perms;
90fa6d68
WD
1125+}
1126+
fa26e11c 1127+#endif /* SUPPORT_ACLS */
9a7eef96
WD
1128--- old/backup.c
1129+++ new/backup.c
70891d26 1130@@ -23,6 +23,7 @@
162234a7 1131
70891d26 1132 extern int verbose;
162234a7
WD
1133 extern int am_root;
1134+extern int preserve_acls;
1135 extern int preserve_devices;
1136 extern int preserve_specials;
1137 extern int preserve_links;
1aa236e1 1138@@ -93,7 +94,8 @@ path
0870c22a
WD
1139 ****************************************************************************/
1140 static int make_bak_dir(char *fullpath)
1141 {
1142- STRUCT_STAT st;
1143+ statx sx;
1144+ struct file_struct *file;
1145 char *rel = fullpath + backup_dir_len;
1146 char *end = rel + strlen(rel);
1147 char *p = end;
1aa236e1 1148@@ -125,15 +127,24 @@ static int make_bak_dir(char *fullpath)
0870c22a
WD
1149 if (p >= rel) {
1150 /* Try to transfer the directory settings of the
1151 * actual dir that the files are coming from. */
1152- if (do_stat(rel, &st) < 0) {
1153+ if (do_stat(rel, &sx.st) < 0) {
1154 rsyserr(FERROR, errno,
1155 "make_bak_dir stat %s failed",
1156 full_fname(rel));
fa26e11c 1157 } else {
0870c22a 1158- do_lchown(fullpath, st.st_uid, st.st_gid);
4d7a8142 1159-#ifdef HAVE_CHMOD
0870c22a
WD
1160- do_chmod(fullpath, st.st_mode);
1161+#ifdef SUPPORT_ACLS
1162+ sx.acc_acl = sx.def_acl = NULL;
1163+#endif
1164+ if (!(file = make_file(rel, NULL, NULL, 0, NO_FILTERS)))
1165+ continue;
e6a7303b 1166+#ifdef SUPPORT_ACLS
0870c22a 1167+ if (preserve_acls) {
98ccc74a
WD
1168+ get_acl(rel, &sx);
1169+ cache_acl(file, &sx);
0870c22a 1170+ }
4d7a8142 1171 #endif
0870c22a
WD
1172+ set_file_attrs(fullpath, file, NULL, 0);
1173+ free(file);
fa26e11c
WD
1174 }
1175 }
1176 *p = '/';
1aa236e1 1177@@ -171,15 +182,18 @@ static int robust_move(const char *src,
0870c22a 1178 * We will move the file to be deleted into a parallel directory tree. */
5e3c6c93 1179 static int keep_backup(const char *fname)
0870c22a
WD
1180 {
1181- STRUCT_STAT st;
1182+ statx sx;
1183 struct file_struct *file;
1184 char *buf;
1185 int kept = 0;
1186 int ret_code;
1187
1188 /* return if no file to keep */
1189- if (do_lstat(fname, &st) < 0)
1190+ if (do_lstat(fname, &sx.st) < 0)
1191 return 1;
1192+#ifdef SUPPORT_ACLS
1193+ sx.acc_acl = sx.def_acl = NULL;
1194+#endif
1195
1196 if (!(file = make_file(fname, NULL, NULL, 0, NO_FILTERS)))
1197 return 1; /* the file could have disappeared */
1aa236e1 1198@@ -189,6 +203,13 @@ static int keep_backup(const char *fname
fa26e11c 1199 return 0;
70891d26 1200 }
fa26e11c 1201
e6a7303b 1202+#ifdef SUPPORT_ACLS
0870c22a 1203+ if (preserve_acls) {
98ccc74a
WD
1204+ get_acl(fname, &sx);
1205+ cache_acl(file, &sx);
0870c22a 1206+ }
e6a7303b 1207+#endif
fa26e11c 1208+
fa26e11c 1209 /* Check to see if this is a device file, or link */
90fa6d68
WD
1210 if ((am_root && preserve_devices && IS_DEVICE(file->mode))
1211 || (preserve_specials && IS_SPECIAL(file->mode))) {
81ecd8e0 1212@@ -260,7 +281,7 @@ static int keep_backup(const char *fname
0870c22a
WD
1213 if (robust_move(fname, buf) != 0) {
1214 rsyserr(FERROR, errno, "keep_backup failed: %s -> \"%s\"",
1215 full_fname(fname), buf);
1216- } else if (st.st_nlink > 1) {
1217+ } else if (sx.st.st_nlink > 1) {
1218 /* If someone has hard-linked the file into the backup
1219 * dir, rename() might return success but do nothing! */
1220 robust_unlink(fname); /* Just in case... */
fdf967c7
WD
1221--- old/compat.c
1222+++ new/compat.c
7e27b6c0
WD
1223@@ -50,6 +50,8 @@ void setup_protocol(int f_out,int f_in)
1224 preserve_uid = ++file_extra_cnt;
fdf967c7 1225 if (preserve_gid)
7e27b6c0 1226 preserve_gid = ++file_extra_cnt;
fdf967c7 1227+ if (preserve_acls && !am_sender)
7e27b6c0 1228+ preserve_acls = ++file_extra_cnt;
fdf967c7
WD
1229
1230 if (remote_protocol == 0) {
1231 if (!read_batch)
9a7eef96
WD
1232--- old/configure.in
1233+++ new/configure.in
7e27b6c0 1234@@ -542,6 +542,11 @@ if test x"$ac_cv_func_strcasecmp" = x"no
fa26e11c
WD
1235 AC_CHECK_LIB(resolv, strcasecmp)
1236 fi
1237
1238+AC_CHECK_FUNCS(aclsort)
1239+if test x"$ac_cv_func_aclsort" = x"no"; then
1240+ AC_CHECK_LIB(sec, aclsort)
1241+fi
1242+
1243 dnl At the moment we don't test for a broken memcmp(), because all we
1244 dnl need to do is test for equality, not comparison, and it seems that
1245 dnl every platform has a memcmp that can do at least that.
7e27b6c0 1246@@ -806,6 +811,78 @@ AC_SUBST(OBJ_RESTORE)
fa26e11c
WD
1247 AC_SUBST(CC_SHOBJ_FLAG)
1248 AC_SUBST(BUILD_POPT)
125d7fca 1249
0909ae28 1250+AC_CHECK_HEADERS(sys/acl.h acl/libacl.h)
fa26e11c
WD
1251+AC_CHECK_FUNCS(_acl __acl _facl __facl)
1252+#################################################
1253+# check for ACL support
1254+
1255+AC_MSG_CHECKING(whether to support ACLs)
f787c90c
WD
1256+AC_ARG_ENABLE(acl-support,
1257+AC_HELP_STRING([--enable-acl-support], [Include ACL support (default=no)]),
3b05e91f 1258+[ case "$enableval" in
fa26e11c
WD
1259+ yes)
1260+
1261+ case "$host_os" in
1262+ *sysv5*)
1263+ AC_MSG_RESULT(Using UnixWare ACLs)
1264+ AC_DEFINE(HAVE_UNIXWARE_ACLS, 1, [true if you have UnixWare ACLs])
1265+ ;;
53c1073a 1266+ *solaris*|*cygwin*)
fa26e11c
WD
1267+ AC_MSG_RESULT(Using solaris ACLs)
1268+ AC_DEFINE(HAVE_SOLARIS_ACLS, 1, [true if you have solaris ACLs])
1269+ ;;
1270+ *hpux*)
1271+ AC_MSG_RESULT(Using HPUX ACLs)
1272+ AC_DEFINE(HAVE_HPUX_ACLS, 1, [true if you have HPUX ACLs])
1273+ ;;
1274+ *irix*)
1275+ AC_MSG_RESULT(Using IRIX ACLs)
1276+ AC_DEFINE(HAVE_IRIX_ACLS, 1, [true if you have IRIX ACLs])
1277+ ;;
1278+ *aix*)
1279+ AC_MSG_RESULT(Using AIX ACLs)
1280+ AC_DEFINE(HAVE_AIX_ACLS, 1, [true if you have AIX ACLs])
1281+ ;;
1282+ *osf*)
1283+ AC_MSG_RESULT(Using Tru64 ACLs)
1284+ AC_DEFINE(HAVE_TRU64_ACLS, 1, [true if you have Tru64 ACLs])
1285+ LIBS="$LIBS -lpacl"
1286+ ;;
1287+ *)
81549708 1288+ AC_MSG_RESULT(ACLs requested -- running tests)
fa26e11c
WD
1289+ AC_CHECK_LIB(acl,acl_get_file)
1290+ AC_CACHE_CHECK([for ACL support],samba_cv_HAVE_POSIX_ACLS,[
1291+ AC_TRY_LINK([#include <sys/types.h>
1292+#include <sys/acl.h>],
1293+[ acl_t acl; int entry_id; acl_entry_t *entry_p; return acl_get_entry( acl, entry_id, entry_p);],
1294+samba_cv_HAVE_POSIX_ACLS=yes,samba_cv_HAVE_POSIX_ACLS=no)])
03d25fc5 1295+ AC_MSG_CHECKING(ACL test results)
fa26e11c
WD
1296+ if test x"$samba_cv_HAVE_POSIX_ACLS" = x"yes"; then
1297+ AC_MSG_RESULT(Using posix ACLs)
1298+ AC_DEFINE(HAVE_POSIX_ACLS, 1, [true if you have posix ACLs])
81549708 1299+ AC_CACHE_CHECK([for acl_get_perm_np],samba_cv_HAVE_ACL_GET_PERM_NP,[
fa26e11c
WD
1300+ AC_TRY_LINK([#include <sys/types.h>
1301+#include <sys/acl.h>],
1302+[ acl_permset_t permset_d; acl_perm_t perm; return acl_get_perm_np( permset_d, perm);],
1303+samba_cv_HAVE_ACL_GET_PERM_NP=yes,samba_cv_HAVE_ACL_GET_PERM_NP=no)])
81549708
WD
1304+ if test x"$samba_cv_HAVE_ACL_GET_PERM_NP" = x"yes"; then
1305+ AC_DEFINE(HAVE_ACL_GET_PERM_NP, 1, [true if you have acl_get_perm_np])
1306+ fi
1307+ else
1308+ AC_MSG_ERROR(Failed to find ACL support)
fa26e11c
WD
1309+ fi
1310+ ;;
1311+ esac
1312+ ;;
1313+ *)
1314+ AC_MSG_RESULT(no)
1315+ AC_DEFINE(HAVE_NO_ACLS, 1, [true if you don't have ACLs])
1316+ ;;
1317+ esac ],
1318+ AC_DEFINE(HAVE_NO_ACLS, 1, [true if you don't have ACLs])
1319+ AC_MSG_RESULT(no)
1320+)
125d7fca 1321+
fa26e11c
WD
1322 AC_CONFIG_FILES([Makefile lib/dummy zlib/dummy popt/dummy shconfig])
1323 AC_OUTPUT
125d7fca 1324
9a7eef96
WD
1325--- old/flist.c
1326+++ new/flist.c
590329e5 1327@@ -41,6 +41,7 @@ extern int filesfrom_fd;
162234a7
WD
1328 extern int one_file_system;
1329 extern int copy_dirlinks;
1330 extern int keep_dirlinks;
1331+extern int preserve_acls;
1332 extern int preserve_links;
1333 extern int preserve_hard_links;
1334 extern int preserve_devices;
fdf967c7 1335@@ -147,6 +148,8 @@ static void list_file_entry(struct file_
0870c22a 1336 permstring(permbuf, f->mode);
1aa236e1 1337 len = F_LENGTH(f);
0870c22a 1338
98ccc74a 1339+ /* TODO: indicate '+' if the entry has an ACL. */
0870c22a
WD
1340+
1341 #ifdef SUPPORT_LINKS
1342 if (preserve_links && S_ISLNK(f->mode)) {
1343 rprintf(FINFO, "%s %11.0f %s %s -> %s\n",
fdf967c7 1344@@ -662,6 +665,12 @@ static struct file_struct *recv_file_ent
70891d26
WD
1345 }
1346 #endif
0870c22a
WD
1347
1348+#ifdef SUPPORT_ACLS
1349+ /* We need one or two index int32s when we're preserving ACLs. */
1350+ if (preserve_acls)
3b3650bb 1351+ extra_len += (S_ISDIR(mode) ? 2 : 1) * EXTRA_LEN;
0870c22a
WD
1352+#endif
1353+
1aa236e1
WD
1354 if (always_checksum && S_ISREG(mode))
1355 extra_len += SUM_EXTRA_CNT * EXTRA_LEN;
0870c22a 1356
fdf967c7 1357@@ -799,6 +808,11 @@ static struct file_struct *recv_file_ent
7c15d5aa 1358 read_buf(f, bp, checksum_len);
0870c22a
WD
1359 }
1360
1361+#ifdef SUPPORT_ACLS
1362+ if (preserve_acls)
98ccc74a 1363+ receive_acl(file, f);
0870c22a
WD
1364+#endif
1365+
1366 return file;
1367 }
1368
fdf967c7 1369@@ -1068,6 +1082,9 @@ static struct file_struct *send_file_nam
7e27b6c0 1370 int flags)
0870c22a
WD
1371 {
1372 struct file_struct *file;
1373+#ifdef SUPPORT_ACLS
1374+ statx sx;
1375+#endif
1376
1377 file = make_file(fname, flist, stp, flags,
1378 f == -2 ? SERVER_FILTERS : ALL_FILTERS);
fdf967c7 1379@@ -1077,12 +1094,26 @@ static struct file_struct *send_file_nam
cf51033a
WD
1380 if (chmod_modes && !S_ISLNK(file->mode))
1381 file->mode = tweak_mode(file->mode, chmod_modes);
1382
e6a7303b 1383+#ifdef SUPPORT_ACLS
d3074350 1384+ if (preserve_acls && f >= 0) {
0870c22a
WD
1385+ sx.st.st_mode = file->mode;
1386+ sx.acc_acl = sx.def_acl = NULL;
98ccc74a 1387+ if (get_acl(fname, &sx) < 0)
0870c22a
WD
1388+ return NULL;
1389+ }
e6a7303b 1390+#endif
cf51033a
WD
1391+
1392 maybe_emit_filelist_progress(flist->count + flist_count_offset);
fa26e11c 1393
cf51033a 1394 flist_expand(flist);
70891d26 1395 flist->files[flist->count++] = file;
7c15d5aa
WD
1396- if (f >= 0)
1397+ if (f >= 0) {
1398 send_file_entry(file, f, flist->count - 1);
162234a7 1399+#ifdef SUPPORT_ACLS
7c15d5aa
WD
1400+ if (preserve_acls)
1401+ send_acl(&sx, f);
0870c22a 1402+#endif
7c15d5aa 1403+ }
0870c22a
WD
1404 return file;
1405 }
70891d26 1406
0870c22a
WD
1407--- old/generator.c
1408+++ new/generator.c
74eccbb1 1409@@ -35,6 +35,7 @@ extern int do_progress;
0870c22a
WD
1410 extern int relative_paths;
1411 extern int implied_dirs;
1412 extern int keep_dirlinks;
1413+extern int preserve_acls;
1414 extern int preserve_links;
1415 extern int preserve_devices;
1416 extern int preserve_specials;
1aa236e1
WD
1417@@ -87,6 +88,7 @@ extern int force_delete;
1418 extern int one_file_system;
0870c22a
WD
1419 extern struct stats stats;
1420 extern dev_t filesystem_dev;
70891d26 1421+extern mode_t orig_umask;
0870c22a 1422 extern char *backup_dir;
70891d26
WD
1423 extern char *backup_suffix;
1424 extern int backup_suffix_len;
3d3ad7f1 1425@@ -518,21 +520,26 @@ static void do_delete_pass(struct file_l
0870c22a
WD
1426 rprintf(FINFO, " \r");
1427 }
1428
1429-int unchanged_attrs(struct file_struct *file, STRUCT_STAT *st)
1430+int unchanged_attrs(struct file_struct *file, statx *sxp)
1431 {
3d3ad7f1
WD
1432- if (preserve_perms && !BITS_EQUAL(st->st_mode, file->mode, CHMOD_BITS))
1433+ if (preserve_perms && !BITS_EQUAL(sxp->st.st_mode, file->mode, CHMOD_BITS))
0870c22a
WD
1434 return 0;
1435
70891d26
WD
1436- if (am_root && preserve_uid && st->st_uid != F_UID(file))
1437+ if (am_root && preserve_uid && sxp->st.st_uid != F_UID(file))
0870c22a
WD
1438 return 0;
1439
70891d26
WD
1440- if (preserve_gid && F_GID(file) != GID_NONE && st->st_gid != F_GID(file))
1441+ if (preserve_gid && F_GID(file) != GID_NONE && sxp->st.st_gid != F_GID(file))
05031682
WD
1442 return 0;
1443
0870c22a 1444+#ifdef SUPPORT_ACLS
98ccc74a 1445+ if (preserve_acls && set_acl(NULL, file, sxp) == 0)
05031682 1446+ return 0;
0870c22a 1447+#endif
05031682 1448+
0870c22a
WD
1449 return 1;
1450 }
1451
1452-void itemize(struct file_struct *file, int ndx, int statret, STRUCT_STAT *st,
1453+void itemize(struct file_struct *file, int ndx, int statret, statx *sxp,
fb11cdd7 1454 int32 iflags, uchar fnamecmp_type, const char *xname)
0870c22a
WD
1455 {
1456 if (statret >= 0) { /* A from-dest-dir statret can == 1! */
3d3ad7f1 1457@@ -540,20 +547,24 @@ void itemize(struct file_struct *file, i
0870c22a
WD
1458 : S_ISDIR(file->mode) ? !omit_dir_times
1459 : !S_ISLNK(file->mode);
1460
1aa236e1
WD
1461- if (S_ISREG(file->mode) && F_LENGTH(file) != st->st_size)
1462+ if (S_ISREG(file->mode) && F_LENGTH(file) != sxp->st.st_size)
0870c22a
WD
1463 iflags |= ITEM_REPORT_SIZE;
1464 if ((iflags & (ITEM_TRANSFER|ITEM_LOCAL_CHANGE) && !keep_time
05031682
WD
1465 && !(iflags & ITEM_MATCHED)
1466 && (!(iflags & ITEM_XNAME_FOLLOWS) || *xname))
1467- || (keep_time && cmp_time(file->modtime, st->st_mtime) != 0))
1468+ || (keep_time && cmp_time(file->modtime, sxp->st.st_mtime) != 0))
0870c22a 1469 iflags |= ITEM_REPORT_TIME;
3d3ad7f1
WD
1470- if (!BITS_EQUAL(st->st_mode, file->mode, CHMOD_BITS))
1471+ if (!BITS_EQUAL(sxp->st.st_mode, file->mode, CHMOD_BITS))
0870c22a 1472 iflags |= ITEM_REPORT_PERMS;
70891d26
WD
1473- if (preserve_uid && am_root && F_UID(file) != st->st_uid)
1474+ if (preserve_uid && am_root && F_UID(file) != sxp->st.st_uid)
0870c22a 1475 iflags |= ITEM_REPORT_OWNER;
70891d26
WD
1476 if (preserve_gid && F_GID(file) != GID_NONE
1477- && st->st_gid != F_GID(file))
1478+ && sxp->st.st_gid != F_GID(file))
0870c22a
WD
1479 iflags |= ITEM_REPORT_GROUP;
1480+#ifdef SUPPORT_ACLS
98ccc74a 1481+ if (preserve_acls && set_acl(NULL, file, sxp) == 0)
0870c22a
WD
1482+ iflags |= ITEM_REPORT_ACL;
1483+#endif
1484 } else
1485 iflags |= ITEM_IS_NEW;
1486
3d3ad7f1 1487@@ -808,7 +819,7 @@ void check_for_finished_hlinks(int itemi
0870c22a
WD
1488 * handling the file, -1 if no dest-linking occurred, or a non-negative
1489 * value if we found an alternate basis file. */
1490 static int try_dests_reg(struct file_struct *file, char *fname, int ndx,
1491- char *cmpbuf, STRUCT_STAT *stp, int itemizing,
1492+ char *cmpbuf, statx *sxp, int itemizing,
7b80cd0e 1493 enum logcode code)
0870c22a 1494 {
1ed0b5c9 1495 int best_match = -1;
3d3ad7f1 1496@@ -817,7 +828,7 @@ static int try_dests_reg(struct file_str
0870c22a
WD
1497
1498 do {
1499 pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
1500- if (link_stat(cmpbuf, stp, 0) < 0 || !S_ISREG(stp->st_mode))
1501+ if (link_stat(cmpbuf, &sxp->st, 0) < 0 || !S_ISREG(sxp->st.st_mode))
1502 continue;
1503 switch (match_level) {
1504 case 0:
3d3ad7f1 1505@@ -825,16 +836,20 @@ static int try_dests_reg(struct file_str
0870c22a
WD
1506 match_level = 1;
1507 /* FALL THROUGH */
1508 case 1:
1509- if (!unchanged_file(cmpbuf, file, stp))
1510+ if (!unchanged_file(cmpbuf, file, &sxp->st))
1511 continue;
1512 best_match = j;
1513 match_level = 2;
1514 /* FALL THROUGH */
1515 case 2:
1516- if (!unchanged_attrs(file, stp))
1517+#ifdef SUPPORT_ACLS
1518+ if (preserve_acls)
98ccc74a 1519+ get_acl(cmpbuf, sxp);
0870c22a
WD
1520+#endif
1521+ if (!unchanged_attrs(file, sxp))
1522 continue;
9386e6b3 1523 if (always_checksum && preserve_times
0870c22a
WD
1524- && cmp_time(stp->st_mtime, file->modtime))
1525+ && cmp_time(sxp->st.st_mtime, file->modtime))
1526 continue;
1527 best_match = j;
1528 match_level = 3;
3d3ad7f1 1529@@ -849,7 +864,7 @@ static int try_dests_reg(struct file_str
0870c22a
WD
1530 if (j != best_match) {
1531 j = best_match;
1532 pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
1533- if (link_stat(cmpbuf, stp, 0) < 0)
1534+ if (link_stat(cmpbuf, &sxp->st, 0) < 0)
85148847 1535 return -1;
0870c22a
WD
1536 }
1537
3d3ad7f1 1538@@ -859,16 +874,25 @@ static int try_dests_reg(struct file_str
7b80cd0e 1539 if (!hard_link_one(file, fname, cmpbuf, 1))
05031682 1540 goto try_a_copy;
1aa236e1 1541 if (preserve_hard_links && F_IS_HLINKED(file))
7b80cd0e
WD
1542- finish_hard_link(file, fname, stp, itemizing, code, j);
1543+ finish_hard_link(file, fname, &sxp->st, itemizing, code, j);
1544 if (itemizing && (verbose > 1 || stdout_format_has_i > 1)) {
1545- itemize(file, ndx, 1, stp,
1546+#ifdef SUPPORT_ACLS
1547+ if (preserve_acls && !ACL_READY(*sxp))
1548+ get_acl(fname, sxp);
1549+#endif
1550+ itemize(file, ndx, 1, sxp,
1551 ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS,
1552 0, "");
1553 }
98e4de3d
WD
1554 } else
1555 #endif
1556- if (itemizing)
0870c22a 1557- itemize(file, ndx, 0, stp, 0, 0, NULL);
98e4de3d 1558+ if (itemizing) {
0870c22a
WD
1559+#ifdef SUPPORT_ACLS
1560+ if (preserve_acls && !ACL_READY(*sxp))
98ccc74a 1561+ get_acl(fname, sxp);
0870c22a
WD
1562+#endif
1563+ itemize(file, ndx, 0, sxp, 0, 0, NULL);
1564+ }
7b80cd0e 1565 if (verbose > 1 && maybe_ATTRS_REPORT)
74eccbb1 1566 rprintf(FCLIENT, "%s is uptodate\n", fname);
7b80cd0e 1567 return -2;
3d3ad7f1 1568@@ -885,8 +909,13 @@ static int try_dests_reg(struct file_str
0870c22a
WD
1569 }
1570 return -1;
1571 }
1572- if (itemizing)
1573- itemize(file, ndx, 0, stp, ITEM_LOCAL_CHANGE, 0, NULL);
1574+ if (itemizing) {
1575+#ifdef SUPPORT_ACLS
1576+ if (preserve_acls && !ACL_READY(*sxp))
98ccc74a 1577+ get_acl(fname, sxp);
e6a7303b 1578+#endif
0870c22a
WD
1579+ itemize(file, ndx, 0, sxp, ITEM_LOCAL_CHANGE, 0, NULL);
1580+ }
1581 set_file_attrs(fname, file, NULL, 0);
1582 if (maybe_ATTRS_REPORT
1583 && ((!itemizing && verbose && match_level == 2)
3d3ad7f1 1584@@ -897,7 +926,7 @@ static int try_dests_reg(struct file_str
7b80cd0e
WD
1585 }
1586 #ifdef SUPPORT_HARD_LINKS
1587 if (preserve_hard_links && F_IS_HLINKED(file))
1588- finish_hard_link(file, fname, stp, itemizing, code, -1);
1589+ finish_hard_link(file, fname, &sxp->st, itemizing, code, -1);
1590 #endif
1591 return -2;
1592 }
3d3ad7f1 1593@@ -909,7 +938,7 @@ static int try_dests_reg(struct file_str
05031682
WD
1594 * handling the file, or -1 if no dest-linking occurred, or a non-negative
1595 * value if we found an alternate basis file. */
1596 static int try_dests_non(struct file_struct *file, char *fname, int ndx,
1597- char *cmpbuf, STRUCT_STAT *stp, int itemizing,
1598+ char *cmpbuf, statx *sxp, int itemizing,
7b80cd0e 1599 enum logcode code)
0870c22a 1600 {
05031682 1601 char lnk[MAXPATHLEN];
3d3ad7f1 1602@@ -942,24 +971,24 @@ static int try_dests_non(struct file_str
fa26e11c 1603
0870c22a 1604 do {
05031682
WD
1605 pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
1606- if (link_stat(cmpbuf, stp, 0) < 0)
1607+ if (link_stat(cmpbuf, &sxp->st, 0) < 0)
0870c22a 1608 continue;
05031682
WD
1609 switch (type) {
1610 case TYPE_DIR:
1611- if (!S_ISDIR(stp->st_mode))
1612+ if (!S_ISDIR(sxp->st.st_mode))
0870c22a 1613 continue;
05031682
WD
1614 break;
1615 case TYPE_SPECIAL:
1616- if (!IS_SPECIAL(stp->st_mode))
1617+ if (!IS_SPECIAL(sxp->st.st_mode))
0870c22a 1618 continue;
05031682
WD
1619 break;
1620 case TYPE_DEVICE:
1621- if (!IS_DEVICE(stp->st_mode))
1622+ if (!IS_DEVICE(sxp->st.st_mode))
0870c22a 1623 continue;
05031682
WD
1624 break;
1625 #ifdef SUPPORT_LINKS
1626 case TYPE_SYMLINK:
1627- if (!S_ISLNK(stp->st_mode))
1628+ if (!S_ISLNK(sxp->st.st_mode))
1629 continue;
1630 break;
1631 #endif
3d3ad7f1 1632@@ -974,7 +1003,7 @@ static int try_dests_non(struct file_str
05031682
WD
1633 case TYPE_SPECIAL:
1634 case TYPE_DEVICE:
81ecd8e0
WD
1635 devp = F_RDEV_P(file);
1636- if (stp->st_rdev != MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp)))
1637+ if (sxp->st.st_rdev != MAKEDEV(DEV_MAJOR(devp), DEV_MINOR(devp)))
05031682
WD
1638 continue;
1639 break;
1640 #ifdef SUPPORT_LINKS
3d3ad7f1 1641@@ -991,7 +1020,11 @@ static int try_dests_non(struct file_str
05031682
WD
1642 match_level = 2;
1643 best_match = j;
1644 }
1645- if (unchanged_attrs(file, stp)) {
1646+#ifdef SUPPORT_ACLS
1647+ if (preserve_acls)
1648+ get_acl(cmpbuf, sxp);
1649+#endif
1650+ if (unchanged_attrs(file, sxp)) {
1651 match_level = 3;
1652 best_match = j;
1653 break;
3d3ad7f1 1654@@ -1004,7 +1037,7 @@ static int try_dests_non(struct file_str
05031682
WD
1655 if (j != best_match) {
1656 j = best_match;
1657 pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
1658- if (link_stat(cmpbuf, stp, 0) < 0)
1659+ if (link_stat(cmpbuf, &sxp->st, 0) < 0)
1660 return -1;
1661 }
1662
3d3ad7f1 1663@@ -1035,7 +1068,15 @@ static int try_dests_non(struct file_str
05031682
WD
1664 : ITEM_LOCAL_CHANGE
1665 + (match_level == 3 ? ITEM_XNAME_FOLLOWS : 0);
1666 char *lp = match_level == 3 ? "" : NULL;
1667- itemize(file, ndx, 0, stp, chg + ITEM_MATCHED, 0, lp);
e6a7303b 1668+#ifdef SUPPORT_ACLS
0870c22a 1669+ if (preserve_acls)
05031682 1670+ get_acl(fname, sxp);
e6a7303b 1671+#endif
05031682 1672+ itemize(file, ndx, 0, sxp, chg + ITEM_MATCHED, 0, lp);
0870c22a
WD
1673+#ifdef SUPPORT_ACLS
1674+ if (preserve_acls)
05031682 1675+ free_acl(sxp);
0870c22a
WD
1676+#endif
1677 }
1678 if (verbose > 1 && maybe_ATTRS_REPORT) {
05031682 1679 rprintf(FCLIENT, "%s%s is uptodate\n",
3d3ad7f1 1680@@ -1048,6 +1089,7 @@ static int try_dests_non(struct file_str
26c810d8
WD
1681 }
1682
1683 static int phase = 0;
1684+static int dflt_perms;
1685
1686 /* Acts on the_file_list->file's ndx'th item, whose name is fname. If a dir,
1687 * make sure it exists, and has the right permissions/timestamp info. For
3d3ad7f1 1688@@ -1068,7 +1110,8 @@ static void recv_generator(char *fname,
0870c22a
WD
1689 static int need_fuzzy_dirlist = 0;
1690 struct file_struct *fuzzy_file = NULL;
1691 int fd = -1, f_copy = -1;
1692- STRUCT_STAT st, real_st, partial_st;
1693+ statx sx, real_sx;
1694+ STRUCT_STAT partial_st;
1695 struct file_struct *back_file = NULL;
1696 int statret, real_ret, stat_errno;
1697 char *fnamecmp, *partialptr, *backupptr = NULL;
3d3ad7f1 1698@@ -1124,6 +1167,9 @@ static void recv_generator(char *fname,
74eccbb1
WD
1699 } else if (!dry_run)
1700 return;
0870c22a
WD
1701 }
1702+#ifdef SUPPORT_ACLS
1703+ sx.acc_acl = sx.def_acl = NULL;
1704+#endif
1705 if (dry_run > 1) {
1706 statret = -1;
1707 stat_errno = ENOENT;
3d3ad7f1 1708@@ -1131,7 +1177,7 @@ static void recv_generator(char *fname,
fb11cdd7 1709 const char *dn = file->dirname ? file->dirname : ".";
0870c22a
WD
1710 if (parent_dirname != dn && strcmp(parent_dirname, dn) != 0) {
1711 if (relative_paths && !implied_dirs
60a8bf36
WD
1712- && do_stat(dn, &st) < 0
1713+ && do_stat(dn, &sx.st) < 0
0870c22a
WD
1714 && create_directory_path(fname) < 0) {
1715 rsyserr(FERROR, errno,
1716 "recv_generator: mkdir %s failed",
3d3ad7f1 1717@@ -1143,6 +1189,10 @@ static void recv_generator(char *fname,
01deb4dc
WD
1718 }
1719 if (fuzzy_basis)
63673ef2 1720 need_fuzzy_dirlist = 1;
26c810d8 1721+#ifdef SUPPORT_ACLS
01deb4dc
WD
1722+ if (!preserve_perms)
1723+ dflt_perms = default_perms_for_dir(dn);
26c810d8 1724+#endif
26c810d8 1725 }
01deb4dc 1726 parent_dirname = dn;
26c810d8 1727
3d3ad7f1 1728@@ -1152,7 +1202,7 @@ static void recv_generator(char *fname,
0870c22a
WD
1729 need_fuzzy_dirlist = 0;
1730 }
1731
1732- statret = link_stat(fname, &st,
1733+ statret = link_stat(fname, &sx.st,
1734 keep_dirlinks && S_ISDIR(file->mode));
1735 stat_errno = errno;
1736 }
3d3ad7f1 1737@@ -1170,8 +1220,9 @@ static void recv_generator(char *fname,
0870c22a 1738 * mode based on the local permissions and some heuristics. */
90fa6d68
WD
1739 if (!preserve_perms) {
1740 int exists = statret == 0
0870c22a 1741- && S_ISDIR(st.st_mode) == S_ISDIR(file->mode);
90fa6d68 1742- file->mode = dest_mode(file->mode, st.st_mode, exists);
0870c22a
WD
1743+ && S_ISDIR(sx.st.st_mode) == S_ISDIR(file->mode);
1744+ file->mode = dest_mode(file->mode, sx.st.st_mode, dflt_perms,
26c810d8 1745+ exists);
90fa6d68
WD
1746 }
1747
1748 if (S_ISDIR(file->mode)) {
3d3ad7f1 1749@@ -1180,8 +1231,8 @@ static void recv_generator(char *fname,
147c8f4c 1750 * file of that name and it is *not* a directory, then
0870c22a
WD
1751 * we need to delete it. If it doesn't exist, then
1752 * (perhaps recursively) create it. */
1753- if (statret == 0 && !S_ISDIR(st.st_mode)) {
87d0091c 1754- if (delete_item(fname, st.st_mode, "directory", del_opts) != 0)
0870c22a 1755+ if (statret == 0 && !S_ISDIR(sx.st.st_mode)) {
87d0091c 1756+ if (delete_item(fname, sx.st.st_mode, "directory", del_opts) != 0)
0870c22a
WD
1757 return;
1758 statret = -1;
1759 }
3d3ad7f1 1760@@ -1190,14 +1241,14 @@ static void recv_generator(char *fname,
147c8f4c
WD
1761 dry_run++;
1762 }
1763 real_ret = statret;
1764- real_st = st;
1765+ real_sx = sx;
1766 if (new_root_dir) {
1767 if (*fname == '.' && fname[1] == '\0')
1768 statret = -1;
05031682
WD
1769 new_root_dir = 0;
1770 }
147c8f4c 1771 if (statret != 0 && basis_dir[0] != NULL) {
05031682
WD
1772- int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &st,
1773+ int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx,
7b80cd0e 1774 itemizing, code);
05031682
WD
1775 if (j == -2) {
1776 itemizing = 0;
3d3ad7f1 1777@@ -1206,7 +1257,11 @@ static void recv_generator(char *fname,
147c8f4c 1778 statret = 1;
05031682
WD
1779 }
1780 if (itemizing && f_out != -1) {
147c8f4c 1781- itemize(file, ndx, statret, &st,
0870c22a 1782+#ifdef SUPPORT_ACLS
147c8f4c 1783+ if (preserve_acls && statret == 0)
98ccc74a 1784+ get_acl(fname, &sx);
0870c22a 1785+#endif
147c8f4c
WD
1786+ itemize(file, ndx, statret, &sx,
1787 statret ? ITEM_LOCAL_CHANGE : 0, 0, NULL);
0870c22a 1788 }
147c8f4c 1789 if (real_ret != 0 && do_mkdir(fname,file->mode) < 0 && errno != EEXIST) {
3d3ad7f1 1790@@ -1226,21 +1281,21 @@ static void recv_generator(char *fname,
74eccbb1 1791 return;
0870c22a
WD
1792 }
1793 }
147c8f4c
WD
1794- if (set_file_attrs(fname, file, real_ret ? NULL : &real_st, 0)
1795+ if (set_file_attrs(fname, file, real_ret ? NULL : &real_sx, 0)
3758a5a5 1796 && verbose && code != FNONE && f_out != -1)
0870c22a 1797 rprintf(code, "%s/\n", fname);
147c8f4c
WD
1798 if (real_ret != 0 && one_file_system)
1799- real_st.st_dev = filesystem_dev;
1800+ real_sx.st.st_dev = filesystem_dev;
0870c22a 1801 if (delete_during && f_out != -1 && !phase && dry_run < 2
70891d26 1802 && (file->flags & FLAG_XFER_DIR))
147c8f4c 1803- delete_in_dir(the_file_list, fname, file, &real_st);
0870c22a 1804- return;
147c8f4c 1805+ delete_in_dir(the_file_list, fname, file, &real_sx.st);
0870c22a
WD
1806+ goto cleanup;
1807 }
1808
81ecd8e0 1809 #ifdef SUPPORT_HARD_LINKS
49551128 1810 if (preserve_hard_links && F_HLINK_NOT_FIRST(file)
7b80cd0e 1811- && hard_link_check(file, ndx, fname, statret, &st, itemizing, code))
0870c22a 1812- return;
7b80cd0e 1813+ && hard_link_check(file, ndx, fname, statret, &sx, itemizing, code))
0870c22a 1814+ goto cleanup;
81ecd8e0 1815 #endif
0870c22a
WD
1816
1817 if (preserve_links && S_ISLNK(file->mode)) {
3d3ad7f1 1818@@ -1260,17 +1315,17 @@ static void recv_generator(char *fname,
0870c22a
WD
1819 char lnk[MAXPATHLEN];
1820 int len;
1821
05031682
WD
1822- if (!S_ISLNK(st.st_mode))
1823+ if (!S_ISLNK(sx.st.st_mode))
1824 statret = -1;
1825 else if ((len = readlink(fname, lnk, MAXPATHLEN-1)) > 0
70891d26 1826 && strncmp(lnk, sl, len) == 0 && sl[len] == '\0') {
05031682
WD
1827 /* The link is pointing to the right place. */
1828 if (itemizing)
1829- itemize(file, ndx, 0, &st, 0, 0, NULL);
1830- set_file_attrs(fname, file, &st, maybe_ATTRS_REPORT);
1831+ itemize(file, ndx, 0, &sx, 0, 0, NULL);
1832+ set_file_attrs(fname, file, &sx, maybe_ATTRS_REPORT);
81ecd8e0 1833 #ifdef SUPPORT_HARD_LINKS
1aa236e1 1834 if (preserve_hard_links && F_IS_HLINKED(file))
7b80cd0e
WD
1835- finish_hard_link(file, fname, &st, itemizing, code, -1);
1836+ finish_hard_link(file, fname, &sx.st, itemizing, code, -1);
1837 #endif
1838 if (remove_source_files == 1)
1839 goto return_with_success;
3d3ad7f1 1840@@ -1278,10 +1333,10 @@ static void recv_generator(char *fname,
0870c22a
WD
1841 }
1842 /* Not the right symlink (or not a symlink), so
1843 * delete it. */
87d0091c
WD
1844- if (delete_item(fname, st.st_mode, "symlink", del_opts) != 0)
1845+ if (delete_item(fname, sx.st.st_mode, "symlink", del_opts) != 0)
0870c22a 1846 return;
0870c22a 1847 } else if (basis_dir[0] != NULL) {
05031682
WD
1848- int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &st,
1849+ int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx,
7b80cd0e 1850 itemizing, code);
05031682
WD
1851 if (j == -2) {
1852 #ifndef CAN_HARDLINK_SYMLINK
3d3ad7f1 1853@@ -1306,7 +1361,7 @@ static void recv_generator(char *fname,
0870c22a
WD
1854 } else {
1855 set_file_attrs(fname, file, NULL, 0);
1856 if (itemizing) {
1857- itemize(file, ndx, statret, &st,
1858+ itemize(file, ndx, statret, &sx,
1859 ITEM_LOCAL_CHANGE, 0, NULL);
1860 }
05031682 1861 if (code != FNONE && verbose)
3d3ad7f1 1862@@ -1332,33 +1387,38 @@ static void recv_generator(char *fname,
05031682 1863 if (statret == 0) {
87d0091c
WD
1864 char *t;
1865 if (IS_DEVICE(file->mode)) {
1866- if (!IS_DEVICE(st.st_mode))
1867+ if (!IS_DEVICE(sx.st.st_mode))
1868 statret = -1;
1869 t = "device file";
1870 } else {
1871- if (!IS_SPECIAL(st.st_mode))
1872+ if (!IS_SPECIAL(sx.st.st_mode))
1873 statret = -1;
1874 t = "special file";
1875 }
1876 if (statret == 0
3d3ad7f1 1877- && BITS_EQUAL(st.st_mode, file->mode, _S_IFMT)
70891d26 1878- && st.st_rdev == rdev) {
3d3ad7f1 1879+ && BITS_EQUAL(sx.st.st_mode, file->mode, _S_IFMT)
70891d26 1880+ && sx.st.st_rdev == rdev) {
05031682
WD
1881 /* The device or special file is identical. */
1882- if (itemizing)
1883- itemize(file, ndx, 0, &st, 0, 0, NULL);
1884- set_file_attrs(fname, file, &st, maybe_ATTRS_REPORT);
1885+ if (itemizing) {
1886+#ifdef SUPPORT_ACLS
1887+ if (preserve_acls)
1888+ get_acl(fname, &sx);
1889+#endif
1890+ itemize(file, ndx, 0, &sx, 0, 0, NULL);
1891+ }
1892+ set_file_attrs(fname, file, &sx, maybe_ATTRS_REPORT);
81ecd8e0 1893 #ifdef SUPPORT_HARD_LINKS
1aa236e1 1894 if (preserve_hard_links && F_IS_HLINKED(file))
7b80cd0e
WD
1895- finish_hard_link(file, fname, &st, itemizing, code, -1);
1896+ finish_hard_link(file, fname, &sx.st, itemizing, code, -1);
81ecd8e0 1897 #endif
05031682
WD
1898 if (remove_source_files == 1)
1899 goto return_with_success;
1900- return;
1901+ goto cleanup;
0870c22a 1902 }
87d0091c
WD
1903- if (delete_item(fname, st.st_mode, t, del_opts) != 0)
1904+ if (delete_item(fname, sx.st.st_mode, t, del_opts) != 0)
05031682
WD
1905 return;
1906 } else if (basis_dir[0] != NULL) {
1907- int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &st,
1908+ int j = try_dests_non(file, fname, ndx, fnamecmpbuf, &sx,
7b80cd0e 1909 itemizing, code);
05031682
WD
1910 if (j == -2) {
1911 #ifndef CAN_HARDLINK_SPECIAL
3d3ad7f1 1912@@ -1388,7 +1448,11 @@ static void recv_generator(char *fname,
0870c22a 1913 } else {
05031682
WD
1914 set_file_attrs(fname, file, NULL, 0);
1915 if (itemizing) {
1916- itemize(file, ndx, statret, &st,
1917+#ifdef SUPPORT_ACLS
1918+ if (preserve_acls && statret == 0)
1919+ get_acl(fname, &sx);
1920+#endif
1921+ itemize(file, ndx, statret, &sx,
1922 ITEM_LOCAL_CHANGE, 0, NULL);
1923 }
1924 if (code != FNONE && verbose)
3d3ad7f1 1925@@ -1400,7 +1464,7 @@ static void recv_generator(char *fname,
195ca26e
WD
1926 if (remove_source_files == 1)
1927 goto return_with_success;
0870c22a
WD
1928 }
1929- return;
1930+ goto cleanup;
1931 }
1932
1933 if (!S_ISREG(file->mode)) {
3d3ad7f1 1934@@ -1434,7 +1498,7 @@ static void recv_generator(char *fname,
0870c22a
WD
1935 }
1936
1937 if (update_only && statret == 0
1938- && cmp_time(st.st_mtime, file->modtime) > 0) {
1939+ && cmp_time(sx.st.st_mtime, file->modtime) > 0) {
1940 if (verbose > 1)
1941 rprintf(FINFO, "%s is newer\n", fname);
1942 return;
3d3ad7f1 1943@@ -1443,20 +1507,20 @@ static void recv_generator(char *fname,
0870c22a
WD
1944 fnamecmp = fname;
1945 fnamecmp_type = FNAMECMP_FNAME;
1946
1947- if (statret == 0 && !S_ISREG(st.st_mode)) {
87d0091c 1948- if (delete_item(fname, st.st_mode, "regular file", del_opts) != 0)
0870c22a 1949+ if (statret == 0 && !S_ISREG(sx.st.st_mode)) {
87d0091c 1950+ if (delete_item(fname, sx.st.st_mode, "regular file", del_opts) != 0)
0870c22a
WD
1951 return;
1952 statret = -1;
1953 stat_errno = ENOENT;
1954 }
1955
1956 if (statret != 0 && basis_dir[0] != NULL) {
1957- int j = try_dests_reg(file, fname, ndx, fnamecmpbuf, &st,
1958+ int j = try_dests_reg(file, fname, ndx, fnamecmpbuf, &sx,
7b80cd0e 1959 itemizing, code);
195ca26e
WD
1960 if (j == -2) {
1961 if (remove_source_files == 1)
1962 goto return_with_success;
0870c22a
WD
1963- return;
1964+ goto cleanup;
195ca26e 1965 }
1ed0b5c9 1966 if (j >= 0) {
0870c22a 1967 fnamecmp = fnamecmpbuf;
3d3ad7f1 1968@@ -1466,7 +1530,7 @@ static void recv_generator(char *fname,
0870c22a
WD
1969 }
1970
1971 real_ret = statret;
1972- real_st = st;
1973+ real_sx = sx;
1974
1975 if (partial_dir && (partialptr = partial_dir_fname(fname)) != NULL
1976 && link_stat(partialptr, &partial_st, 0) == 0
3d3ad7f1 1977@@ -1485,7 +1549,7 @@ static void recv_generator(char *fname,
0870c22a
WD
1978 rprintf(FINFO, "fuzzy basis selected for %s: %s\n",
1979 fname, fnamecmpbuf);
1980 }
1aa236e1
WD
1981- st.st_size = F_LENGTH(fuzzy_file);
1982+ sx.st.st_size = F_LENGTH(fuzzy_file);
0870c22a
WD
1983 statret = 0;
1984 fnamecmp = fnamecmpbuf;
1985 fnamecmp_type = FNAMECMP_FUZZY;
3d3ad7f1 1986@@ -1504,36 +1568,41 @@ static void recv_generator(char *fname,
0870c22a
WD
1987 return;
1988 }
1989
1aa236e1
WD
1990- if (append_mode && st.st_size > F_LENGTH(file))
1991+ if (append_mode && sx.st.st_size > F_LENGTH(file))
0870c22a
WD
1992 return;
1993
1994 if (fnamecmp_type <= FNAMECMP_BASIS_DIR_HIGH)
1995 ;
1996 else if (fnamecmp_type == FNAMECMP_FUZZY)
1997 ;
1998- else if (unchanged_file(fnamecmp, file, &st)) {
1999+ else if (unchanged_file(fnamecmp, file, &sx.st)) {
2000 if (partialptr) {
2001 do_unlink(partialptr);
2002 handle_partial_dir(partialptr, PDIR_DELETE);
2003 }
fdb46bbc
WD
2004- if (itemizing)
2005- itemize(file, ndx, statret, &st, 0, 0, NULL);
2006- set_file_attrs(fname, file, &st, maybe_ATTRS_REPORT);
2007+ if (itemizing) {
0870c22a 2008+#ifdef SUPPORT_ACLS
7b80cd0e
WD
2009+ if (preserve_acls && statret == 0)
2010+ get_acl(fnamecmp, &sx);
0870c22a 2011+#endif
fdb46bbc
WD
2012+ itemize(file, ndx, statret, &sx, 0, 0, NULL);
2013+ }
0870c22a 2014+ set_file_attrs(fname, file, &sx, maybe_ATTRS_REPORT);
81ecd8e0 2015 #ifdef SUPPORT_HARD_LINKS
1aa236e1 2016 if (preserve_hard_links && F_IS_HLINKED(file))
7b80cd0e
WD
2017- finish_hard_link(file, fname, &st, itemizing, code, -1);
2018+ finish_hard_link(file, fname, &sx.st, itemizing, code, -1);
81ecd8e0 2019 #endif
195ca26e
WD
2020 if (remove_source_files != 1)
2021- return;
2022+ goto cleanup;
2023 return_with_success:
dfb2ddef
WD
2024 if (!dry_run)
2025 send_msg_int(MSG_SUCCESS, ndx);
0870c22a
WD
2026- return;
2027+ goto cleanup;
2028 }
2029
2030 prepare_to_open:
2031 if (partialptr) {
2032- st = partial_st;
2033+ sx.st = partial_st;
2034 fnamecmp = partialptr;
2035 fnamecmp_type = FNAMECMP_PARTIAL_DIR;
2036 statret = 0;
3d3ad7f1 2037@@ -1558,16 +1627,20 @@ static void recv_generator(char *fname,
0870c22a 2038 /* pretend the file didn't exist */
81ecd8e0 2039 #ifdef SUPPORT_HARD_LINKS
49551128 2040 if (preserve_hard_links && F_HLINK_NOT_LAST(file))
0870c22a
WD
2041- return;
2042+ goto cleanup;
81ecd8e0 2043 #endif
0870c22a
WD
2044 statret = real_ret = -1;
2045+#ifdef SUPPORT_ACLS
2046+ if (preserve_acls && ACL_READY(sx))
98ccc74a 2047+ free_acl(&sx);
0870c22a
WD
2048+#endif
2049 goto notify_others;
2050 }
2051
2052 if (inplace && make_backups && fnamecmp_type == FNAMECMP_FNAME) {
2053 if (!(backupptr = get_backup_name(fname))) {
2054 close(fd);
2055- return;
2056+ goto cleanup;
2057 }
2058 if (!(back_file = make_file(fname, NULL, NULL, 0, NO_FILTERS))) {
2059 close(fd);
3d3ad7f1 2060@@ -1578,7 +1651,7 @@ static void recv_generator(char *fname,
0870c22a 2061 full_fname(backupptr));
70891d26 2062 unmake_file(back_file);
0870c22a
WD
2063 close(fd);
2064- return;
2065+ goto cleanup;
2066 }
2067 if ((f_copy = do_open(backupptr,
2068 O_WRONLY | O_CREAT | O_TRUNC | O_EXCL, 0600)) < 0) {
3d3ad7f1 2069@@ -1586,14 +1659,14 @@ static void recv_generator(char *fname,
0870c22a 2070 full_fname(backupptr));
70891d26 2071 unmake_file(back_file);
0870c22a
WD
2072 close(fd);
2073- return;
2074+ goto cleanup;
2075 }
2076 fnamecmp_type = FNAMECMP_BACKUP;
2077 }
2078
2079 if (verbose > 3) {
2080 rprintf(FINFO, "gen mapped %s of size %.0f\n",
2081- fnamecmp, (double)st.st_size);
2082+ fnamecmp, (double)sx.st.st_size);
2083 }
2084
2085 if (verbose > 2)
3d3ad7f1 2086@@ -1615,26 +1688,34 @@ static void recv_generator(char *fname,
0870c22a
WD
2087 iflags |= ITEM_BASIS_TYPE_FOLLOWS;
2088 if (fnamecmp_type == FNAMECMP_FUZZY)
2089 iflags |= ITEM_XNAME_FOLLOWS;
2090- itemize(file, -1, real_ret, &real_st, iflags, fnamecmp_type,
2091+#ifdef SUPPORT_ACLS
2092+ if (preserve_acls && real_ret == 0)
b6c2bb12 2093+ get_acl(fnamecmp, &real_sx);
0870c22a
WD
2094+#endif
2095+ itemize(file, -1, real_ret, &real_sx, iflags, fnamecmp_type,
b80daf10 2096 fuzzy_file ? fuzzy_file->basename : NULL);
0870c22a
WD
2097+#ifdef SUPPORT_ACLS
2098+ if (preserve_acls)
98ccc74a 2099+ free_acl(&real_sx);
0870c22a
WD
2100+#endif
2101 }
2102
2103 if (!do_xfers) {
7b80cd0e 2104 #ifdef SUPPORT_HARD_LINKS
1aa236e1 2105 if (preserve_hard_links && F_IS_HLINKED(file))
7b80cd0e
WD
2106- finish_hard_link(file, fname, &st, itemizing, code, -1);
2107+ finish_hard_link(file, fname, &sx.st, itemizing, code, -1);
81ecd8e0 2108 #endif
0870c22a
WD
2109- return;
2110+ goto cleanup;
2111 }
2112 if (read_batch)
2113- return;
2114+ goto cleanup;
2115
2116 if (statret != 0 || whole_file) {
2117 write_sum_head(f_out, NULL);
2118- return;
2119+ goto cleanup;
2120 }
2121
2122- generate_and_send_sums(fd, st.st_size, f_out, f_copy);
2123+ generate_and_send_sums(fd, sx.st.st_size, f_out, f_copy);
2124
2125 if (f_copy >= 0) {
2126 close(f_copy);
3d3ad7f1 2127@@ -1647,6 +1728,13 @@ static void recv_generator(char *fname,
0870c22a
WD
2128 }
2129
2130 close(fd);
2131+
2132+ cleanup:
2133+#ifdef SUPPORT_ACLS
2134+ if (preserve_acls)
98ccc74a 2135+ free_acl(&sx);
0870c22a
WD
2136+#endif
2137+ return;
2138 }
2139
2140 void generate_files(int f_out, struct file_list *flist, char *local_name)
3d3ad7f1 2141@@ -1713,6 +1801,8 @@ void generate_files(int f_out, struct fi
26c810d8
WD
2142 * notice that and let us know via the redo pipe (or its closing). */
2143 ignore_timeout = 1;
2144
2145+ dflt_perms = (ACCESSPERMS & ~orig_umask);
2146+
2147 for (i = 0; i < flist->count; i++) {
2148 struct file_struct *file = flist->files[i];
2149
0870c22a
WD
2150--- old/hlink.c
2151+++ new/hlink.c
70891d26
WD
2152@@ -27,6 +27,7 @@ extern int verbose;
2153 extern int dry_run;
195ca26e 2154 extern int do_xfers;
0870c22a
WD
2155 extern int link_dest;
2156+extern int preserve_acls;
2157 extern int make_backups;
7c15d5aa 2158 extern int protocol_version;
195ca26e 2159 extern int remove_source_files;
7e27b6c0 2160@@ -268,15 +269,19 @@ void match_hard_links(void)
81ecd8e0 2161 }
0870c22a 2162
0870c22a 2163 static int maybe_hard_link(struct file_struct *file, int ndx,
81ecd8e0
WD
2164- const char *fname, int statret, STRUCT_STAT *stp,
2165+ const char *fname, int statret, statx *sxp,
7b80cd0e
WD
2166 const char *oldname, STRUCT_STAT *old_stp,
2167 const char *realname, int itemizing, enum logcode code)
0870c22a
WD
2168 {
2169 if (statret == 0) {
7b80cd0e
WD
2170- if (stp->st_dev == old_stp->st_dev
2171- && stp->st_ino == old_stp->st_ino) {
2172+ if (sxp->st.st_dev == old_stp->st_dev
2173+ && sxp->st.st_ino == old_stp->st_ino) {
0870c22a 2174 if (itemizing) {
81ecd8e0 2175- itemize(file, ndx, statret, stp,
0870c22a
WD
2176+#ifdef SUPPORT_ACLS
2177+ if (preserve_acls && !ACL_READY(*sxp))
98ccc74a 2178+ get_acl(fname, sxp);
0870c22a
WD
2179+#endif
2180+ itemize(file, ndx, statret, sxp,
2181 ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS,
2182 0, "");
2183 }
7e27b6c0 2184@@ -297,7 +302,11 @@ static int maybe_hard_link(struct file_s
0870c22a 2185
7b80cd0e
WD
2186 if (hard_link_one(file, fname, oldname, 0)) {
2187 if (itemizing) {
2188- itemize(file, ndx, statret, stp,
2189+#ifdef SUPPORT_ACLS
2190+ if (preserve_acls && statret == 0 && !ACL_READY(*sxp))
2191+ get_acl(fname, sxp);
2192+#endif
2193+ itemize(file, ndx, statret, sxp,
2194 ITEM_LOCAL_CHANGE | ITEM_XNAME_FOLLOWS, 0,
2195 realname);
2196 }
7e27b6c0 2197@@ -311,7 +320,7 @@ static int maybe_hard_link(struct file_s
7b80cd0e
WD
2198 /* Only called if FLAG_HLINKED is set and FLAG_HLINK_FIRST is not. Returns:
2199 * 0 = process the file, 1 = skip the file, -1 = error occurred. */
81ecd8e0
WD
2200 int hard_link_check(struct file_struct *file, int ndx, const char *fname,
2201- int statret, STRUCT_STAT *stp, int itemizing,
0870c22a 2202+ int statret, statx *sxp, int itemizing,
7b80cd0e 2203 enum logcode code)
0870c22a 2204 {
7b80cd0e 2205 STRUCT_STAT prev_st;
7e27b6c0 2206@@ -362,18 +371,20 @@ int hard_link_check(struct file_struct *
7b80cd0e
WD
2207 if (statret < 0 && basis_dir[0] != NULL) {
2208 /* If we match an alt-dest item, we don't output this as a change. */
2209 char cmpbuf[MAXPATHLEN];
2210- STRUCT_STAT alt_st;
2211+ statx alt_sx;
2212 int j = 0;
0870c22a 2213+#ifdef SUPPORT_ACLS
7b80cd0e 2214+ alt_sx.acc_acl = alt_sx.def_acl = NULL;
0870c22a 2215+#endif
7b80cd0e
WD
2216 do {
2217 pathjoin(cmpbuf, MAXPATHLEN, basis_dir[j], fname);
2218- if (link_stat(cmpbuf, &alt_st, 0) < 0)
2219+ if (link_stat(cmpbuf, &alt_sx.st, 0) < 0)
2220 continue;
2221 if (link_dest) {
2222- if (prev_st.st_dev != alt_st.st_dev
2223- || prev_st.st_ino != alt_st.st_ino)
2224+ if (prev_st.st_dev != alt_sx.st.st_dev
2225+ || prev_st.st_ino != alt_sx.st.st_ino)
2226 continue;
2227 statret = 1;
2228- *stp = alt_st;
2229 if (verbose < 2 || !stdout_format_has_i) {
2230 itemizing = 0;
2231 code = FNONE;
7e27b6c0 2232@@ -382,16 +393,36 @@ int hard_link_check(struct file_struct *
7b80cd0e
WD
2233 }
2234 break;
0870c22a 2235 }
7b80cd0e
WD
2236- if (!unchanged_file(cmpbuf, file, &alt_st))
2237+ if (!unchanged_file(cmpbuf, file, &alt_sx.st))
2238 continue;
2239 statret = 1;
2240- *stp = alt_st;
2241- if (unchanged_attrs(file, &alt_st))
0870c22a 2242+#ifdef SUPPORT_ACLS
7b80cd0e
WD
2243+ if (preserve_acls)
2244+ get_acl(cmpbuf, &alt_sx);
2245+#endif
2246+ if (unchanged_attrs(file, &alt_sx))
2247 break;
2248 } while (basis_dir[++j] != NULL);
2249+ if (statret == 1) {
2250+ sxp->st = alt_sx.st;
2251+#ifdef SUPPORT_ACLS
2252+ if (preserve_acls) {
2253+ if (!ACL_READY(*sxp))
2254+ get_acl(cmpbuf, sxp);
2255+ else {
2256+ sxp->acc_acl = alt_sx.acc_acl;
2257+ sxp->def_acl = alt_sx.def_acl;
2258+ }
2259+ }
2260+#endif
2261+ }
2262+#ifdef SUPPORT_ACLS
2263+ else if (preserve_acls)
2264+ free_acl(&alt_sx);
0870c22a 2265+#endif
0870c22a 2266 }
7b80cd0e
WD
2267
2268- if (maybe_hard_link(file, ndx, fname, statret, stp, prev_name, &prev_st,
2269+ if (maybe_hard_link(file, ndx, fname, statret, sxp, prev_name, &prev_st,
2270 realname, itemizing, code) < 0)
2271 return -1;
2272
7e27b6c0 2273@@ -426,7 +457,8 @@ void finish_hard_link(struct file_struct
7b80cd0e
WD
2274 STRUCT_STAT *stp, int itemizing, enum logcode code,
2275 int alt_dest)
81ecd8e0 2276 {
7b80cd0e
WD
2277- STRUCT_STAT st, prev_st;
2278+ statx prev_sx;
0870c22a 2279+ STRUCT_STAT st;
7b80cd0e
WD
2280 char alt_name[MAXPATHLEN], *prev_name;
2281 const char *our_name;
2282 int prev_statret, ndx, prev_ndx = F_HL_PREV(file);
7e27b6c0 2283@@ -450,14 +482,24 @@ void finish_hard_link(struct file_struct
7b80cd0e
WD
2284 } else
2285 our_name = fname;
0870c22a 2286
7b80cd0e
WD
2287+#ifdef SUPPORT_ACLS
2288+ prev_sx.acc_acl = prev_sx.def_acl = NULL;
2289+#endif
2290+
2291 while ((ndx = prev_ndx) >= 0) {
2292+ int val;
2293 file = FPTR(ndx);
2294 file->flags = (file->flags & ~FLAG_HLINK_FIRST) | FLAG_HLINK_DONE;
2295 prev_ndx = F_HL_PREV(file);
2296 prev_name = f_name(file, NULL);
2297- prev_statret = link_stat(prev_name, &prev_st, 0);
2298- if (maybe_hard_link(file, ndx, prev_name, prev_statret, &prev_st,
2299- our_name, stp, fname, itemizing, code) < 0)
2300+ prev_statret = link_stat(prev_name, &prev_sx.st, 0);
2301+ val = maybe_hard_link(file, ndx, prev_name, prev_statret, &prev_sx,
2302+ our_name, stp, fname, itemizing, code);
0870c22a
WD
2303+#ifdef SUPPORT_ACLS
2304+ if (preserve_acls)
7b80cd0e 2305+ free_acl(&prev_sx);
0870c22a 2306+#endif
7b80cd0e
WD
2307+ if (val < 0)
2308 continue;
dfb2ddef
WD
2309 if (remove_source_files == 1 && do_xfers)
2310 send_msg_int(MSG_SUCCESS, ndx);
9a7eef96
WD
2311--- old/lib/sysacls.c
2312+++ new/lib/sysacls.c
131abbd3 2313@@ -0,0 +1,3251 @@
0870c22a
WD
2314+/*
2315+ Unix SMB/CIFS implementation.
2316+ Samba system utilities for ACL support.
2317+ Copyright (C) Jeremy Allison 2000.
2318+
2319+ This program is free software; you can redistribute it and/or modify
2320+ it under the terms of the GNU General Public License as published by
2321+ the Free Software Foundation; either version 2 of the License, or
2322+ (at your option) any later version.
2323+
2324+ This program is distributed in the hope that it will be useful,
2325+ but WITHOUT ANY WARRANTY; without even the implied warranty of
2326+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
2327+ GNU General Public License for more details.
2328+
2329+ You should have received a copy of the GNU General Public License
2330+ along with this program; if not, write to the Free Software
2331+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
2332+*/
fa26e11c 2333+
0f6733d8 2334+#include "rsync.h"
252945ef 2335+#include "sysacls.h" /****** ADDED ******/
fa26e11c 2336+
131abbd3
WD
2337+#ifdef SUPPORT_ACLS
2338+
252945ef 2339+/****** EXTRAS -- THESE ITEMS ARE NOT FROM THE SAMBA SOURCE ******/
f42b0645
WD
2340+#ifdef DEBUG
2341+#undef DEBUG
2342+#endif
2343+#define DEBUG(x,y)
2344+
0f6733d8
WD
2345+void SAFE_FREE(void *mem)
2346+{
2347+ if (mem)
2348+ free(mem);
2349+}
fa26e11c 2350+
5ca9317d
WD
2351+char *uidtoname(uid_t uid)
2352+{
2353+ static char idbuf[12];
2354+ struct passwd *pw;
2355+
2356+ if ((pw = getpwuid(uid)) == NULL) {
2357+ slprintf(idbuf, sizeof(idbuf)-1, "%ld", (long)uid);
2358+ return idbuf;
2359+ }
2360+ return pw->pw_name;
2361+}
252945ef 2362+/****** EXTRAS -- END ******/
5ca9317d 2363+
0f6733d8
WD
2364+/*
2365+ This file wraps all differing system ACL interfaces into a consistent
2366+ one based on the POSIX interface. It also returns the correct errors
2367+ for older UNIX systems that don't support ACLs.
fa26e11c 2368+
0f6733d8 2369+ The interfaces that each ACL implementation must support are as follows :
fa26e11c 2370+
0f6733d8
WD
2371+ int sys_acl_get_entry( SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
2372+ int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
2373+ int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p
2374+ void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
2375+ SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
2376+ SMB_ACL_T sys_acl_get_fd(int fd)
2377+ int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset);
2378+ int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm);
2379+ char *sys_acl_to_text( SMB_ACL_T theacl, ssize_t *plen)
2380+ SMB_ACL_T sys_acl_init( int count)
2381+ int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
2382+ int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
2383+ int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
2384+ int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
2385+ int sys_acl_valid( SMB_ACL_T theacl )
2386+ int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
2387+ int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
2388+ int sys_acl_delete_def_file(const char *path)
fa26e11c 2389+
0f6733d8
WD
2390+ This next one is not POSIX complient - but we *have* to have it !
2391+ More POSIX braindamage.
fa26e11c 2392+
0f6733d8 2393+ int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
fa26e11c 2394+
0f6733d8
WD
2395+ The generic POSIX free is the following call. We split this into
2396+ several different free functions as we may need to add tag info
2397+ to structures when emulating the POSIX interface.
fa26e11c 2398+
0f6733d8 2399+ int sys_acl_free( void *obj_p)
fa26e11c 2400+
0f6733d8 2401+ The calls we actually use are :
fa26e11c 2402+
0f6733d8
WD
2403+ int sys_acl_free_text(char *text) - free acl_to_text
2404+ int sys_acl_free_acl(SMB_ACL_T posix_acl)
2405+ int sys_acl_free_qualifier(void *qualifier, SMB_ACL_TAG_T tagtype)
fa26e11c 2406+
0f6733d8 2407+*/
fa26e11c 2408+
0f6733d8 2409+#if defined(HAVE_POSIX_ACLS)
fa26e11c 2410+
0f6733d8 2411+/* Identity mapping - easy. */
fa26e11c 2412+
0f6733d8 2413+int sys_acl_get_entry( SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
fa26e11c 2414+{
0f6733d8 2415+ return acl_get_entry( the_acl, entry_id, entry_p);
fa26e11c
WD
2416+}
2417+
0f6733d8 2418+int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
fa26e11c 2419+{
0f6733d8 2420+ return acl_get_tag_type( entry_d, tag_type_p);
fa26e11c
WD
2421+}
2422+
0f6733d8 2423+int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
fa26e11c 2424+{
0f6733d8 2425+ return acl_get_permset( entry_d, permset_p);
fa26e11c
WD
2426+}
2427+
0f6733d8 2428+void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
fa26e11c 2429+{
0f6733d8 2430+ return acl_get_qualifier( entry_d);
fa26e11c
WD
2431+}
2432+
0f6733d8 2433+SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
fa26e11c 2434+{
0f6733d8 2435+ return acl_get_file( path_p, type);
fa26e11c
WD
2436+}
2437+
2438+SMB_ACL_T sys_acl_get_fd(int fd)
2439+{
2440+ return acl_get_fd(fd);
2441+}
2442+
2443+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
2444+{
2445+ return acl_clear_perms(permset);
2446+}
2447+
0f6733d8 2448+int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
fa26e11c
WD
2449+{
2450+ return acl_add_perm(permset, perm);
2451+}
2452+
0f6733d8 2453+int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
fa26e11c
WD
2454+{
2455+#if defined(HAVE_ACL_GET_PERM_NP)
0f6733d8
WD
2456+ /*
2457+ * Required for TrustedBSD-based ACL implementations where
fa26e11c 2458+ * non-POSIX.1e functions are denoted by a _np (non-portable)
0f6733d8
WD
2459+ * suffix.
2460+ */
fa26e11c
WD
2461+ return acl_get_perm_np(permset, perm);
2462+#else
2463+ return acl_get_perm(permset, perm);
2464+#endif
2465+}
2466+
0f6733d8 2467+char *sys_acl_to_text( SMB_ACL_T the_acl, ssize_t *plen)
fa26e11c 2468+{
0f6733d8 2469+ return acl_to_text( the_acl, plen);
fa26e11c
WD
2470+}
2471+
0f6733d8 2472+SMB_ACL_T sys_acl_init( int count)
fa26e11c
WD
2473+{
2474+ return acl_init(count);
2475+}
2476+
0f6733d8 2477+int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
fa26e11c
WD
2478+{
2479+ return acl_create_entry(pacl, pentry);
2480+}
2481+
0f6733d8 2482+int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
fa26e11c
WD
2483+{
2484+ return acl_set_tag_type(entry, tagtype);
2485+}
2486+
0f6733d8 2487+int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
fa26e11c
WD
2488+{
2489+ return acl_set_qualifier(entry, qual);
2490+}
2491+
0f6733d8 2492+int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
fa26e11c
WD
2493+{
2494+ return acl_set_permset(entry, permset);
2495+}
2496+
0f6733d8 2497+int sys_acl_valid( SMB_ACL_T theacl )
fa26e11c
WD
2498+{
2499+ return acl_valid(theacl);
2500+}
2501+
2502+int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
2503+{
2504+ return acl_set_file(name, acltype, theacl);
2505+}
2506+
0f6733d8 2507+int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
fa26e11c
WD
2508+{
2509+ return acl_set_fd(fd, theacl);
2510+}
2511+
2512+int sys_acl_delete_def_file(const char *name)
2513+{
2514+ return acl_delete_def_file(name);
2515+}
2516+
2517+int sys_acl_free_text(char *text)
2518+{
2519+ return acl_free(text);
2520+}
2521+
0f6733d8 2522+int sys_acl_free_acl(SMB_ACL_T the_acl)
fa26e11c
WD
2523+{
2524+ return acl_free(the_acl);
2525+}
2526+
1f839b40 2527+int sys_acl_free_qualifier(void *qual, UNUSED(SMB_ACL_TAG_T tagtype))
fa26e11c
WD
2528+{
2529+ return acl_free(qual);
2530+}
2531+
2532+#elif defined(HAVE_TRU64_ACLS)
0f6733d8
WD
2533+/*
2534+ * The interface to DEC/Compaq Tru64 UNIX ACLs
fa26e11c
WD
2535+ * is based on Draft 13 of the POSIX spec which is
2536+ * slightly different from the Draft 16 interface.
0f6733d8 2537+ *
fa26e11c
WD
2538+ * Also, some of the permset manipulation functions
2539+ * such as acl_clear_perm() and acl_add_perm() appear
2540+ * to be broken on Tru64 so we have to manipulate
0f6733d8
WD
2541+ * the permission bits in the permset directly.
2542+ */
2543+int sys_acl_get_entry( SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
fa26e11c 2544+{
0f6733d8 2545+ SMB_ACL_ENTRY_T entry;
fa26e11c
WD
2546+
2547+ if (entry_id == SMB_ACL_FIRST_ENTRY && acl_first_entry(the_acl) != 0) {
2548+ return -1;
2549+ }
2550+
2551+ errno = 0;
2552+ if ((entry = acl_get_entry(the_acl)) != NULL) {
2553+ *entry_p = entry;
2554+ return 1;
2555+ }
2556+
2557+ return errno ? -1 : 0;
2558+}
2559+
0f6733d8 2560+int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
fa26e11c 2561+{
0f6733d8 2562+ return acl_get_tag_type( entry_d, tag_type_p);
fa26e11c
WD
2563+}
2564+
0f6733d8 2565+int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
fa26e11c 2566+{
0f6733d8 2567+ return acl_get_permset( entry_d, permset_p);
fa26e11c
WD
2568+}
2569+
0f6733d8 2570+void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
fa26e11c 2571+{
0f6733d8 2572+ return acl_get_qualifier( entry_d);
fa26e11c
WD
2573+}
2574+
0f6733d8 2575+SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
fa26e11c
WD
2576+{
2577+ return acl_get_file((char *)path_p, type);
2578+}
2579+
0f6733d8 2580+SMB_ACL_T sys_acl_get_fd(int fd)
fa26e11c
WD
2581+{
2582+ return acl_get_fd(fd, ACL_TYPE_ACCESS);
2583+}
2584+
0f6733d8 2585+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
fa26e11c 2586+{
0f6733d8 2587+ *permset = 0; /* acl_clear_perm() is broken on Tru64 */
fa26e11c
WD
2588+
2589+ return 0;
2590+}
2591+
0f6733d8 2592+int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
fa26e11c
WD
2593+{
2594+ if (perm & ~(SMB_ACL_READ | SMB_ACL_WRITE | SMB_ACL_EXECUTE)) {
2595+ errno = EINVAL;
2596+ return -1;
2597+ }
2598+
0f6733d8 2599+ *permset |= perm; /* acl_add_perm() is broken on Tru64 */
fa26e11c
WD
2600+
2601+ return 0;
2602+}
2603+
0f6733d8 2604+int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
fa26e11c
WD
2605+{
2606+ return *permset & perm; /* Tru64 doesn't have acl_get_perm() */
2607+}
2608+
0f6733d8 2609+char *sys_acl_to_text( SMB_ACL_T the_acl, ssize_t *plen)
fa26e11c 2610+{
0f6733d8 2611+ return acl_to_text( the_acl, plen);
fa26e11c
WD
2612+}
2613+
0f6733d8 2614+SMB_ACL_T sys_acl_init( int count)
fa26e11c
WD
2615+{
2616+ return acl_init(count);
2617+}
2618+
0f6733d8 2619+int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
fa26e11c
WD
2620+{
2621+ SMB_ACL_ENTRY_T entry;
2622+
2623+ if ((entry = acl_create_entry(pacl)) == NULL) {
2624+ return -1;
2625+ }
2626+
2627+ *pentry = entry;
2628+ return 0;
2629+}
2630+
0f6733d8 2631+int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
fa26e11c
WD
2632+{
2633+ return acl_set_tag_type(entry, tagtype);
2634+}
2635+
0f6733d8 2636+int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
fa26e11c
WD
2637+{
2638+ return acl_set_qualifier(entry, qual);
2639+}
2640+
0f6733d8 2641+int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
fa26e11c
WD
2642+{
2643+ return acl_set_permset(entry, permset);
2644+}
2645+
0f6733d8 2646+int sys_acl_valid( SMB_ACL_T theacl )
fa26e11c 2647+{
0f6733d8 2648+ acl_entry_t entry;
fa26e11c
WD
2649+
2650+ return acl_valid(theacl, &entry);
2651+}
2652+
0f6733d8 2653+int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
fa26e11c
WD
2654+{
2655+ return acl_set_file((char *)name, acltype, theacl);
2656+}
2657+
0f6733d8 2658+int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
fa26e11c
WD
2659+{
2660+ return acl_set_fd(fd, ACL_TYPE_ACCESS, theacl);
2661+}
2662+
0f6733d8 2663+int sys_acl_delete_def_file(const char *name)
fa26e11c
WD
2664+{
2665+ return acl_delete_def_file((char *)name);
2666+}
2667+
0f6733d8 2668+int sys_acl_free_text(char *text)
fa26e11c 2669+{
0f6733d8
WD
2670+ /*
2671+ * (void) cast and explicit return 0 are for DEC UNIX
2672+ * which just #defines acl_free_text() to be free()
2673+ */
fa26e11c
WD
2674+ (void) acl_free_text(text);
2675+ return 0;
2676+}
2677+
0f6733d8 2678+int sys_acl_free_acl(SMB_ACL_T the_acl)
fa26e11c
WD
2679+{
2680+ return acl_free(the_acl);
2681+}
2682+
0f6733d8 2683+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
fa26e11c
WD
2684+{
2685+ return acl_free_qualifier(qual, tagtype);
2686+}
2687+
2688+#elif defined(HAVE_UNIXWARE_ACLS) || defined(HAVE_SOLARIS_ACLS)
2689+
0f6733d8
WD
2690+/*
2691+ * Donated by Michael Davidson <md@sco.COM> for UnixWare / OpenUNIX.
2692+ * Modified by Toomas Soome <tsoome@ut.ee> for Solaris.
2693+ */
fa26e11c 2694+
0f6733d8
WD
2695+/*
2696+ * Note that while this code implements sufficient functionality
fa26e11c
WD
2697+ * to support the sys_acl_* interfaces it does not provide all
2698+ * of the semantics of the POSIX ACL interfaces.
2699+ *
2700+ * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned
2701+ * from a call to sys_acl_get_entry() should not be assumed to be
2702+ * valid after calling any of the following functions, which may
2703+ * reorder the entries in the ACL.
2704+ *
2705+ * sys_acl_valid()
2706+ * sys_acl_set_file()
2707+ * sys_acl_set_fd()
2708+ */
2709+
0f6733d8
WD
2710+/*
2711+ * The only difference between Solaris and UnixWare / OpenUNIX is
2712+ * that the #defines for the ACL operations have different names
2713+ */
fa26e11c
WD
2714+#if defined(HAVE_UNIXWARE_ACLS)
2715+
0f6733d8
WD
2716+#define SETACL ACL_SET
2717+#define GETACL ACL_GET
2718+#define GETACLCNT ACL_CNT
fa26e11c
WD
2719+
2720+#endif
2721+
2722+
0f6733d8 2723+int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
fa26e11c
WD
2724+{
2725+ if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
2726+ errno = EINVAL;
2727+ return -1;
2728+ }
2729+
2730+ if (entry_p == NULL) {
2731+ errno = EINVAL;
2732+ return -1;
2733+ }
2734+
2735+ if (entry_id == SMB_ACL_FIRST_ENTRY) {
2736+ acl_d->next = 0;
2737+ }
2738+
2739+ if (acl_d->next < 0) {
2740+ errno = EINVAL;
2741+ return -1;
2742+ }
2743+
2744+ if (acl_d->next >= acl_d->count) {
2745+ return 0;
2746+ }
2747+
2748+ *entry_p = &acl_d->acl[acl_d->next++];
2749+
2750+ return 1;
2751+}
2752+
0f6733d8 2753+int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
fa26e11c
WD
2754+{
2755+ *type_p = entry_d->a_type;
2756+
2757+ return 0;
2758+}
2759+
0f6733d8 2760+int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
fa26e11c
WD
2761+{
2762+ *permset_p = &entry_d->a_perm;
2763+
2764+ return 0;
2765+}
2766+
0f6733d8 2767+void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
fa26e11c
WD
2768+{
2769+ if (entry_d->a_type != SMB_ACL_USER
2770+ && entry_d->a_type != SMB_ACL_GROUP) {
2771+ errno = EINVAL;
2772+ return NULL;
2773+ }
2774+
2775+ return &entry_d->a_id;
2776+}
2777+
0f6733d8
WD
2778+/*
2779+ * There is no way of knowing what size the ACL returned by
fa26e11c
WD
2780+ * GETACL will be unless you first call GETACLCNT which means
2781+ * making an additional system call.
2782+ *
2783+ * In the hope of avoiding the cost of the additional system
2784+ * call in most cases, we initially allocate enough space for
2785+ * an ACL with INITIAL_ACL_SIZE entries. If this turns out to
2786+ * be too small then we use GETACLCNT to find out the actual
0f6733d8
WD
2787+ * size, reallocate the ACL buffer, and then call GETACL again.
2788+ */
fa26e11c 2789+
0f6733d8 2790+#define INITIAL_ACL_SIZE 16
fa26e11c 2791+
0f6733d8 2792+SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
fa26e11c 2793+{
0f6733d8
WD
2794+ SMB_ACL_T acl_d;
2795+ int count; /* # of ACL entries allocated */
2796+ int naccess; /* # of access ACL entries */
2797+ int ndefault; /* # of default ACL entries */
fa26e11c
WD
2798+
2799+ if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
2800+ errno = EINVAL;
2801+ return NULL;
2802+ }
2803+
2804+ count = INITIAL_ACL_SIZE;
2805+ if ((acl_d = sys_acl_init(count)) == NULL) {
2806+ return NULL;
2807+ }
2808+
0f6733d8
WD
2809+ /*
2810+ * If there isn't enough space for the ACL entries we use
fa26e11c
WD
2811+ * GETACLCNT to determine the actual number of ACL entries
2812+ * reallocate and try again. This is in a loop because it
2813+ * is possible that someone else could modify the ACL and
2814+ * increase the number of entries between the call to
0f6733d8
WD
2815+ * GETACLCNT and the call to GETACL.
2816+ */
fa26e11c
WD
2817+ while ((count = acl(path_p, GETACL, count, &acl_d->acl[0])) < 0
2818+ && errno == ENOSPC) {
2819+
2820+ sys_acl_free_acl(acl_d);
2821+
2822+ if ((count = acl(path_p, GETACLCNT, 0, NULL)) < 0) {
2823+ return NULL;
2824+ }
2825+
2826+ if ((acl_d = sys_acl_init(count)) == NULL) {
2827+ return NULL;
2828+ }
2829+ }
2830+
2831+ if (count < 0) {
2832+ sys_acl_free_acl(acl_d);
2833+ return NULL;
2834+ }
2835+
0f6733d8
WD
2836+ /*
2837+ * calculate the number of access and default ACL entries
fa26e11c
WD
2838+ *
2839+ * Note: we assume that the acl() system call returned a
2840+ * well formed ACL which is sorted so that all of the
0f6733d8
WD
2841+ * access ACL entries preceed any default ACL entries
2842+ */
fa26e11c
WD
2843+ for (naccess = 0; naccess < count; naccess++) {
2844+ if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
2845+ break;
2846+ }
2847+ ndefault = count - naccess;
0f6733d8
WD
2848+
2849+ /*
2850+ * if the caller wants the default ACL we have to copy
fa26e11c 2851+ * the entries down to the start of the acl[] buffer
0f6733d8
WD
2852+ * and mask out the ACL_DEFAULT flag from the type field
2853+ */
fa26e11c 2854+ if (type == SMB_ACL_TYPE_DEFAULT) {
0f6733d8 2855+ int i, j;
fa26e11c
WD
2856+
2857+ for (i = 0, j = naccess; i < ndefault; i++, j++) {
2858+ acl_d->acl[i] = acl_d->acl[j];
2859+ acl_d->acl[i].a_type &= ~ACL_DEFAULT;
2860+ }
2861+
2862+ acl_d->count = ndefault;
2863+ } else {
2864+ acl_d->count = naccess;
2865+ }
2866+
2867+ return acl_d;
2868+}
2869+
0f6733d8 2870+SMB_ACL_T sys_acl_get_fd(int fd)
fa26e11c 2871+{
0f6733d8
WD
2872+ SMB_ACL_T acl_d;
2873+ int count; /* # of ACL entries allocated */
2874+ int naccess; /* # of access ACL entries */
fa26e11c
WD
2875+
2876+ count = INITIAL_ACL_SIZE;
2877+ if ((acl_d = sys_acl_init(count)) == NULL) {
2878+ return NULL;
2879+ }
2880+
2881+ while ((count = facl(fd, GETACL, count, &acl_d->acl[0])) < 0
2882+ && errno == ENOSPC) {
2883+
2884+ sys_acl_free_acl(acl_d);
2885+
2886+ if ((count = facl(fd, GETACLCNT, 0, NULL)) < 0) {
2887+ return NULL;
2888+ }
2889+
2890+ if ((acl_d = sys_acl_init(count)) == NULL) {
2891+ return NULL;
2892+ }
2893+ }
2894+
2895+ if (count < 0) {
2896+ sys_acl_free_acl(acl_d);
2897+ return NULL;
2898+ }
2899+
0f6733d8
WD
2900+ /*
2901+ * calculate the number of access ACL entries
2902+ */
fa26e11c
WD
2903+ for (naccess = 0; naccess < count; naccess++) {
2904+ if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
2905+ break;
2906+ }
0f6733d8 2907+
fa26e11c
WD
2908+ acl_d->count = naccess;
2909+
2910+ return acl_d;
2911+}
2912+
0f6733d8 2913+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
fa26e11c
WD
2914+{
2915+ *permset_d = 0;
2916+
2917+ return 0;
2918+}
2919+
0f6733d8 2920+int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
fa26e11c
WD
2921+{
2922+ if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
2923+ && perm != SMB_ACL_EXECUTE) {
2924+ errno = EINVAL;
2925+ return -1;
2926+ }
2927+
2928+ if (permset_d == NULL) {
2929+ errno = EINVAL;
2930+ return -1;
2931+ }
2932+
2933+ *permset_d |= perm;
2934+
2935+ return 0;
2936+}
2937+
0f6733d8 2938+int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
fa26e11c
WD
2939+{
2940+ return *permset_d & perm;
2941+}
2942+
0f6733d8 2943+char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p)
fa26e11c 2944+{
0f6733d8
WD
2945+ int i;
2946+ int len, maxlen;
2947+ char *text;
fa26e11c 2948+
0f6733d8
WD
2949+ /*
2950+ * use an initial estimate of 20 bytes per ACL entry
fa26e11c 2951+ * when allocating memory for the text representation
0f6733d8
WD
2952+ * of the ACL
2953+ */
2954+ len = 0;
2955+ maxlen = 20 * acl_d->count;
252945ef 2956+ if ((text = SMB_MALLOC(maxlen)) == NULL) {
fa26e11c
WD
2957+ errno = ENOMEM;
2958+ return NULL;
2959+ }
2960+
2961+ for (i = 0; i < acl_d->count; i++) {
0f6733d8 2962+ struct acl *ap = &acl_d->acl[i];
0f6733d8
WD
2963+ struct group *gr;
2964+ char tagbuf[12];
2965+ char idbuf[12];
2966+ char *tag;
2967+ char *id = "";
2968+ char perms[4];
2969+ int nbytes;
fa26e11c
WD
2970+
2971+ switch (ap->a_type) {
0f6733d8
WD
2972+ /*
2973+ * for debugging purposes it's probably more
fa26e11c 2974+ * useful to dump unknown tag types rather
0f6733d8
WD
2975+ * than just returning an error
2976+ */
fa26e11c 2977+ default:
0f6733d8 2978+ slprintf(tagbuf, sizeof(tagbuf)-1, "0x%x",
fa26e11c
WD
2979+ ap->a_type);
2980+ tag = tagbuf;
0f6733d8 2981+ slprintf(idbuf, sizeof(idbuf)-1, "%ld",
fa26e11c
WD
2982+ (long)ap->a_id);
2983+ id = idbuf;
2984+ break;
2985+
2986+ case SMB_ACL_USER:
5ca9317d 2987+ id = uidtoname(ap->a_id);
fa26e11c
WD
2988+ case SMB_ACL_USER_OBJ:
2989+ tag = "user";
2990+ break;
2991+
2992+ case SMB_ACL_GROUP:
2993+ if ((gr = getgrgid(ap->a_id)) == NULL) {
0f6733d8 2994+ slprintf(idbuf, sizeof(idbuf)-1, "%ld",
fa26e11c
WD
2995+ (long)ap->a_id);
2996+ id = idbuf;
2997+ } else {
2998+ id = gr->gr_name;
2999+ }
3000+ case SMB_ACL_GROUP_OBJ:
3001+ tag = "group";
3002+ break;
3003+
3004+ case SMB_ACL_OTHER:
3005+ tag = "other";
3006+ break;
3007+
3008+ case SMB_ACL_MASK:
3009+ tag = "mask";
3010+ break;
3011+
3012+ }
3013+
3014+ perms[0] = (ap->a_perm & SMB_ACL_READ) ? 'r' : '-';
3015+ perms[1] = (ap->a_perm & SMB_ACL_WRITE) ? 'w' : '-';
3016+ perms[2] = (ap->a_perm & SMB_ACL_EXECUTE) ? 'x' : '-';
3017+ perms[3] = '\0';
3018+
3019+ /* <tag> : <qualifier> : rwx \n \0 */
3020+ nbytes = strlen(tag) + 1 + strlen(id) + 1 + 3 + 1 + 1;
3021+
0f6733d8
WD
3022+ /*
3023+ * If this entry would overflow the buffer
fa26e11c
WD
3024+ * allocate enough additional memory for this
3025+ * entry and an estimate of another 20 bytes
0f6733d8
WD
3026+ * for each entry still to be processed
3027+ */
fa26e11c
WD
3028+ if ((len + nbytes) > maxlen) {
3029+ char *oldtext = text;
3030+
3031+ maxlen += nbytes + 20 * (acl_d->count - i);
3032+
252945ef 3033+ if ((text = SMB_REALLOC(oldtext, maxlen)) == NULL) {
0f6733d8 3034+ SAFE_FREE(oldtext);
fa26e11c
WD
3035+ errno = ENOMEM;
3036+ return NULL;
3037+ }
3038+ }
3039+
0f6733d8 3040+ slprintf(&text[len], nbytes-1, "%s:%s:%s\n", tag, id, perms);
fa26e11c
WD
3041+ len += nbytes - 1;
3042+ }
3043+
3044+ if (len_p)
3045+ *len_p = len;
3046+
3047+ return text;
3048+}
3049+
0f6733d8 3050+SMB_ACL_T sys_acl_init(int count)
fa26e11c 3051+{
0f6733d8 3052+ SMB_ACL_T a;
fa26e11c
WD
3053+
3054+ if (count < 0) {
3055+ errno = EINVAL;
3056+ return NULL;
3057+ }
3058+
0f6733d8
WD
3059+ /*
3060+ * note that since the definition of the structure pointed
fa26e11c
WD
3061+ * to by the SMB_ACL_T includes the first element of the
3062+ * acl[] array, this actually allocates an ACL with room
0f6733d8
WD
3063+ * for (count+1) entries
3064+ */
53c1073a 3065+ if ((a = (SMB_ACL_T)SMB_MALLOC(sizeof(struct SMB_ACL_T) + count * sizeof(struct acl))) == NULL) {
fa26e11c
WD
3066+ errno = ENOMEM;
3067+ return NULL;
3068+ }
3069+
3070+ a->size = count + 1;
3071+ a->count = 0;
3072+ a->next = -1;
3073+
3074+ return a;
3075+}
3076+
3077+
0f6733d8 3078+int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
fa26e11c 3079+{
0f6733d8
WD
3080+ SMB_ACL_T acl_d;
3081+ SMB_ACL_ENTRY_T entry_d;
fa26e11c
WD
3082+
3083+ if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
3084+ errno = EINVAL;
3085+ return -1;
3086+ }
3087+
3088+ if (acl_d->count >= acl_d->size) {
3089+ errno = ENOSPC;
3090+ return -1;
3091+ }
3092+
0f6733d8
WD
3093+ entry_d = &acl_d->acl[acl_d->count++];
3094+ entry_d->a_type = 0;
3095+ entry_d->a_id = -1;
3096+ entry_d->a_perm = 0;
3097+ *entry_p = entry_d;
fa26e11c
WD
3098+
3099+ return 0;
3100+}
3101+
0f6733d8 3102+int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
fa26e11c
WD
3103+{
3104+ switch (tag_type) {
3105+ case SMB_ACL_USER:
3106+ case SMB_ACL_USER_OBJ:
3107+ case SMB_ACL_GROUP:
3108+ case SMB_ACL_GROUP_OBJ:
3109+ case SMB_ACL_OTHER:
3110+ case SMB_ACL_MASK:
3111+ entry_d->a_type = tag_type;
3112+ break;
3113+ default:
3114+ errno = EINVAL;
3115+ return -1;
3116+ }
3117+
3118+ return 0;
3119+}
3120+
0f6733d8 3121+int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
fa26e11c
WD
3122+{
3123+ if (entry_d->a_type != SMB_ACL_GROUP
3124+ && entry_d->a_type != SMB_ACL_USER) {
3125+ errno = EINVAL;
3126+ return -1;
3127+ }
3128+
3129+ entry_d->a_id = *((id_t *)qual_p);
3130+
3131+ return 0;
3132+}
3133+
0f6733d8 3134+int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
fa26e11c
WD
3135+{
3136+ if (*permset_d & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
3137+ return EINVAL;
3138+ }
3139+
3140+ entry_d->a_perm = *permset_d;
3141+
3142+ return 0;
3143+}
3144+
0f6733d8
WD
3145+/*
3146+ * sort the ACL and check it for validity
fa26e11c 3147+ *
0f6733d8 3148+ * if it's a minimal ACL with only 4 entries then we
fa26e11c
WD
3149+ * need to recalculate the mask permissions to make
3150+ * sure that they are the same as the GROUP_OBJ
3151+ * permissions as required by the UnixWare acl() system call.
3152+ *
0f6733d8 3153+ * (note: since POSIX allows minimal ACLs which only contain
fa26e11c
WD
3154+ * 3 entries - ie there is no mask entry - we should, in theory,
3155+ * check for this and add a mask entry if necessary - however
3156+ * we "know" that the caller of this interface always specifies
3157+ * a mask so, in practice "this never happens" (tm) - if it *does*
3158+ * happen aclsort() will fail and return an error and someone will
0f6733d8
WD
3159+ * have to fix it ...)
3160+ */
fa26e11c
WD
3161+
3162+static int acl_sort(SMB_ACL_T acl_d)
3163+{
3164+ int fixmask = (acl_d->count <= 4);
3165+
3166+ if (aclsort(acl_d->count, fixmask, acl_d->acl) != 0) {
3167+ errno = EINVAL;
3168+ return -1;
3169+ }
3170+ return 0;
3171+}
0f6733d8
WD
3172+
3173+int sys_acl_valid(SMB_ACL_T acl_d)
fa26e11c
WD
3174+{
3175+ return acl_sort(acl_d);
3176+}
3177+
0f6733d8 3178+int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
fa26e11c 3179+{
0f6733d8
WD
3180+ struct stat s;
3181+ struct acl *acl_p;
3182+ int acl_count;
3183+ struct acl *acl_buf = NULL;
3184+ int ret;
fa26e11c
WD
3185+
3186+ if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
3187+ errno = EINVAL;
3188+ return -1;
3189+ }
3190+
3191+ if (acl_sort(acl_d) != 0) {
3192+ return -1;
3193+ }
3194+
0f6733d8
WD
3195+ acl_p = &acl_d->acl[0];
3196+ acl_count = acl_d->count;
fa26e11c 3197+
0f6733d8
WD
3198+ /*
3199+ * if it's a directory there is extra work to do
3200+ * since the acl() system call will replace both
3201+ * the access ACLs and the default ACLs (if any)
3202+ */
fa26e11c
WD
3203+ if (stat(name, &s) != 0) {
3204+ return -1;
3205+ }
3206+ if (S_ISDIR(s.st_mode)) {
0f6733d8
WD
3207+ SMB_ACL_T acc_acl;
3208+ SMB_ACL_T def_acl;
3209+ SMB_ACL_T tmp_acl;
3210+ int i;
fa26e11c
WD
3211+
3212+ if (type == SMB_ACL_TYPE_ACCESS) {
3213+ acc_acl = acl_d;
3214+ def_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT);
3215+
3216+ } else {
3217+ def_acl = acl_d;
3218+ acc_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS);
3219+ }
3220+
3221+ if (tmp_acl == NULL) {
3222+ return -1;
3223+ }
3224+
0f6733d8
WD
3225+ /*
3226+ * allocate a temporary buffer for the complete ACL
3227+ */
fa26e11c 3228+ acl_count = acc_acl->count + def_acl->count;
252945ef 3229+ acl_p = acl_buf = SMB_MALLOC_ARRAY(struct acl, acl_count);
fa26e11c
WD
3230+
3231+ if (acl_buf == NULL) {
3232+ sys_acl_free_acl(tmp_acl);
3233+ errno = ENOMEM;
3234+ return -1;
3235+ }
3236+
0f6733d8
WD
3237+ /*
3238+ * copy the access control and default entries into the buffer
3239+ */
fa26e11c 3240+ memcpy(&acl_buf[0], &acc_acl->acl[0],
0f6733d8 3241+ acc_acl->count * sizeof(acl_buf[0]));
fa26e11c
WD
3242+
3243+ memcpy(&acl_buf[acc_acl->count], &def_acl->acl[0],
0f6733d8 3244+ def_acl->count * sizeof(acl_buf[0]));
fa26e11c 3245+
0f6733d8
WD
3246+ /*
3247+ * set the ACL_DEFAULT flag on the default entries
3248+ */
fa26e11c
WD
3249+ for (i = acc_acl->count; i < acl_count; i++) {
3250+ acl_buf[i].a_type |= ACL_DEFAULT;
3251+ }
3252+
3253+ sys_acl_free_acl(tmp_acl);
3254+
3255+ } else if (type != SMB_ACL_TYPE_ACCESS) {
3256+ errno = EINVAL;
3257+ return -1;
3258+ }
3259+
3260+ ret = acl(name, SETACL, acl_count, acl_p);
3261+
0f6733d8 3262+ SAFE_FREE(acl_buf);
fa26e11c
WD
3263+
3264+ return ret;
3265+}
3266+
0f6733d8 3267+int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
fa26e11c
WD
3268+{
3269+ if (acl_sort(acl_d) != 0) {
3270+ return -1;
3271+ }
3272+
3273+ return facl(fd, SETACL, acl_d->count, &acl_d->acl[0]);
3274+}
3275+
0f6733d8 3276+int sys_acl_delete_def_file(const char *path)
fa26e11c 3277+{
0f6733d8
WD
3278+ SMB_ACL_T acl_d;
3279+ int ret;
fa26e11c 3280+
0f6733d8
WD
3281+ /*
3282+ * fetching the access ACL and rewriting it has
3283+ * the effect of deleting the default ACL
3284+ */
fa26e11c
WD
3285+ if ((acl_d = sys_acl_get_file(path, SMB_ACL_TYPE_ACCESS)) == NULL) {
3286+ return -1;
3287+ }
3288+
3289+ ret = acl(path, SETACL, acl_d->count, acl_d->acl);
3290+
3291+ sys_acl_free_acl(acl_d);
0f6733d8 3292+
fa26e11c
WD
3293+ return ret;
3294+}
3295+
0f6733d8 3296+int sys_acl_free_text(char *text)
fa26e11c 3297+{
0f6733d8 3298+ SAFE_FREE(text);
fa26e11c
WD
3299+ return 0;
3300+}
3301+
0f6733d8 3302+int sys_acl_free_acl(SMB_ACL_T acl_d)
fa26e11c 3303+{
0f6733d8 3304+ SAFE_FREE(acl_d);
fa26e11c
WD
3305+ return 0;
3306+}
3307+
53c1073a 3308+int sys_acl_free_qualifier(UNUSED(void *qual), UNUSED(SMB_ACL_TAG_T tagtype))
fa26e11c
WD
3309+{
3310+ return 0;
3311+}
3312+
3313+#elif defined(HAVE_HPUX_ACLS)
3314+#include <dl.h>
3315+
0f6733d8
WD
3316+/*
3317+ * Based on the Solaris/SCO code - with modifications.
3318+ */
fa26e11c 3319+
0f6733d8
WD
3320+/*
3321+ * Note that while this code implements sufficient functionality
fa26e11c
WD
3322+ * to support the sys_acl_* interfaces it does not provide all
3323+ * of the semantics of the POSIX ACL interfaces.
3324+ *
3325+ * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned
3326+ * from a call to sys_acl_get_entry() should not be assumed to be
3327+ * valid after calling any of the following functions, which may
3328+ * reorder the entries in the ACL.
3329+ *
3330+ * sys_acl_valid()
3331+ * sys_acl_set_file()
3332+ * sys_acl_set_fd()
3333+ */
3334+
0f6733d8
WD
3335+/* This checks if the POSIX ACL system call is defined */
3336+/* which basically corresponds to whether JFS 3.3 or */
3337+/* higher is installed. If acl() was called when it */
3338+/* isn't defined, it causes the process to core dump */
3339+/* so it is important to check this and avoid acl() */
3340+/* calls if it isn't there. */
fa26e11c
WD
3341+
3342+static BOOL hpux_acl_call_presence(void)
3343+{
3344+
3345+ shl_t handle = NULL;
3346+ void *value;
3347+ int ret_val=0;
3348+ static BOOL already_checked=0;
3349+
0f6733d8 3350+ if(already_checked)
fa26e11c
WD
3351+ return True;
3352+
3353+
3354+ ret_val = shl_findsym(&handle, "acl", TYPE_PROCEDURE, &value);
3355+
0f6733d8 3356+ if(ret_val != 0) {
fa26e11c
WD
3357+ DEBUG(5, ("hpux_acl_call_presence: shl_findsym() returned %d, errno = %d, error %s\n",
3358+ ret_val, errno, strerror(errno)));
3359+ DEBUG(5,("hpux_acl_call_presence: acl() system call is not present. Check if you have JFS 3.3 and above?\n"));
3360+ return False;
3361+ }
3362+
3363+ DEBUG(10,("hpux_acl_call_presence: acl() system call is present. We have JFS 3.3 or above \n"));
3364+
3365+ already_checked = True;
3366+ return True;
3367+}
3368+
0f6733d8 3369+int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
fa26e11c
WD
3370+{
3371+ if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
3372+ errno = EINVAL;
3373+ return -1;
3374+ }
3375+
3376+ if (entry_p == NULL) {
3377+ errno = EINVAL;
3378+ return -1;
3379+ }
3380+
3381+ if (entry_id == SMB_ACL_FIRST_ENTRY) {
3382+ acl_d->next = 0;
3383+ }
3384+
3385+ if (acl_d->next < 0) {
3386+ errno = EINVAL;
3387+ return -1;
3388+ }
3389+
3390+ if (acl_d->next >= acl_d->count) {
3391+ return 0;
3392+ }
3393+
3394+ *entry_p = &acl_d->acl[acl_d->next++];
3395+
3396+ return 1;
3397+}
3398+
0f6733d8 3399+int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
fa26e11c
WD
3400+{
3401+ *type_p = entry_d->a_type;
3402+
3403+ return 0;
3404+}
3405+
0f6733d8 3406+int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
fa26e11c
WD
3407+{
3408+ *permset_p = &entry_d->a_perm;
3409+
3410+ return 0;
3411+}
3412+
0f6733d8 3413+void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
fa26e11c
WD
3414+{
3415+ if (entry_d->a_type != SMB_ACL_USER
3416+ && entry_d->a_type != SMB_ACL_GROUP) {
3417+ errno = EINVAL;
3418+ return NULL;
3419+ }
3420+
3421+ return &entry_d->a_id;
3422+}
3423+
0f6733d8
WD
3424+/*
3425+ * There is no way of knowing what size the ACL returned by
fa26e11c
WD
3426+ * ACL_GET will be unless you first call ACL_CNT which means
3427+ * making an additional system call.
3428+ *
3429+ * In the hope of avoiding the cost of the additional system
3430+ * call in most cases, we initially allocate enough space for
3431+ * an ACL with INITIAL_ACL_SIZE entries. If this turns out to
3432+ * be too small then we use ACL_CNT to find out the actual
3433+ * size, reallocate the ACL buffer, and then call ACL_GET again.
3434+ */
3435+
0f6733d8 3436+#define INITIAL_ACL_SIZE 16
fa26e11c 3437+
0f6733d8 3438+SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
fa26e11c 3439+{
0f6733d8
WD
3440+ SMB_ACL_T acl_d;
3441+ int count; /* # of ACL entries allocated */
3442+ int naccess; /* # of access ACL entries */
3443+ int ndefault; /* # of default ACL entries */
fa26e11c 3444+
0f6733d8
WD
3445+ if(hpux_acl_call_presence() == False) {
3446+ /* Looks like we don't have the acl() system call on HPUX.
3447+ * May be the system doesn't have the latest version of JFS.
3448+ */
3449+ return NULL;
fa26e11c
WD
3450+ }
3451+
3452+ if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
3453+ errno = EINVAL;
3454+ return NULL;
3455+ }
3456+
3457+ count = INITIAL_ACL_SIZE;
3458+ if ((acl_d = sys_acl_init(count)) == NULL) {
3459+ return NULL;
3460+ }
3461+
0f6733d8
WD
3462+ /*
3463+ * If there isn't enough space for the ACL entries we use
fa26e11c
WD
3464+ * ACL_CNT to determine the actual number of ACL entries
3465+ * reallocate and try again. This is in a loop because it
3466+ * is possible that someone else could modify the ACL and
3467+ * increase the number of entries between the call to
0f6733d8
WD
3468+ * ACL_CNT and the call to ACL_GET.
3469+ */
fa26e11c
WD
3470+ while ((count = acl(path_p, ACL_GET, count, &acl_d->acl[0])) < 0 && errno == ENOSPC) {
3471+
3472+ sys_acl_free_acl(acl_d);
3473+
3474+ if ((count = acl(path_p, ACL_CNT, 0, NULL)) < 0) {
3475+ return NULL;
3476+ }
3477+
3478+ if ((acl_d = sys_acl_init(count)) == NULL) {
3479+ return NULL;
3480+ }
3481+ }
3482+
3483+ if (count < 0) {
3484+ sys_acl_free_acl(acl_d);
3485+ return NULL;
3486+ }
3487+
0f6733d8
WD
3488+ /*
3489+ * calculate the number of access and default ACL entries
fa26e11c
WD
3490+ *
3491+ * Note: we assume that the acl() system call returned a
3492+ * well formed ACL which is sorted so that all of the
0f6733d8
WD
3493+ * access ACL entries preceed any default ACL entries
3494+ */
fa26e11c
WD
3495+ for (naccess = 0; naccess < count; naccess++) {
3496+ if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
3497+ break;
3498+ }
3499+ ndefault = count - naccess;
0f6733d8
WD
3500+
3501+ /*
3502+ * if the caller wants the default ACL we have to copy
fa26e11c 3503+ * the entries down to the start of the acl[] buffer
0f6733d8
WD
3504+ * and mask out the ACL_DEFAULT flag from the type field
3505+ */
fa26e11c 3506+ if (type == SMB_ACL_TYPE_DEFAULT) {
0f6733d8 3507+ int i, j;
fa26e11c
WD
3508+
3509+ for (i = 0, j = naccess; i < ndefault; i++, j++) {
3510+ acl_d->acl[i] = acl_d->acl[j];
3511+ acl_d->acl[i].a_type &= ~ACL_DEFAULT;
3512+ }
3513+
3514+ acl_d->count = ndefault;
3515+ } else {
3516+ acl_d->count = naccess;
3517+ }
3518+
3519+ return acl_d;
3520+}
3521+
0f6733d8 3522+SMB_ACL_T sys_acl_get_fd(int fd)
fa26e11c 3523+{
0f6733d8
WD
3524+ /*
3525+ * HPUX doesn't have the facl call. Fake it using the path.... JRA.
3526+ */
fa26e11c
WD
3527+
3528+ files_struct *fsp = file_find_fd(fd);
3529+
3530+ if (fsp == NULL) {
3531+ errno = EBADF;
3532+ return NULL;
3533+ }
3534+
0f6733d8
WD
3535+ /*
3536+ * We know we're in the same conn context. So we
3537+ * can use the relative path.
3538+ */
fa26e11c 3539+
5ca9317d 3540+ return sys_acl_get_file(fsp->fsp_name, SMB_ACL_TYPE_ACCESS);
fa26e11c
WD
3541+}
3542+
0f6733d8 3543+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
fa26e11c
WD
3544+{
3545+ *permset_d = 0;
3546+
3547+ return 0;
3548+}
3549+
0f6733d8 3550+int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
fa26e11c
WD
3551+{
3552+ if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
3553+ && perm != SMB_ACL_EXECUTE) {
3554+ errno = EINVAL;
3555+ return -1;
3556+ }
3557+
3558+ if (permset_d == NULL) {
3559+ errno = EINVAL;
3560+ return -1;
3561+ }
3562+
3563+ *permset_d |= perm;
3564+
3565+ return 0;
3566+}
3567+
0f6733d8 3568+int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
fa26e11c
WD
3569+{
3570+ return *permset_d & perm;
3571+}
3572+
0f6733d8 3573+char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p)
fa26e11c 3574+{
0f6733d8
WD
3575+ int i;
3576+ int len, maxlen;
3577+ char *text;
fa26e11c 3578+
0f6733d8
WD
3579+ /*
3580+ * use an initial estimate of 20 bytes per ACL entry
3581+ * when allocating memory for the text representation
3582+ * of the ACL
3583+ */
3584+ len = 0;
3585+ maxlen = 20 * acl_d->count;
252945ef 3586+ if ((text = SMB_MALLOC(maxlen)) == NULL) {
fa26e11c
WD
3587+ errno = ENOMEM;
3588+ return NULL;
3589+ }
3590+
3591+ for (i = 0; i < acl_d->count; i++) {
0f6733d8 3592+ struct acl *ap = &acl_d->acl[i];
0f6733d8
WD
3593+ struct group *gr;
3594+ char tagbuf[12];
3595+ char idbuf[12];
3596+ char *tag;
3597+ char *id = "";
3598+ char perms[4];
3599+ int nbytes;
fa26e11c
WD
3600+
3601+ switch (ap->a_type) {
0f6733d8
WD
3602+ /*
3603+ * for debugging purposes it's probably more
fa26e11c 3604+ * useful to dump unknown tag types rather
0f6733d8
WD
3605+ * than just returning an error
3606+ */
fa26e11c 3607+ default:
0f6733d8 3608+ slprintf(tagbuf, sizeof(tagbuf)-1, "0x%x",
fa26e11c
WD
3609+ ap->a_type);
3610+ tag = tagbuf;
0f6733d8 3611+ slprintf(idbuf, sizeof(idbuf)-1, "%ld",
fa26e11c
WD
3612+ (long)ap->a_id);
3613+ id = idbuf;
3614+ break;
3615+
3616+ case SMB_ACL_USER:
5ca9317d 3617+ id = uidtoname(ap->a_id);
fa26e11c
WD
3618+ case SMB_ACL_USER_OBJ:
3619+ tag = "user";
3620+ break;
3621+
3622+ case SMB_ACL_GROUP:
3623+ if ((gr = getgrgid(ap->a_id)) == NULL) {
0f6733d8 3624+ slprintf(idbuf, sizeof(idbuf)-1, "%ld",
fa26e11c
WD
3625+ (long)ap->a_id);
3626+ id = idbuf;
3627+ } else {
3628+ id = gr->gr_name;
3629+ }
3630+ case SMB_ACL_GROUP_OBJ:
3631+ tag = "group";
3632+ break;
3633+
3634+ case SMB_ACL_OTHER:
3635+ tag = "other";
3636+ break;
3637+
3638+ case SMB_ACL_MASK:
3639+ tag = "mask";
3640+ break;
3641+
3642+ }
3643+
3644+ perms[0] = (ap->a_perm & SMB_ACL_READ) ? 'r' : '-';
3645+ perms[1] = (ap->a_perm & SMB_ACL_WRITE) ? 'w' : '-';
3646+ perms[2] = (ap->a_perm & SMB_ACL_EXECUTE) ? 'x' : '-';
3647+ perms[3] = '\0';
3648+
3649+ /* <tag> : <qualifier> : rwx \n \0 */
3650+ nbytes = strlen(tag) + 1 + strlen(id) + 1 + 3 + 1 + 1;
3651+
0f6733d8
WD
3652+ /*
3653+ * If this entry would overflow the buffer
fa26e11c
WD
3654+ * allocate enough additional memory for this
3655+ * entry and an estimate of another 20 bytes
0f6733d8
WD
3656+ * for each entry still to be processed
3657+ */
fa26e11c
WD
3658+ if ((len + nbytes) > maxlen) {
3659+ char *oldtext = text;
3660+
3661+ maxlen += nbytes + 20 * (acl_d->count - i);
3662+
252945ef 3663+ if ((text = SMB_REALLOC(oldtext, maxlen)) == NULL) {
fa26e11c
WD
3664+ free(oldtext);
3665+ errno = ENOMEM;
3666+ return NULL;
3667+ }
3668+ }
3669+
0f6733d8 3670+ slprintf(&text[len], nbytes-1, "%s:%s:%s\n", tag, id, perms);
fa26e11c
WD
3671+ len += nbytes - 1;
3672+ }
3673+
3674+ if (len_p)
3675+ *len_p = len;
3676+
3677+ return text;
3678+}
3679+
0f6733d8 3680+SMB_ACL_T sys_acl_init(int count)
fa26e11c 3681+{
0f6733d8 3682+ SMB_ACL_T a;
fa26e11c
WD
3683+
3684+ if (count < 0) {
3685+ errno = EINVAL;
3686+ return NULL;
3687+ }
3688+
0f6733d8
WD
3689+ /*
3690+ * note that since the definition of the structure pointed
fa26e11c
WD
3691+ * to by the SMB_ACL_T includes the first element of the
3692+ * acl[] array, this actually allocates an ACL with room
0f6733d8
WD
3693+ * for (count+1) entries
3694+ */
252945ef 3695+ if ((a = SMB_MALLOC(sizeof(struct SMB_ACL_T) + count * sizeof(struct acl))) == NULL) {
fa26e11c
WD
3696+ errno = ENOMEM;
3697+ return NULL;
3698+ }
3699+
3700+ a->size = count + 1;
3701+ a->count = 0;
3702+ a->next = -1;
3703+
3704+ return a;
3705+}
3706+
3707+
0f6733d8 3708+int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
fa26e11c 3709+{
0f6733d8
WD
3710+ SMB_ACL_T acl_d;
3711+ SMB_ACL_ENTRY_T entry_d;
fa26e11c
WD
3712+
3713+ if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
3714+ errno = EINVAL;
3715+ return -1;
3716+ }
3717+
3718+ if (acl_d->count >= acl_d->size) {
3719+ errno = ENOSPC;
3720+ return -1;
3721+ }
3722+
0f6733d8
WD
3723+ entry_d = &acl_d->acl[acl_d->count++];
3724+ entry_d->a_type = 0;
3725+ entry_d->a_id = -1;
3726+ entry_d->a_perm = 0;
3727+ *entry_p = entry_d;
fa26e11c
WD
3728+
3729+ return 0;
3730+}
3731+
0f6733d8 3732+int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
fa26e11c
WD
3733+{
3734+ switch (tag_type) {
3735+ case SMB_ACL_USER:
3736+ case SMB_ACL_USER_OBJ:
3737+ case SMB_ACL_GROUP:
3738+ case SMB_ACL_GROUP_OBJ:
3739+ case SMB_ACL_OTHER:
3740+ case SMB_ACL_MASK:
3741+ entry_d->a_type = tag_type;
3742+ break;
3743+ default:
3744+ errno = EINVAL;
3745+ return -1;
3746+ }
3747+
3748+ return 0;
3749+}
3750+
0f6733d8 3751+int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
fa26e11c
WD
3752+{
3753+ if (entry_d->a_type != SMB_ACL_GROUP
3754+ && entry_d->a_type != SMB_ACL_USER) {
3755+ errno = EINVAL;
3756+ return -1;
3757+ }
3758+
3759+ entry_d->a_id = *((id_t *)qual_p);
3760+
3761+ return 0;
3762+}
3763+
0f6733d8 3764+int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
fa26e11c
WD
3765+{
3766+ if (*permset_d & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
3767+ return EINVAL;
3768+ }
3769+
3770+ entry_d->a_perm = *permset_d;
3771+
3772+ return 0;
3773+}
3774+
3775+/* Structure to capture the count for each type of ACE. */
3776+
3777+struct hpux_acl_types {
3778+ int n_user;
3779+ int n_def_user;
3780+ int n_user_obj;
3781+ int n_def_user_obj;
3782+
3783+ int n_group;
3784+ int n_def_group;
3785+ int n_group_obj;
3786+ int n_def_group_obj;
3787+
3788+ int n_other;
3789+ int n_other_obj;
3790+ int n_def_other_obj;
3791+
3792+ int n_class_obj;
3793+ int n_def_class_obj;
3794+
3795+ int n_illegal_obj;
3796+};
3797+
3798+/* count_obj:
3799+ * Counts the different number of objects in a given array of ACL
3800+ * structures.
3801+ * Inputs:
3802+ *
3803+ * acl_count - Count of ACLs in the array of ACL strucutres.
3804+ * aclp - Array of ACL structures.
3805+ * acl_type_count - Pointer to acl_types structure. Should already be
3806+ * allocated.
0f6733d8 3807+ * Output:
fa26e11c 3808+ *
0f6733d8 3809+ * acl_type_count - This structure is filled up with counts of various
fa26e11c
WD
3810+ * acl types.
3811+ */
3812+
3813+static int hpux_count_obj(int acl_count, struct acl *aclp, struct hpux_acl_types *acl_type_count)
3814+{
3815+ int i;
3816+
0f6733d8 3817+ memset(acl_type_count, 0, sizeof(struct hpux_acl_types));
fa26e11c 3818+
0f6733d8
WD
3819+ for(i=0;i<acl_count;i++) {
3820+ switch(aclp[i].a_type) {
3821+ case USER:
fa26e11c
WD
3822+ acl_type_count->n_user++;
3823+ break;
0f6733d8 3824+ case USER_OBJ:
fa26e11c
WD
3825+ acl_type_count->n_user_obj++;
3826+ break;
0f6733d8 3827+ case DEF_USER_OBJ:
fa26e11c
WD
3828+ acl_type_count->n_def_user_obj++;
3829+ break;
0f6733d8 3830+ case GROUP:
fa26e11c
WD
3831+ acl_type_count->n_group++;
3832+ break;
0f6733d8 3833+ case GROUP_OBJ:
fa26e11c
WD
3834+ acl_type_count->n_group_obj++;
3835+ break;
0f6733d8 3836+ case DEF_GROUP_OBJ:
fa26e11c
WD
3837+ acl_type_count->n_def_group_obj++;
3838+ break;
0f6733d8 3839+ case OTHER_OBJ:
fa26e11c
WD
3840+ acl_type_count->n_other_obj++;
3841+ break;
0f6733d8 3842+ case DEF_OTHER_OBJ:
fa26e11c
WD
3843+ acl_type_count->n_def_other_obj++;
3844+ break;
3845+ case CLASS_OBJ:
3846+ acl_type_count->n_class_obj++;
3847+ break;
3848+ case DEF_CLASS_OBJ:
3849+ acl_type_count->n_def_class_obj++;
3850+ break;
3851+ case DEF_USER:
3852+ acl_type_count->n_def_user++;
3853+ break;
3854+ case DEF_GROUP:
3855+ acl_type_count->n_def_group++;
3856+ break;
0f6733d8 3857+ default:
fa26e11c
WD
3858+ acl_type_count->n_illegal_obj++;
3859+ break;
3860+ }
3861+ }
3862+}
3863+
0f6733d8 3864+/* swap_acl_entries: Swaps two ACL entries.
fa26e11c
WD
3865+ *
3866+ * Inputs: aclp0, aclp1 - ACL entries to be swapped.
3867+ */
3868+
3869+static void hpux_swap_acl_entries(struct acl *aclp0, struct acl *aclp1)
3870+{
3871+ struct acl temp_acl;
3872+
3873+ temp_acl.a_type = aclp0->a_type;
3874+ temp_acl.a_id = aclp0->a_id;
3875+ temp_acl.a_perm = aclp0->a_perm;
3876+
3877+ aclp0->a_type = aclp1->a_type;
3878+ aclp0->a_id = aclp1->a_id;
3879+ aclp0->a_perm = aclp1->a_perm;
3880+
3881+ aclp1->a_type = temp_acl.a_type;
3882+ aclp1->a_id = temp_acl.a_id;
3883+ aclp1->a_perm = temp_acl.a_perm;
3884+}
3885+
3886+/* prohibited_duplicate_type
0f6733d8 3887+ * Identifies if given ACL type can have duplicate entries or
fa26e11c
WD
3888+ * not.
3889+ *
3890+ * Inputs: acl_type - ACL Type.
3891+ *
0f6733d8 3892+ * Outputs:
fa26e11c 3893+ *
0f6733d8 3894+ * Return..
fa26e11c
WD
3895+ *
3896+ * True - If the ACL type matches any of the prohibited types.
3897+ * False - If the ACL type doesn't match any of the prohibited types.
0f6733d8 3898+ */
fa26e11c
WD
3899+
3900+static BOOL hpux_prohibited_duplicate_type(int acl_type)
3901+{
0f6733d8 3902+ switch(acl_type) {
fa26e11c
WD
3903+ case USER:
3904+ case GROUP:
0f6733d8 3905+ case DEF_USER:
fa26e11c
WD
3906+ case DEF_GROUP:
3907+ return True;
0f6733d8
WD
3908+ default:
3909+ return False;
fa26e11c 3910+ }
fa26e11c
WD
3911+}
3912+
3913+/* get_needed_class_perm
3914+ * Returns the permissions of a ACL structure only if the ACL
0f6733d8 3915+ * type matches one of the pre-determined types for computing
fa26e11c
WD
3916+ * CLASS_OBJ permissions.
3917+ *
3918+ * Inputs: aclp - Pointer to ACL structure.
3919+ */
3920+
3921+static int hpux_get_needed_class_perm(struct acl *aclp)
3922+{
0f6733d8
WD
3923+ switch(aclp->a_type) {
3924+ case USER:
3925+ case GROUP_OBJ:
3926+ case GROUP:
3927+ case DEF_USER_OBJ:
fa26e11c 3928+ case DEF_USER:
0f6733d8 3929+ case DEF_GROUP_OBJ:
fa26e11c
WD
3930+ case DEF_GROUP:
3931+ case DEF_CLASS_OBJ:
0f6733d8 3932+ case DEF_OTHER_OBJ:
fa26e11c 3933+ return aclp->a_perm;
0f6733d8 3934+ default:
fa26e11c
WD
3935+ return 0;
3936+ }
3937+}
3938+
3939+/* acl_sort for HPUX.
3940+ * Sorts the array of ACL structures as per the description in
3941+ * aclsort man page. Refer to aclsort man page for more details
3942+ *
3943+ * Inputs:
3944+ *
3945+ * acl_count - Count of ACLs in the array of ACL structures.
3946+ * calclass - If this is not zero, then we compute the CLASS_OBJ
3947+ * permissions.
3948+ * aclp - Array of ACL structures.
3949+ *
3950+ * Outputs:
3951+ *
3952+ * aclp - Sorted array of ACL structures.
3953+ *
3954+ * Outputs:
3955+ *
3956+ * Returns 0 for success -1 for failure. Prints a message to the Samba
3957+ * debug log in case of failure.
3958+ */
3959+
3960+static int hpux_acl_sort(int acl_count, int calclass, struct acl *aclp)
3961+{
3962+#if !defined(HAVE_HPUX_ACLSORT)
0f6733d8
WD
3963+ /*
3964+ * The aclsort() system call is availabe on the latest HPUX General
3965+ * Patch Bundles. So for HPUX, we developed our version of acl_sort
3966+ * function. Because, we don't want to update to a new
3967+ * HPUX GR bundle just for aclsort() call.
3968+ */
fa26e11c
WD
3969+
3970+ struct hpux_acl_types acl_obj_count;
3971+ int n_class_obj_perm = 0;
3972+ int i, j;
0f6733d8
WD
3973+
3974+ if(!acl_count) {
fa26e11c
WD
3975+ DEBUG(10,("Zero acl count passed. Returning Success\n"));
3976+ return 0;
3977+ }
3978+
0f6733d8 3979+ if(aclp == NULL) {
fa26e11c
WD
3980+ DEBUG(0,("Null ACL pointer in hpux_acl_sort. Returning Failure. \n"));
3981+ return -1;
3982+ }
3983+
3984+ /* Count different types of ACLs in the ACLs array */
3985+
3986+ hpux_count_obj(acl_count, aclp, &acl_obj_count);
3987+
0f6733d8
WD
3988+ /* There should be only one entry each of type USER_OBJ, GROUP_OBJ,
3989+ * CLASS_OBJ and OTHER_OBJ
fa26e11c
WD
3990+ */
3991+
0f6733d8
WD
3992+ if( (acl_obj_count.n_user_obj != 1) ||
3993+ (acl_obj_count.n_group_obj != 1) ||
3994+ (acl_obj_count.n_class_obj != 1) ||
3995+ (acl_obj_count.n_other_obj != 1)
3996+ ) {
fa26e11c
WD
3997+ DEBUG(0,("hpux_acl_sort: More than one entry or no entries for \
3998+USER OBJ or GROUP_OBJ or OTHER_OBJ or CLASS_OBJ\n"));
3999+ return -1;
4000+ }
4001+
4002+ /* If any of the default objects are present, there should be only
4003+ * one of them each.
4004+ */
4005+
0f6733d8
WD
4006+ if( (acl_obj_count.n_def_user_obj > 1) || (acl_obj_count.n_def_group_obj > 1) ||
4007+ (acl_obj_count.n_def_other_obj > 1) || (acl_obj_count.n_def_class_obj > 1) ) {
fa26e11c
WD
4008+ DEBUG(0,("hpux_acl_sort: More than one entry for DEF_CLASS_OBJ \
4009+or DEF_USER_OBJ or DEF_GROUP_OBJ or DEF_OTHER_OBJ\n"));
4010+ return -1;
4011+ }
4012+
0f6733d8
WD
4013+ /* We now have proper number of OBJ and DEF_OBJ entries. Now sort the acl
4014+ * structures.
fa26e11c
WD
4015+ *
4016+ * Sorting crieteria - First sort by ACL type. If there are multiple entries of
4017+ * same ACL type, sort by ACL id.
4018+ *
0f6733d8 4019+ * I am using the trival kind of sorting method here because, performance isn't
fa26e11c 4020+ * really effected by the ACLs feature. More over there aren't going to be more
0f6733d8 4021+ * than 17 entries on HPUX.
fa26e11c
WD
4022+ */
4023+
0f6733d8 4024+ for(i=0; i<acl_count;i++) {
fa26e11c 4025+ for (j=i+1; j<acl_count; j++) {
0f6733d8 4026+ if( aclp[i].a_type > aclp[j].a_type ) {
fa26e11c
WD
4027+ /* ACL entries out of order, swap them */
4028+
4029+ hpux_swap_acl_entries((aclp+i), (aclp+j));
4030+
0f6733d8 4031+ } else if ( aclp[i].a_type == aclp[j].a_type ) {
fa26e11c
WD
4032+
4033+ /* ACL entries of same type, sort by id */
4034+
0f6733d8 4035+ if(aclp[i].a_id > aclp[j].a_id) {
fa26e11c
WD
4036+ hpux_swap_acl_entries((aclp+i), (aclp+j));
4037+ } else if (aclp[i].a_id == aclp[j].a_id) {
4038+ /* We have a duplicate entry. */
0f6733d8 4039+ if(hpux_prohibited_duplicate_type(aclp[i].a_type)) {
fa26e11c
WD
4040+ DEBUG(0, ("hpux_acl_sort: Duplicate entry: Type(hex): %x Id: %d\n",
4041+ aclp[i].a_type, aclp[i].a_id));
4042+ return -1;
4043+ }
4044+ }
4045+
4046+ }
4047+ }
4048+ }
4049+
4050+ /* set the class obj permissions to the computed one. */
0f6733d8 4051+ if(calclass) {
fa26e11c
WD
4052+ int n_class_obj_index = -1;
4053+
0f6733d8 4054+ for(i=0;i<acl_count;i++) {
fa26e11c
WD
4055+ n_class_obj_perm |= hpux_get_needed_class_perm((aclp+i));
4056+
0f6733d8 4057+ if(aclp[i].a_type == CLASS_OBJ)
fa26e11c
WD
4058+ n_class_obj_index = i;
4059+ }
4060+ aclp[n_class_obj_index].a_perm = n_class_obj_perm;
4061+ }
4062+
4063+ return 0;
4064+#else
4065+ return aclsort(acl_count, calclass, aclp);
4066+#endif
4067+}
4068+
0f6733d8
WD
4069+/*
4070+ * sort the ACL and check it for validity
fa26e11c 4071+ *
0f6733d8 4072+ * if it's a minimal ACL with only 4 entries then we
fa26e11c
WD
4073+ * need to recalculate the mask permissions to make
4074+ * sure that they are the same as the GROUP_OBJ
4075+ * permissions as required by the UnixWare acl() system call.
4076+ *
0f6733d8 4077+ * (note: since POSIX allows minimal ACLs which only contain
fa26e11c
WD
4078+ * 3 entries - ie there is no mask entry - we should, in theory,
4079+ * check for this and add a mask entry if necessary - however
4080+ * we "know" that the caller of this interface always specifies
4081+ * a mask so, in practice "this never happens" (tm) - if it *does*
4082+ * happen aclsort() will fail and return an error and someone will
0f6733d8
WD
4083+ * have to fix it ...)
4084+ */
fa26e11c
WD
4085+
4086+static int acl_sort(SMB_ACL_T acl_d)
4087+{
4088+ int fixmask = (acl_d->count <= 4);
4089+
4090+ if (hpux_acl_sort(acl_d->count, fixmask, acl_d->acl) != 0) {
4091+ errno = EINVAL;
4092+ return -1;
4093+ }
4094+ return 0;
4095+}
0f6733d8
WD
4096+
4097+int sys_acl_valid(SMB_ACL_T acl_d)
fa26e11c
WD
4098+{
4099+ return acl_sort(acl_d);
4100+}
4101+
0f6733d8 4102+int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
fa26e11c 4103+{
0f6733d8
WD
4104+ struct stat s;
4105+ struct acl *acl_p;
4106+ int acl_count;
4107+ struct acl *acl_buf = NULL;
4108+ int ret;
fa26e11c 4109+
0f6733d8
WD
4110+ if(hpux_acl_call_presence() == False) {
4111+ /* Looks like we don't have the acl() system call on HPUX.
4112+ * May be the system doesn't have the latest version of JFS.
4113+ */
4114+ errno=ENOSYS;
4115+ return -1;
fa26e11c
WD
4116+ }
4117+
4118+ if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
4119+ errno = EINVAL;
4120+ return -1;
4121+ }
4122+
4123+ if (acl_sort(acl_d) != 0) {
4124+ return -1;
4125+ }
4126+
0f6733d8
WD
4127+ acl_p = &acl_d->acl[0];
4128+ acl_count = acl_d->count;
fa26e11c 4129+
0f6733d8
WD
4130+ /*
4131+ * if it's a directory there is extra work to do
4132+ * since the acl() system call will replace both
4133+ * the access ACLs and the default ACLs (if any)
4134+ */
fa26e11c
WD
4135+ if (stat(name, &s) != 0) {
4136+ return -1;
4137+ }
4138+ if (S_ISDIR(s.st_mode)) {
0f6733d8
WD
4139+ SMB_ACL_T acc_acl;
4140+ SMB_ACL_T def_acl;
4141+ SMB_ACL_T tmp_acl;
4142+ int i;
fa26e11c
WD
4143+
4144+ if (type == SMB_ACL_TYPE_ACCESS) {
4145+ acc_acl = acl_d;
4146+ def_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT);
4147+
4148+ } else {
4149+ def_acl = acl_d;
4150+ acc_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS);
4151+ }
4152+
4153+ if (tmp_acl == NULL) {
4154+ return -1;
4155+ }
4156+
0f6733d8
WD
4157+ /*
4158+ * allocate a temporary buffer for the complete ACL
4159+ */
fa26e11c 4160+ acl_count = acc_acl->count + def_acl->count;
252945ef 4161+ acl_p = acl_buf = SMB_MALLOC_ARRAY(struct acl, acl_count);
fa26e11c
WD
4162+
4163+ if (acl_buf == NULL) {
4164+ sys_acl_free_acl(tmp_acl);
4165+ errno = ENOMEM;
4166+ return -1;
4167+ }
4168+
0f6733d8
WD
4169+ /*
4170+ * copy the access control and default entries into the buffer
4171+ */
fa26e11c 4172+ memcpy(&acl_buf[0], &acc_acl->acl[0],
0f6733d8 4173+ acc_acl->count * sizeof(acl_buf[0]));
fa26e11c
WD
4174+
4175+ memcpy(&acl_buf[acc_acl->count], &def_acl->acl[0],
0f6733d8 4176+ def_acl->count * sizeof(acl_buf[0]));
fa26e11c 4177+
0f6733d8
WD
4178+ /*
4179+ * set the ACL_DEFAULT flag on the default entries
4180+ */
fa26e11c
WD
4181+ for (i = acc_acl->count; i < acl_count; i++) {
4182+ acl_buf[i].a_type |= ACL_DEFAULT;
4183+ }
4184+
4185+ sys_acl_free_acl(tmp_acl);
4186+
4187+ } else if (type != SMB_ACL_TYPE_ACCESS) {
4188+ errno = EINVAL;
4189+ return -1;
4190+ }
4191+
4192+ ret = acl(name, ACL_SET, acl_count, acl_p);
4193+
0f6733d8
WD
4194+ if (acl_buf) {
4195+ free(acl_buf);
4196+ }
fa26e11c
WD
4197+
4198+ return ret;
4199+}
4200+
0f6733d8 4201+int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
fa26e11c 4202+{
0f6733d8
WD
4203+ /*
4204+ * HPUX doesn't have the facl call. Fake it using the path.... JRA.
4205+ */
fa26e11c
WD
4206+
4207+ files_struct *fsp = file_find_fd(fd);
4208+
4209+ if (fsp == NULL) {
4210+ errno = EBADF;
4211+ return NULL;
4212+ }
4213+
4214+ if (acl_sort(acl_d) != 0) {
4215+ return -1;
4216+ }
4217+
0f6733d8
WD
4218+ /*
4219+ * We know we're in the same conn context. So we
4220+ * can use the relative path.
4221+ */
fa26e11c 4222+
5ca9317d 4223+ return sys_acl_set_file(fsp->fsp_name, SMB_ACL_TYPE_ACCESS, acl_d);
fa26e11c
WD
4224+}
4225+
0f6733d8 4226+int sys_acl_delete_def_file(const char *path)
fa26e11c 4227+{
0f6733d8
WD
4228+ SMB_ACL_T acl_d;
4229+ int ret;
fa26e11c 4230+
0f6733d8
WD
4231+ /*
4232+ * fetching the access ACL and rewriting it has
4233+ * the effect of deleting the default ACL
4234+ */
fa26e11c
WD
4235+ if ((acl_d = sys_acl_get_file(path, SMB_ACL_TYPE_ACCESS)) == NULL) {
4236+ return -1;
4237+ }
4238+
4239+ ret = acl(path, ACL_SET, acl_d->count, acl_d->acl);
4240+
4241+ sys_acl_free_acl(acl_d);
0f6733d8 4242+
fa26e11c
WD
4243+ return ret;
4244+}
4245+
0f6733d8 4246+int sys_acl_free_text(char *text)
fa26e11c
WD
4247+{
4248+ free(text);
4249+ return 0;
4250+}
4251+
0f6733d8 4252+int sys_acl_free_acl(SMB_ACL_T acl_d)
fa26e11c
WD
4253+{
4254+ free(acl_d);
4255+ return 0;
4256+}
4257+
0f6733d8 4258+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
fa26e11c
WD
4259+{
4260+ return 0;
4261+}
4262+
4263+#elif defined(HAVE_IRIX_ACLS)
4264+
0f6733d8 4265+int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
fa26e11c
WD
4266+{
4267+ if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
4268+ errno = EINVAL;
4269+ return -1;
4270+ }
4271+
4272+ if (entry_p == NULL) {
4273+ errno = EINVAL;
4274+ return -1;
4275+ }
4276+
4277+ if (entry_id == SMB_ACL_FIRST_ENTRY) {
4278+ acl_d->next = 0;
4279+ }
4280+
4281+ if (acl_d->next < 0) {
4282+ errno = EINVAL;
4283+ return -1;
4284+ }
4285+
4286+ if (acl_d->next >= acl_d->aclp->acl_cnt) {
4287+ return 0;
4288+ }
4289+
4290+ *entry_p = &acl_d->aclp->acl_entry[acl_d->next++];
4291+
4292+ return 1;
4293+}
4294+
0f6733d8 4295+int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
fa26e11c
WD
4296+{
4297+ *type_p = entry_d->ae_tag;
4298+
4299+ return 0;
4300+}
4301+
0f6733d8 4302+int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
fa26e11c
WD
4303+{
4304+ *permset_p = entry_d;
4305+
4306+ return 0;
4307+}
4308+
0f6733d8 4309+void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
fa26e11c
WD
4310+{
4311+ if (entry_d->ae_tag != SMB_ACL_USER
4312+ && entry_d->ae_tag != SMB_ACL_GROUP) {
4313+ errno = EINVAL;
4314+ return NULL;
4315+ }
4316+
4317+ return &entry_d->ae_id;
4318+}
4319+
0f6733d8 4320+SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
fa26e11c 4321+{
0f6733d8 4322+ SMB_ACL_T a;
fa26e11c 4323+
252945ef 4324+ if ((a = SMB_MALLOC_P(struct SMB_ACL_T)) == NULL) {
fa26e11c
WD
4325+ errno = ENOMEM;
4326+ return NULL;
4327+ }
4328+ if ((a->aclp = acl_get_file(path_p, type)) == NULL) {
0f6733d8 4329+ SAFE_FREE(a);
fa26e11c
WD
4330+ return NULL;
4331+ }
4332+ a->next = -1;
4333+ a->freeaclp = True;
4334+ return a;
4335+}
4336+
0f6733d8 4337+SMB_ACL_T sys_acl_get_fd(int fd)
fa26e11c 4338+{
0f6733d8 4339+ SMB_ACL_T a;
fa26e11c 4340+
252945ef 4341+ if ((a = SMB_MALLOC_P(struct SMB_ACL_T)) == NULL) {
fa26e11c
WD
4342+ errno = ENOMEM;
4343+ return NULL;
4344+ }
4345+ if ((a->aclp = acl_get_fd(fd)) == NULL) {
0f6733d8 4346+ SAFE_FREE(a);
fa26e11c
WD
4347+ return NULL;
4348+ }
4349+ a->next = -1;
4350+ a->freeaclp = True;
4351+ return a;
4352+}
4353+
0f6733d8 4354+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
fa26e11c
WD
4355+{
4356+ permset_d->ae_perm = 0;
4357+
4358+ return 0;
4359+}
4360+
0f6733d8 4361+int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
fa26e11c
WD
4362+{
4363+ if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
4364+ && perm != SMB_ACL_EXECUTE) {
4365+ errno = EINVAL;
4366+ return -1;
4367+ }
4368+
4369+ if (permset_d == NULL) {
4370+ errno = EINVAL;
4371+ return -1;
4372+ }
4373+
4374+ permset_d->ae_perm |= perm;
4375+
4376+ return 0;
4377+}
4378+
0f6733d8 4379+int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
fa26e11c
WD
4380+{
4381+ return permset_d->ae_perm & perm;
4382+}
4383+
0f6733d8 4384+char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p)
fa26e11c
WD
4385+{
4386+ return acl_to_text(acl_d->aclp, len_p);
4387+}
4388+
0f6733d8 4389+SMB_ACL_T sys_acl_init(int count)
fa26e11c 4390+{
0f6733d8 4391+ SMB_ACL_T a;
fa26e11c
WD
4392+
4393+ if (count < 0) {
4394+ errno = EINVAL;
4395+ return NULL;
4396+ }
4397+
252945ef 4398+ if ((a = SMB_MALLOC(sizeof(struct SMB_ACL_T) + sizeof(struct acl))) == NULL) {
fa26e11c
WD
4399+ errno = ENOMEM;
4400+ return NULL;
4401+ }
4402+
4403+ a->next = -1;
4404+ a->freeaclp = False;
0f6733d8 4405+ a->aclp = (struct acl *)(&a->aclp + sizeof(struct acl *));
fa26e11c
WD
4406+ a->aclp->acl_cnt = 0;
4407+
4408+ return a;
4409+}
4410+
4411+
0f6733d8 4412+int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
fa26e11c 4413+{
0f6733d8
WD
4414+ SMB_ACL_T acl_d;
4415+ SMB_ACL_ENTRY_T entry_d;
fa26e11c
WD
4416+
4417+ if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
4418+ errno = EINVAL;
4419+ return -1;
4420+ }
4421+
4422+ if (acl_d->aclp->acl_cnt >= ACL_MAX_ENTRIES) {
4423+ errno = ENOSPC;
4424+ return -1;
4425+ }
4426+
0f6733d8
WD
4427+ entry_d = &acl_d->aclp->acl_entry[acl_d->aclp->acl_cnt++];
4428+ entry_d->ae_tag = 0;
4429+ entry_d->ae_id = 0;
4430+ entry_d->ae_perm = 0;
4431+ *entry_p = entry_d;
fa26e11c
WD
4432+
4433+ return 0;
4434+}
4435+
0f6733d8 4436+int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
fa26e11c
WD
4437+{
4438+ switch (tag_type) {
4439+ case SMB_ACL_USER:
4440+ case SMB_ACL_USER_OBJ:
4441+ case SMB_ACL_GROUP:
4442+ case SMB_ACL_GROUP_OBJ:
4443+ case SMB_ACL_OTHER:
4444+ case SMB_ACL_MASK:
4445+ entry_d->ae_tag = tag_type;
4446+ break;
4447+ default:
4448+ errno = EINVAL;
4449+ return -1;
4450+ }
4451+
4452+ return 0;
4453+}
4454+
0f6733d8 4455+int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
fa26e11c
WD
4456+{
4457+ if (entry_d->ae_tag != SMB_ACL_GROUP
4458+ && entry_d->ae_tag != SMB_ACL_USER) {
4459+ errno = EINVAL;
4460+ return -1;
4461+ }
4462+
4463+ entry_d->ae_id = *((id_t *)qual_p);
4464+
4465+ return 0;
4466+}
4467+
0f6733d8 4468+int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
fa26e11c
WD
4469+{
4470+ if (permset_d->ae_perm & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
4471+ return EINVAL;
4472+ }
4473+
4474+ entry_d->ae_perm = permset_d->ae_perm;
4475+
4476+ return 0;
4477+}
4478+
0f6733d8 4479+int sys_acl_valid(SMB_ACL_T acl_d)
fa26e11c
WD
4480+{
4481+ return acl_valid(acl_d->aclp);
4482+}
4483+
0f6733d8 4484+int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
fa26e11c
WD
4485+{
4486+ return acl_set_file(name, type, acl_d->aclp);
4487+}
4488+
0f6733d8 4489+int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
fa26e11c
WD
4490+{
4491+ return acl_set_fd(fd, acl_d->aclp);
4492+}
4493+
0f6733d8 4494+int sys_acl_delete_def_file(const char *name)
fa26e11c
WD
4495+{
4496+ return acl_delete_def_file(name);
4497+}
4498+
0f6733d8 4499+int sys_acl_free_text(char *text)
fa26e11c
WD
4500+{
4501+ return acl_free(text);
4502+}
4503+
0f6733d8 4504+int sys_acl_free_acl(SMB_ACL_T acl_d)
fa26e11c
WD
4505+{
4506+ if (acl_d->freeaclp) {
4507+ acl_free(acl_d->aclp);
4508+ }
4509+ acl_free(acl_d);
4510+ return 0;
4511+}
4512+
0f6733d8 4513+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
fa26e11c
WD
4514+{
4515+ return 0;
4516+}
4517+
4518+#elif defined(HAVE_AIX_ACLS)
4519+
4520+/* Donated by Medha Date, mdate@austin.ibm.com, for IBM */
4521+
0f6733d8 4522+int sys_acl_get_entry( SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
fa26e11c
WD
4523+{
4524+ struct acl_entry_link *link;
4525+ struct new_acl_entry *entry;
4526+ int keep_going;
4527+
4528+ DEBUG(10,("This is the count: %d\n",theacl->count));
4529+
0f6733d8
WD
4530+ /* Check if count was previously set to -1. *
4531+ * If it was, that means we reached the end *
4532+ * of the acl last time. */
4533+ if(theacl->count == -1)
4534+ return(0);
fa26e11c
WD
4535+
4536+ link = theacl;
0f6733d8
WD
4537+ /* To get to the next acl, traverse linked list until index *
4538+ * of acl matches the count we are keeping. This count is *
4539+ * incremented each time we return an acl entry. */
fa26e11c 4540+
0f6733d8 4541+ for(keep_going = 0; keep_going < theacl->count; keep_going++)
fa26e11c
WD
4542+ link = link->nextp;
4543+
4544+ entry = *entry_p = link->entryp;
4545+
4546+ DEBUG(10,("*entry_p is %d\n",entry_p));
4547+ DEBUG(10,("*entry_p->ace_access is %d\n",entry->ace_access));
4548+
4549+ /* Increment count */
4550+ theacl->count++;
0f6733d8 4551+ if(link->nextp == NULL)
fa26e11c
WD
4552+ theacl->count = -1;
4553+
0f6733d8 4554+ return(1);
fa26e11c
WD
4555+}
4556+
0f6733d8 4557+int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
fa26e11c
WD
4558+{
4559+ /* Initialize tag type */
4560+
4561+ *tag_type_p = -1;
4562+ DEBUG(10,("the tagtype is %d\n",entry_d->ace_id->id_type));
4563+
0f6733d8
WD
4564+ /* Depending on what type of entry we have, *
4565+ * return tag type. */
4566+ switch(entry_d->ace_id->id_type) {
fa26e11c
WD
4567+ case ACEID_USER:
4568+ *tag_type_p = SMB_ACL_USER;
4569+ break;
4570+ case ACEID_GROUP:
4571+ *tag_type_p = SMB_ACL_GROUP;
4572+ break;
4573+
4574+ case SMB_ACL_USER_OBJ:
4575+ case SMB_ACL_GROUP_OBJ:
4576+ case SMB_ACL_OTHER:
4577+ *tag_type_p = entry_d->ace_id->id_type;
4578+ break;
0f6733d8 4579+
fa26e11c 4580+ default:
0f6733d8 4581+ return(-1);
fa26e11c
WD
4582+ }
4583+
0f6733d8 4584+ return(0);
fa26e11c
WD
4585+}
4586+
0f6733d8 4587+int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
fa26e11c
WD
4588+{
4589+ DEBUG(10,("Starting AIX sys_acl_get_permset\n"));
4590+ *permset_p = &entry_d->ace_access;
4591+ DEBUG(10,("**permset_p is %d\n",**permset_p));
0f6733d8
WD
4592+ if(!(**permset_p & S_IXUSR) &&
4593+ !(**permset_p & S_IWUSR) &&
4594+ !(**permset_p & S_IRUSR) &&
4595+ (**permset_p != 0))
4596+ return(-1);
fa26e11c
WD
4597+
4598+ DEBUG(10,("Ending AIX sys_acl_get_permset\n"));
0f6733d8 4599+ return(0);
fa26e11c
WD
4600+}
4601+
0f6733d8 4602+void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
fa26e11c 4603+{
0f6733d8 4604+ return(entry_d->ace_id->id_data);
fa26e11c
WD
4605+}
4606+
0f6733d8 4607+SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
fa26e11c
WD
4608+{
4609+ struct acl *file_acl = (struct acl *)NULL;
4610+ struct acl_entry *acl_entry;
4611+ struct new_acl_entry *new_acl_entry;
4612+ struct ace_id *idp;
4613+ struct acl_entry_link *acl_entry_link;
4614+ struct acl_entry_link *acl_entry_link_head;
4615+ int i;
4616+ int rc = 0;
4617+ uid_t user_id;
4618+
252945ef 4619+ /* AIX has no DEFAULT */
85148847
WD
4620+ if ( type == SMB_ACL_TYPE_DEFAULT ) {
4621+ errno = ENOTSUP;
252945ef 4622+ return NULL;
85148847 4623+ }
252945ef 4624+
fa26e11c 4625+ /* Get the acl using statacl */
0f6733d8 4626+
fa26e11c
WD
4627+ DEBUG(10,("Entering sys_acl_get_file\n"));
4628+ DEBUG(10,("path_p is %s\n",path_p));
4629+
252945ef 4630+ file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
0f6733d8
WD
4631+
4632+ if(file_acl == NULL) {
fa26e11c
WD
4633+ errno=ENOMEM;
4634+ DEBUG(0,("Error in AIX sys_acl_get_file: %d\n",errno));
0f6733d8 4635+ return(NULL);
fa26e11c
WD
4636+ }
4637+
4638+ memset(file_acl,0,BUFSIZ);
4639+
4640+ rc = statacl((char *)path_p,0,file_acl,BUFSIZ);
0f6733d8 4641+ if(rc == -1) {
fa26e11c 4642+ DEBUG(0,("statacl returned %d with errno %d\n",rc,errno));
0f6733d8
WD
4643+ SAFE_FREE(file_acl);
4644+ return(NULL);
fa26e11c
WD
4645+ }
4646+
4647+ DEBUG(10,("Got facl and returned it\n"));
4648+
4649+ /* Point to the first acl entry in the acl */
4650+ acl_entry = file_acl->acl_ext;
4651+
0f6733d8
WD
4652+ /* Begin setting up the head of the linked list *
4653+ * that will be used for the storing the acl *
4654+ * in a way that is useful for the posix_acls.c *
4655+ * code. */
fa26e11c
WD
4656+
4657+ acl_entry_link_head = acl_entry_link = sys_acl_init(0);
0f6733d8
WD
4658+ if(acl_entry_link_head == NULL)
4659+ return(NULL);
fa26e11c 4660+
252945ef 4661+ acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
0f6733d8
WD
4662+ if(acl_entry_link->entryp == NULL) {
4663+ SAFE_FREE(file_acl);
fa26e11c
WD
4664+ errno = ENOMEM;
4665+ DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
0f6733d8 4666+ return(NULL);
fa26e11c
WD
4667+ }
4668+
4669+ DEBUG(10,("acl_entry is %d\n",acl_entry));
4670+ DEBUG(10,("acl_last(file_acl) id %d\n",acl_last(file_acl)));
4671+
0f6733d8
WD
4672+ /* Check if the extended acl bit is on. *
4673+ * If it isn't, do not show the *
4674+ * contents of the acl since AIX intends *
4675+ * the extended info to remain unused */
fa26e11c 4676+
0f6733d8 4677+ if(file_acl->acl_mode & S_IXACL){
fa26e11c 4678+ /* while we are not pointing to the very end */
0f6733d8 4679+ while(acl_entry < acl_last(file_acl)) {
fa26e11c
WD
4680+ /* before we malloc anything, make sure this is */
4681+ /* a valid acl entry and one that we want to map */
4682+ idp = id_nxt(acl_entry->ace_id);
0f6733d8
WD
4683+ if((acl_entry->ace_type == ACC_SPECIFY ||
4684+ (acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) {
4685+ acl_entry = acl_nxt(acl_entry);
4686+ continue;
fa26e11c
WD
4687+ }
4688+
4689+ idp = acl_entry->ace_id;
4690+
0f6733d8
WD
4691+ /* Check if this is the first entry in the linked list. *
4692+ * The first entry needs to keep prevp pointing to NULL *
4693+ * and already has entryp allocated. */
fa26e11c 4694+
0f6733d8 4695+ if(acl_entry_link_head->count != 0) {
252945ef 4696+ acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
fa26e11c 4697+
0f6733d8
WD
4698+ if(acl_entry_link->nextp == NULL) {
4699+ SAFE_FREE(file_acl);
fa26e11c
WD
4700+ errno = ENOMEM;
4701+ DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
0f6733d8 4702+ return(NULL);
fa26e11c
WD
4703+ }
4704+
4705+ acl_entry_link->nextp->prevp = acl_entry_link;
4706+ acl_entry_link = acl_entry_link->nextp;
252945ef 4707+ acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
0f6733d8
WD
4708+ if(acl_entry_link->entryp == NULL) {
4709+ SAFE_FREE(file_acl);
fa26e11c
WD
4710+ errno = ENOMEM;
4711+ DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
0f6733d8 4712+ return(NULL);
fa26e11c
WD
4713+ }
4714+ acl_entry_link->nextp = NULL;
4715+ }
4716+
4717+ acl_entry_link->entryp->ace_len = acl_entry->ace_len;
4718+
0f6733d8
WD
4719+ /* Don't really need this since all types are going *
4720+ * to be specified but, it's better than leaving it 0 */
fa26e11c
WD
4721+
4722+ acl_entry_link->entryp->ace_type = acl_entry->ace_type;
0f6733d8 4723+
fa26e11c 4724+ acl_entry_link->entryp->ace_access = acl_entry->ace_access;
0f6733d8
WD
4725+
4726+ memcpy(acl_entry_link->entryp->ace_id,idp,sizeof(struct ace_id));
fa26e11c 4727+
0f6733d8
WD
4728+ /* The access in the acl entries must be left shifted by *
4729+ * three bites, because they will ultimately be compared *
4730+ * to S_IRUSR, S_IWUSR, and S_IXUSR. */
fa26e11c 4731+
0f6733d8 4732+ switch(acl_entry->ace_type){
fa26e11c
WD
4733+ case ACC_PERMIT:
4734+ case ACC_SPECIFY:
4735+ acl_entry_link->entryp->ace_access = acl_entry->ace_access;
4736+ acl_entry_link->entryp->ace_access <<= 6;
4737+ acl_entry_link_head->count++;
4738+ break;
4739+ case ACC_DENY:
0f6733d8
WD
4740+ /* Since there is no way to return a DENY acl entry *
4741+ * change to PERMIT and then shift. */
fa26e11c
WD
4742+ DEBUG(10,("acl_entry->ace_access is %d\n",acl_entry->ace_access));
4743+ acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7;
4744+ DEBUG(10,("acl_entry_link->entryp->ace_access is %d\n",acl_entry_link->entryp->ace_access));
4745+ acl_entry_link->entryp->ace_access <<= 6;
4746+ acl_entry_link_head->count++;
4747+ break;
4748+ default:
0f6733d8 4749+ return(0);
fa26e11c
WD
4750+ }
4751+
4752+ DEBUG(10,("acl_entry = %d\n",acl_entry));
4753+ DEBUG(10,("The ace_type is %d\n",acl_entry->ace_type));
0f6733d8 4754+
fa26e11c
WD
4755+ acl_entry = acl_nxt(acl_entry);
4756+ }
4757+ } /* end of if enabled */
4758+
0f6733d8
WD
4759+ /* Since owner, group, other acl entries are not *
4760+ * part of the acl entries in an acl, they must *
4761+ * be dummied up to become part of the list. */
fa26e11c 4762+
0f6733d8 4763+ for( i = 1; i < 4; i++) {
fa26e11c 4764+ DEBUG(10,("i is %d\n",i));
0f6733d8 4765+ if(acl_entry_link_head->count != 0) {
252945ef 4766+ acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
0f6733d8
WD
4767+ if(acl_entry_link->nextp == NULL) {
4768+ SAFE_FREE(file_acl);
fa26e11c
WD
4769+ errno = ENOMEM;
4770+ DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
0f6733d8 4771+ return(NULL);
fa26e11c
WD
4772+ }
4773+
4774+ acl_entry_link->nextp->prevp = acl_entry_link;
4775+ acl_entry_link = acl_entry_link->nextp;
252945ef 4776+ acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
0f6733d8
WD
4777+ if(acl_entry_link->entryp == NULL) {
4778+ SAFE_FREE(file_acl);
fa26e11c
WD
4779+ errno = ENOMEM;
4780+ DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
0f6733d8 4781+ return(NULL);
fa26e11c
WD
4782+ }
4783+ }
4784+
4785+ acl_entry_link->nextp = NULL;
4786+
4787+ new_acl_entry = acl_entry_link->entryp;
4788+ idp = new_acl_entry->ace_id;
4789+
0f6733d8 4790+ new_acl_entry->ace_len = sizeof(struct acl_entry);
fa26e11c 4791+ new_acl_entry->ace_type = ACC_PERMIT;
0f6733d8 4792+ idp->id_len = sizeof(struct ace_id);
fa26e11c 4793+ DEBUG(10,("idp->id_len = %d\n",idp->id_len));
0f6733d8 4794+ memset(idp->id_data,0,sizeof(uid_t));
fa26e11c 4795+
0f6733d8 4796+ switch(i) {
fa26e11c
WD
4797+ case 2:
4798+ new_acl_entry->ace_access = file_acl->g_access << 6;
4799+ idp->id_type = SMB_ACL_GROUP_OBJ;
4800+ break;
4801+
4802+ case 3:
4803+ new_acl_entry->ace_access = file_acl->o_access << 6;
4804+ idp->id_type = SMB_ACL_OTHER;
4805+ break;
0f6733d8 4806+
fa26e11c
WD
4807+ case 1:
4808+ new_acl_entry->ace_access = file_acl->u_access << 6;
4809+ idp->id_type = SMB_ACL_USER_OBJ;
4810+ break;
0f6733d8 4811+
fa26e11c 4812+ default:
0f6733d8 4813+ return(NULL);
fa26e11c
WD
4814+
4815+ }
4816+
4817+ acl_entry_link_head->count++;
4818+ DEBUG(10,("new_acl_entry->ace_access = %d\n",new_acl_entry->ace_access));
4819+ }
4820+
4821+ acl_entry_link_head->count = 0;
0f6733d8 4822+ SAFE_FREE(file_acl);
fa26e11c 4823+
0f6733d8 4824+ return(acl_entry_link_head);
fa26e11c
WD
4825+}
4826+
0f6733d8 4827+SMB_ACL_T sys_acl_get_fd(int fd)
fa26e11c
WD
4828+{
4829+ struct acl *file_acl = (struct acl *)NULL;
4830+ struct acl_entry *acl_entry;
4831+ struct new_acl_entry *new_acl_entry;
4832+ struct ace_id *idp;
4833+ struct acl_entry_link *acl_entry_link;
4834+ struct acl_entry_link *acl_entry_link_head;
4835+ int i;
4836+ int rc = 0;
4837+ uid_t user_id;
4838+
4839+ /* Get the acl using fstatacl */
0f6733d8 4840+
fa26e11c
WD
4841+ DEBUG(10,("Entering sys_acl_get_fd\n"));
4842+ DEBUG(10,("fd is %d\n",fd));
252945ef 4843+ file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
fa26e11c 4844+
0f6733d8 4845+ if(file_acl == NULL) {
fa26e11c
WD
4846+ errno=ENOMEM;
4847+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
0f6733d8 4848+ return(NULL);
fa26e11c
WD
4849+ }
4850+
4851+ memset(file_acl,0,BUFSIZ);
4852+
4853+ rc = fstatacl(fd,0,file_acl,BUFSIZ);
0f6733d8 4854+ if(rc == -1) {
fa26e11c 4855+ DEBUG(0,("The fstatacl call returned %d with errno %d\n",rc,errno));
0f6733d8
WD
4856+ SAFE_FREE(file_acl);
4857+ return(NULL);
fa26e11c
WD
4858+ }
4859+
4860+ DEBUG(10,("Got facl and returned it\n"));
4861+
4862+ /* Point to the first acl entry in the acl */
4863+
4864+ acl_entry = file_acl->acl_ext;
0f6733d8
WD
4865+ /* Begin setting up the head of the linked list *
4866+ * that will be used for the storing the acl *
4867+ * in a way that is useful for the posix_acls.c *
4868+ * code. */
fa26e11c
WD
4869+
4870+ acl_entry_link_head = acl_entry_link = sys_acl_init(0);
0f6733d8
WD
4871+ if(acl_entry_link_head == NULL){
4872+ SAFE_FREE(file_acl);
4873+ return(NULL);
fa26e11c
WD
4874+ }
4875+
252945ef 4876+ acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
fa26e11c 4877+
0f6733d8 4878+ if(acl_entry_link->entryp == NULL) {
fa26e11c
WD
4879+ errno = ENOMEM;
4880+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
0f6733d8
WD
4881+ SAFE_FREE(file_acl);
4882+ return(NULL);
fa26e11c
WD
4883+ }
4884+
4885+ DEBUG(10,("acl_entry is %d\n",acl_entry));
4886+ DEBUG(10,("acl_last(file_acl) id %d\n",acl_last(file_acl)));
0f6733d8
WD
4887+
4888+ /* Check if the extended acl bit is on. *
4889+ * If it isn't, do not show the *
4890+ * contents of the acl since AIX intends *
4891+ * the extended info to remain unused */
4892+
4893+ if(file_acl->acl_mode & S_IXACL){
fa26e11c 4894+ /* while we are not pointing to the very end */
0f6733d8 4895+ while(acl_entry < acl_last(file_acl)) {
fa26e11c
WD
4896+ /* before we malloc anything, make sure this is */
4897+ /* a valid acl entry and one that we want to map */
4898+
4899+ idp = id_nxt(acl_entry->ace_id);
0f6733d8
WD
4900+ if((acl_entry->ace_type == ACC_SPECIFY ||
4901+ (acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) {
4902+ acl_entry = acl_nxt(acl_entry);
4903+ continue;
fa26e11c
WD
4904+ }
4905+
4906+ idp = acl_entry->ace_id;
0f6733d8
WD
4907+
4908+ /* Check if this is the first entry in the linked list. *
4909+ * The first entry needs to keep prevp pointing to NULL *
4910+ * and already has entryp allocated. */
fa26e11c 4911+
0f6733d8 4912+ if(acl_entry_link_head->count != 0) {
252945ef 4913+ acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
0f6733d8 4914+ if(acl_entry_link->nextp == NULL) {
fa26e11c
WD
4915+ errno = ENOMEM;
4916+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
0f6733d8
WD
4917+ SAFE_FREE(file_acl);
4918+ return(NULL);
fa26e11c
WD
4919+ }
4920+ acl_entry_link->nextp->prevp = acl_entry_link;
4921+ acl_entry_link = acl_entry_link->nextp;
252945ef 4922+ acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
0f6733d8 4923+ if(acl_entry_link->entryp == NULL) {
fa26e11c
WD
4924+ errno = ENOMEM;
4925+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
0f6733d8
WD
4926+ SAFE_FREE(file_acl);
4927+ return(NULL);
fa26e11c
WD
4928+ }
4929+
4930+ acl_entry_link->nextp = NULL;
4931+ }
4932+
4933+ acl_entry_link->entryp->ace_len = acl_entry->ace_len;
4934+
0f6733d8
WD
4935+ /* Don't really need this since all types are going *
4936+ * to be specified but, it's better than leaving it 0 */
fa26e11c
WD
4937+
4938+ acl_entry_link->entryp->ace_type = acl_entry->ace_type;
4939+ acl_entry_link->entryp->ace_access = acl_entry->ace_access;
4940+
0f6733d8 4941+ memcpy(acl_entry_link->entryp->ace_id, idp, sizeof(struct ace_id));
fa26e11c 4942+
0f6733d8
WD
4943+ /* The access in the acl entries must be left shifted by *
4944+ * three bites, because they will ultimately be compared *
4945+ * to S_IRUSR, S_IWUSR, and S_IXUSR. */
fa26e11c 4946+
0f6733d8 4947+ switch(acl_entry->ace_type){
fa26e11c
WD
4948+ case ACC_PERMIT:
4949+ case ACC_SPECIFY:
4950+ acl_entry_link->entryp->ace_access = acl_entry->ace_access;
4951+ acl_entry_link->entryp->ace_access <<= 6;
4952+ acl_entry_link_head->count++;
4953+ break;
4954+ case ACC_DENY:
0f6733d8
WD
4955+ /* Since there is no way to return a DENY acl entry *
4956+ * change to PERMIT and then shift. */
fa26e11c
WD
4957+ DEBUG(10,("acl_entry->ace_access is %d\n",acl_entry->ace_access));
4958+ acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7;
4959+ DEBUG(10,("acl_entry_link->entryp->ace_access is %d\n",acl_entry_link->entryp->ace_access));
4960+ acl_entry_link->entryp->ace_access <<= 6;
4961+ acl_entry_link_head->count++;
4962+ break;
4963+ default:
0f6733d8 4964+ return(0);
fa26e11c
WD
4965+ }
4966+
4967+ DEBUG(10,("acl_entry = %d\n",acl_entry));
4968+ DEBUG(10,("The ace_type is %d\n",acl_entry->ace_type));
0f6733d8 4969+
fa26e11c
WD
4970+ acl_entry = acl_nxt(acl_entry);
4971+ }
4972+ } /* end of if enabled */
4973+
0f6733d8
WD
4974+ /* Since owner, group, other acl entries are not *
4975+ * part of the acl entries in an acl, they must *
4976+ * be dummied up to become part of the list. */
fa26e11c 4977+
0f6733d8 4978+ for( i = 1; i < 4; i++) {
fa26e11c 4979+ DEBUG(10,("i is %d\n",i));
0f6733d8 4980+ if(acl_entry_link_head->count != 0){
252945ef 4981+ acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
0f6733d8 4982+ if(acl_entry_link->nextp == NULL) {
fa26e11c
WD
4983+ errno = ENOMEM;
4984+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
0f6733d8
WD
4985+ SAFE_FREE(file_acl);
4986+ return(NULL);
fa26e11c
WD
4987+ }
4988+
4989+ acl_entry_link->nextp->prevp = acl_entry_link;
4990+ acl_entry_link = acl_entry_link->nextp;
252945ef 4991+ acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
fa26e11c 4992+
0f6733d8
WD
4993+ if(acl_entry_link->entryp == NULL) {
4994+ SAFE_FREE(file_acl);
fa26e11c
WD
4995+ errno = ENOMEM;
4996+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
0f6733d8 4997+ return(NULL);
fa26e11c
WD
4998+ }
4999+ }
5000+
5001+ acl_entry_link->nextp = NULL;
0f6733d8 5002+
fa26e11c
WD
5003+ new_acl_entry = acl_entry_link->entryp;
5004+ idp = new_acl_entry->ace_id;
0f6733d8
WD
5005+
5006+ new_acl_entry->ace_len = sizeof(struct acl_entry);
fa26e11c 5007+ new_acl_entry->ace_type = ACC_PERMIT;
0f6733d8 5008+ idp->id_len = sizeof(struct ace_id);
fa26e11c 5009+ DEBUG(10,("idp->id_len = %d\n",idp->id_len));
0f6733d8
WD
5010+ memset(idp->id_data,0,sizeof(uid_t));
5011+
5012+ switch(i) {
fa26e11c
WD
5013+ case 2:
5014+ new_acl_entry->ace_access = file_acl->g_access << 6;
5015+ idp->id_type = SMB_ACL_GROUP_OBJ;
5016+ break;
0f6733d8 5017+
fa26e11c
WD
5018+ case 3:
5019+ new_acl_entry->ace_access = file_acl->o_access << 6;
5020+ idp->id_type = SMB_ACL_OTHER;
5021+ break;
0f6733d8 5022+
fa26e11c
WD
5023+ case 1:
5024+ new_acl_entry->ace_access = file_acl->u_access << 6;
5025+ idp->id_type = SMB_ACL_USER_OBJ;
5026+ break;
0f6733d8 5027+
fa26e11c 5028+ default:
0f6733d8 5029+ return(NULL);
fa26e11c 5030+ }
0f6733d8 5031+
fa26e11c
WD
5032+ acl_entry_link_head->count++;
5033+ DEBUG(10,("new_acl_entry->ace_access = %d\n",new_acl_entry->ace_access));
5034+ }
5035+
5036+ acl_entry_link_head->count = 0;
0f6733d8
WD
5037+ SAFE_FREE(file_acl);
5038+
5039+ return(acl_entry_link_head);
fa26e11c
WD
5040+}
5041+
0f6733d8 5042+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
fa26e11c
WD
5043+{
5044+ *permset = *permset & ~0777;
0f6733d8 5045+ return(0);
fa26e11c
WD
5046+}
5047+
0f6733d8 5048+int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
fa26e11c 5049+{
0f6733d8
WD
5050+ if((perm != 0) &&
5051+ (perm & (S_IXUSR | S_IWUSR | S_IRUSR)) == 0)
5052+ return(-1);
fa26e11c
WD
5053+
5054+ *permset |= perm;
5055+ DEBUG(10,("This is the permset now: %d\n",*permset));
0f6733d8 5056+ return(0);
fa26e11c
WD
5057+}
5058+
0f6733d8 5059+char *sys_acl_to_text( SMB_ACL_T theacl, ssize_t *plen)
fa26e11c 5060+{
0f6733d8 5061+ return(NULL);
fa26e11c
WD
5062+}
5063+
0f6733d8 5064+SMB_ACL_T sys_acl_init( int count)
fa26e11c
WD
5065+{
5066+ struct acl_entry_link *theacl = NULL;
0f6733d8 5067+
fa26e11c
WD
5068+ DEBUG(10,("Entering sys_acl_init\n"));
5069+
252945ef 5070+ theacl = SMB_MALLOC_P(struct acl_entry_link);
0f6733d8 5071+ if(theacl == NULL) {
fa26e11c
WD
5072+ errno = ENOMEM;
5073+ DEBUG(0,("Error in sys_acl_init is %d\n",errno));
0f6733d8 5074+ return(NULL);
fa26e11c
WD
5075+ }
5076+
5077+ theacl->count = 0;
5078+ theacl->nextp = NULL;
5079+ theacl->prevp = NULL;
5080+ theacl->entryp = NULL;
5081+ DEBUG(10,("Exiting sys_acl_init\n"));
0f6733d8 5082+ return(theacl);
fa26e11c
WD
5083+}
5084+
0f6733d8 5085+int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
fa26e11c
WD
5086+{
5087+ struct acl_entry_link *theacl;
5088+ struct acl_entry_link *acl_entryp;
5089+ struct acl_entry_link *temp_entry;
5090+ int counting;
5091+
5092+ DEBUG(10,("Entering the sys_acl_create_entry\n"));
5093+
5094+ theacl = acl_entryp = *pacl;
5095+
5096+ /* Get to the end of the acl before adding entry */
5097+
0f6733d8 5098+ for(counting=0; counting < theacl->count; counting++){
fa26e11c
WD
5099+ DEBUG(10,("The acl_entryp is %d\n",acl_entryp));
5100+ temp_entry = acl_entryp;
5101+ acl_entryp = acl_entryp->nextp;
5102+ }
5103+
0f6733d8 5104+ if(theacl->count != 0){
252945ef 5105+ temp_entry->nextp = acl_entryp = SMB_MALLOC_P(struct acl_entry_link);
0f6733d8 5106+ if(acl_entryp == NULL) {
fa26e11c
WD
5107+ errno = ENOMEM;
5108+ DEBUG(0,("Error in sys_acl_create_entry is %d\n",errno));
0f6733d8 5109+ return(-1);
fa26e11c
WD
5110+ }
5111+
5112+ DEBUG(10,("The acl_entryp is %d\n",acl_entryp));
5113+ acl_entryp->prevp = temp_entry;
5114+ DEBUG(10,("The acl_entryp->prevp is %d\n",acl_entryp->prevp));
5115+ }
5116+
252945ef 5117+ *pentry = acl_entryp->entryp = SMB_MALLOC_P(struct new_acl_entry);
0f6733d8 5118+ if(*pentry == NULL) {
fa26e11c
WD
5119+ errno = ENOMEM;
5120+ DEBUG(0,("Error in sys_acl_create_entry is %d\n",errno));
0f6733d8 5121+ return(-1);
fa26e11c
WD
5122+ }
5123+
0f6733d8
WD
5124+ memset(*pentry,0,sizeof(struct new_acl_entry));
5125+ acl_entryp->entryp->ace_len = sizeof(struct acl_entry);
fa26e11c 5126+ acl_entryp->entryp->ace_type = ACC_PERMIT;
0f6733d8 5127+ acl_entryp->entryp->ace_id->id_len = sizeof(struct ace_id);
fa26e11c
WD
5128+ acl_entryp->nextp = NULL;
5129+ theacl->count++;
5130+ DEBUG(10,("Exiting sys_acl_create_entry\n"));
0f6733d8 5131+ return(0);
fa26e11c
WD
5132+}
5133+
0f6733d8 5134+int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
fa26e11c
WD
5135+{
5136+ DEBUG(10,("Starting AIX sys_acl_set_tag_type\n"));
5137+ entry->ace_id->id_type = tagtype;
5138+ DEBUG(10,("The tag type is %d\n",entry->ace_id->id_type));
5139+ DEBUG(10,("Ending AIX sys_acl_set_tag_type\n"));
5140+}
5141+
0f6733d8 5142+int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
fa26e11c
WD
5143+{
5144+ DEBUG(10,("Starting AIX sys_acl_set_qualifier\n"));
0f6733d8 5145+ memcpy(entry->ace_id->id_data,qual,sizeof(uid_t));
fa26e11c 5146+ DEBUG(10,("Ending AIX sys_acl_set_qualifier\n"));
0f6733d8 5147+ return(0);
fa26e11c
WD
5148+}
5149+
0f6733d8 5150+int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
fa26e11c
WD
5151+{
5152+ DEBUG(10,("Starting AIX sys_acl_set_permset\n"));
0f6733d8
WD
5153+ if(!(*permset & S_IXUSR) &&
5154+ !(*permset & S_IWUSR) &&
5155+ !(*permset & S_IRUSR) &&
5156+ (*permset != 0))
5157+ return(-1);
fa26e11c
WD
5158+
5159+ entry->ace_access = *permset;
5160+ DEBUG(10,("entry->ace_access = %d\n",entry->ace_access));
5161+ DEBUG(10,("Ending AIX sys_acl_set_permset\n"));
0f6733d8 5162+ return(0);
fa26e11c
WD
5163+}
5164+
0f6733d8 5165+int sys_acl_valid( SMB_ACL_T theacl )
fa26e11c
WD
5166+{
5167+ int user_obj = 0;
5168+ int group_obj = 0;
5169+ int other_obj = 0;
5170+ struct acl_entry_link *acl_entry;
5171+
0f6733d8 5172+ for(acl_entry=theacl; acl_entry != NULL; acl_entry = acl_entry->nextp) {
fa26e11c
WD
5173+ user_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_USER_OBJ);
5174+ group_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_GROUP_OBJ);
5175+ other_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_OTHER);
5176+ }
5177+
5178+ DEBUG(10,("user_obj=%d, group_obj=%d, other_obj=%d\n",user_obj,group_obj,other_obj));
0f6733d8
WD
5179+
5180+ if(user_obj != 1 || group_obj != 1 || other_obj != 1)
5181+ return(-1);
fa26e11c 5182+
0f6733d8 5183+ return(0);
fa26e11c
WD
5184+}
5185+
0f6733d8 5186+int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
fa26e11c
WD
5187+{
5188+ struct acl_entry_link *acl_entry_link = NULL;
5189+ struct acl *file_acl = NULL;
5190+ struct acl *file_acl_temp = NULL;
5191+ struct acl_entry *acl_entry = NULL;
5192+ struct ace_id *ace_id = NULL;
5193+ uint id_type;
5194+ uint ace_access;
5195+ uint user_id;
5196+ uint acl_length;
5197+ uint rc;
5198+
5199+ DEBUG(10,("Entering sys_acl_set_file\n"));
5200+ DEBUG(10,("File name is %s\n",name));
0f6733d8 5201+
fa26e11c 5202+ /* AIX has no default ACL */
0f6733d8
WD
5203+ if(acltype == SMB_ACL_TYPE_DEFAULT)
5204+ return(0);
fa26e11c
WD
5205+
5206+ acl_length = BUFSIZ;
252945ef 5207+ file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
fa26e11c 5208+
0f6733d8 5209+ if(file_acl == NULL) {
fa26e11c
WD
5210+ errno = ENOMEM;
5211+ DEBUG(0,("Error in sys_acl_set_file is %d\n",errno));
0f6733d8 5212+ return(-1);
fa26e11c
WD
5213+ }
5214+
5215+ memset(file_acl,0,BUFSIZ);
5216+
5217+ file_acl->acl_len = ACL_SIZ;
5218+ file_acl->acl_mode = S_IXACL;
5219+
0f6733d8 5220+ for(acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) {
fa26e11c
WD
5221+ acl_entry_link->entryp->ace_access >>= 6;
5222+ id_type = acl_entry_link->entryp->ace_id->id_type;
5223+
0f6733d8 5224+ switch(id_type) {
fa26e11c
WD
5225+ case SMB_ACL_USER_OBJ:
5226+ file_acl->u_access = acl_entry_link->entryp->ace_access;
5227+ continue;
5228+ case SMB_ACL_GROUP_OBJ:
5229+ file_acl->g_access = acl_entry_link->entryp->ace_access;
5230+ continue;
5231+ case SMB_ACL_OTHER:
5232+ file_acl->o_access = acl_entry_link->entryp->ace_access;
5233+ continue;
5234+ case SMB_ACL_MASK:
5235+ continue;
5236+ }
5237+
0f6733d8
WD
5238+ if((file_acl->acl_len + sizeof(struct acl_entry)) > acl_length) {
5239+ acl_length += sizeof(struct acl_entry);
252945ef 5240+ file_acl_temp = (struct acl *)SMB_MALLOC(acl_length);
0f6733d8
WD
5241+ if(file_acl_temp == NULL) {
5242+ SAFE_FREE(file_acl);
fa26e11c
WD
5243+ errno = ENOMEM;
5244+ DEBUG(0,("Error in sys_acl_set_file is %d\n",errno));
0f6733d8
WD
5245+ return(-1);
5246+ }
fa26e11c
WD
5247+
5248+ memcpy(file_acl_temp,file_acl,file_acl->acl_len);
0f6733d8 5249+ SAFE_FREE(file_acl);
fa26e11c
WD
5250+ file_acl = file_acl_temp;
5251+ }
5252+
5253+ acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len);
0f6733d8 5254+ file_acl->acl_len += sizeof(struct acl_entry);
fa26e11c
WD
5255+ acl_entry->ace_len = acl_entry_link->entryp->ace_len;
5256+ acl_entry->ace_access = acl_entry_link->entryp->ace_access;
0f6733d8 5257+
fa26e11c 5258+ /* In order to use this, we'll need to wait until we can get denies */
0f6733d8
WD
5259+ /* if(!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
5260+ acl_entry->ace_type = ACC_SPECIFY; */
fa26e11c
WD
5261+
5262+ acl_entry->ace_type = ACC_SPECIFY;
0f6733d8 5263+
fa26e11c 5264+ ace_id = acl_entry->ace_id;
0f6733d8 5265+
fa26e11c
WD
5266+ ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
5267+ DEBUG(10,("The id type is %d\n",ace_id->id_type));
5268+ ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
0f6733d8
WD
5269+ memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof(uid_t));
5270+ memcpy(acl_entry->ace_id->id_data, &user_id, sizeof(uid_t));
fa26e11c
WD
5271+ }
5272+
0f6733d8 5273+ rc = chacl(name,file_acl,file_acl->acl_len);
fa26e11c
WD
5274+ DEBUG(10,("errno is %d\n",errno));
5275+ DEBUG(10,("return code is %d\n",rc));
0f6733d8 5276+ SAFE_FREE(file_acl);
fa26e11c 5277+ DEBUG(10,("Exiting the sys_acl_set_file\n"));
0f6733d8 5278+ return(rc);
fa26e11c
WD
5279+}
5280+
0f6733d8 5281+int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
fa26e11c
WD
5282+{
5283+ struct acl_entry_link *acl_entry_link = NULL;
5284+ struct acl *file_acl = NULL;
5285+ struct acl *file_acl_temp = NULL;
5286+ struct acl_entry *acl_entry = NULL;
5287+ struct ace_id *ace_id = NULL;
5288+ uint id_type;
5289+ uint user_id;
5290+ uint acl_length;
5291+ uint rc;
0f6733d8 5292+
fa26e11c
WD
5293+ DEBUG(10,("Entering sys_acl_set_fd\n"));
5294+ acl_length = BUFSIZ;
252945ef 5295+ file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
fa26e11c 5296+
0f6733d8 5297+ if(file_acl == NULL) {
fa26e11c
WD
5298+ errno = ENOMEM;
5299+ DEBUG(0,("Error in sys_acl_set_fd is %d\n",errno));
0f6733d8 5300+ return(-1);
fa26e11c
WD
5301+ }
5302+
5303+ memset(file_acl,0,BUFSIZ);
0f6733d8 5304+
fa26e11c
WD
5305+ file_acl->acl_len = ACL_SIZ;
5306+ file_acl->acl_mode = S_IXACL;
5307+
0f6733d8 5308+ for(acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) {
fa26e11c
WD
5309+ acl_entry_link->entryp->ace_access >>= 6;
5310+ id_type = acl_entry_link->entryp->ace_id->id_type;
5311+ DEBUG(10,("The id_type is %d\n",id_type));
5312+
0f6733d8 5313+ switch(id_type) {
fa26e11c
WD
5314+ case SMB_ACL_USER_OBJ:
5315+ file_acl->u_access = acl_entry_link->entryp->ace_access;
5316+ continue;
5317+ case SMB_ACL_GROUP_OBJ:
5318+ file_acl->g_access = acl_entry_link->entryp->ace_access;
5319+ continue;
5320+ case SMB_ACL_OTHER:
5321+ file_acl->o_access = acl_entry_link->entryp->ace_access;
5322+ continue;
5323+ case SMB_ACL_MASK:
5324+ continue;
5325+ }
5326+
0f6733d8
WD
5327+ if((file_acl->acl_len + sizeof(struct acl_entry)) > acl_length) {
5328+ acl_length += sizeof(struct acl_entry);
252945ef 5329+ file_acl_temp = (struct acl *)SMB_MALLOC(acl_length);
0f6733d8
WD
5330+ if(file_acl_temp == NULL) {
5331+ SAFE_FREE(file_acl);
fa26e11c
WD
5332+ errno = ENOMEM;
5333+ DEBUG(0,("Error in sys_acl_set_fd is %d\n",errno));
0f6733d8 5334+ return(-1);
fa26e11c
WD
5335+ }
5336+
5337+ memcpy(file_acl_temp,file_acl,file_acl->acl_len);
0f6733d8 5338+ SAFE_FREE(file_acl);
fa26e11c
WD
5339+ file_acl = file_acl_temp;
5340+ }
5341+
5342+ acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len);
0f6733d8 5343+ file_acl->acl_len += sizeof(struct acl_entry);
fa26e11c
WD
5344+ acl_entry->ace_len = acl_entry_link->entryp->ace_len;
5345+ acl_entry->ace_access = acl_entry_link->entryp->ace_access;
0f6733d8 5346+
fa26e11c 5347+ /* In order to use this, we'll need to wait until we can get denies */
0f6733d8 5348+ /* if(!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
fa26e11c 5349+ acl_entry->ace_type = ACC_SPECIFY; */
0f6733d8 5350+
fa26e11c 5351+ acl_entry->ace_type = ACC_SPECIFY;
0f6733d8 5352+
fa26e11c 5353+ ace_id = acl_entry->ace_id;
0f6733d8 5354+
fa26e11c
WD
5355+ ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
5356+ DEBUG(10,("The id type is %d\n",ace_id->id_type));
5357+ ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
0f6733d8
WD
5358+ memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof(uid_t));
5359+ memcpy(ace_id->id_data, &user_id, sizeof(uid_t));
fa26e11c 5360+ }
0f6733d8 5361+
fa26e11c
WD
5362+ rc = fchacl(fd,file_acl,file_acl->acl_len);
5363+ DEBUG(10,("errno is %d\n",errno));
5364+ DEBUG(10,("return code is %d\n",rc));
0f6733d8 5365+ SAFE_FREE(file_acl);
fa26e11c 5366+ DEBUG(10,("Exiting sys_acl_set_fd\n"));
0f6733d8 5367+ return(rc);
fa26e11c
WD
5368+}
5369+
0f6733d8 5370+int sys_acl_delete_def_file(const char *name)
fa26e11c
WD
5371+{
5372+ /* AIX has no default ACL */
5373+ return 0;
5374+}
5375+
0f6733d8 5376+int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
fa26e11c 5377+{
0f6733d8 5378+ return(*permset & perm);
fa26e11c
WD
5379+}
5380+
0f6733d8 5381+int sys_acl_free_text(char *text)
fa26e11c 5382+{
0f6733d8 5383+ return(0);
fa26e11c
WD
5384+}
5385+
0f6733d8 5386+int sys_acl_free_acl(SMB_ACL_T posix_acl)
fa26e11c
WD
5387+{
5388+ struct acl_entry_link *acl_entry_link;
5389+
0f6733d8
WD
5390+ for(acl_entry_link = posix_acl->nextp; acl_entry_link->nextp != NULL; acl_entry_link = acl_entry_link->nextp) {
5391+ SAFE_FREE(acl_entry_link->prevp->entryp);
5392+ SAFE_FREE(acl_entry_link->prevp);
fa26e11c
WD
5393+ }
5394+
0f6733d8
WD
5395+ SAFE_FREE(acl_entry_link->prevp->entryp);
5396+ SAFE_FREE(acl_entry_link->prevp);
5397+ SAFE_FREE(acl_entry_link->entryp);
5398+ SAFE_FREE(acl_entry_link);
5399+
5400+ return(0);
fa26e11c
WD
5401+}
5402+
0f6733d8 5403+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
fa26e11c 5404+{
0f6733d8 5405+ return(0);
fa26e11c
WD
5406+}
5407+
5408+#else /* No ACLs. */
5409+
4df546eb 5410+int sys_acl_get_entry(UNUSED(SMB_ACL_T the_acl), UNUSED(int entry_id), UNUSED(SMB_ACL_ENTRY_T *entry_p))
fa26e11c
WD
5411+{
5412+ errno = ENOSYS;
5413+ return -1;
5414+}
5415+
4df546eb 5416+int sys_acl_get_tag_type(UNUSED(SMB_ACL_ENTRY_T entry_d), UNUSED(SMB_ACL_TAG_T *tag_type_p))
fa26e11c
WD
5417+{
5418+ errno = ENOSYS;
5419+ return -1;
5420+}
5421+
4df546eb 5422+int sys_acl_get_permset(UNUSED(SMB_ACL_ENTRY_T entry_d), UNUSED(SMB_ACL_PERMSET_T *permset_p))
fa26e11c
WD
5423+{
5424+ errno = ENOSYS;
5425+ return -1;
5426+}
5427+
4df546eb 5428+void *sys_acl_get_qualifier(UNUSED(SMB_ACL_ENTRY_T entry_d))
fa26e11c
WD
5429+{
5430+ errno = ENOSYS;
5431+ return NULL;
5432+}
5433+
4df546eb 5434+SMB_ACL_T sys_acl_get_file(UNUSED(const char *path_p), UNUSED(SMB_ACL_TYPE_T type))
fa26e11c
WD
5435+{
5436+ errno = ENOSYS;
5ca9317d 5437+ return (SMB_ACL_T)NULL;
fa26e11c
WD
5438+}
5439+
4df546eb 5440+SMB_ACL_T sys_acl_get_fd(UNUSED(int fd))
fa26e11c
WD
5441+{
5442+ errno = ENOSYS;
5ca9317d 5443+ return (SMB_ACL_T)NULL;
fa26e11c
WD
5444+}
5445+
4df546eb 5446+int sys_acl_clear_perms(UNUSED(SMB_ACL_PERMSET_T permset))
fa26e11c
WD
5447+{
5448+ errno = ENOSYS;
5449+ return -1;
5450+}
5451+
4df546eb 5452+int sys_acl_add_perm( UNUSED(SMB_ACL_PERMSET_T permset), UNUSED(SMB_ACL_PERM_T perm))
fa26e11c
WD
5453+{
5454+ errno = ENOSYS;
5455+ return -1;
5456+}
5457+
0f6733d8 5458+int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
fa26e11c
WD
5459+{
5460+ errno = ENOSYS;
0f6733d8 5461+ return (permset & perm) ? 1 : 0;
fa26e11c
WD
5462+}
5463+
4df546eb 5464+char *sys_acl_to_text(UNUSED(SMB_ACL_T the_acl), UNUSED(ssize_t *plen))
fa26e11c
WD
5465+{
5466+ errno = ENOSYS;
5467+ return NULL;
5468+}
5469+
4df546eb 5470+int sys_acl_free_text(UNUSED(char *text))
fa26e11c
WD
5471+{
5472+ errno = ENOSYS;
5473+ return -1;
5474+}
5475+
4df546eb 5476+SMB_ACL_T sys_acl_init(UNUSED(int count))
fa26e11c
WD
5477+{
5478+ errno = ENOSYS;
5479+ return NULL;
5480+}
5481+
4df546eb 5482+int sys_acl_create_entry(UNUSED(SMB_ACL_T *pacl), UNUSED(SMB_ACL_ENTRY_T *pentry))
fa26e11c
WD
5483+{
5484+ errno = ENOSYS;
5485+ return -1;
5486+}
5487+
4df546eb 5488+int sys_acl_set_tag_type(UNUSED(SMB_ACL_ENTRY_T entry), UNUSED(SMB_ACL_TAG_T tagtype))
fa26e11c
WD
5489+{
5490+ errno = ENOSYS;
5491+ return -1;
5492+}
5493+
4df546eb 5494+int sys_acl_set_qualifier(UNUSED(SMB_ACL_ENTRY_T entry), UNUSED(void *qual))
fa26e11c
WD
5495+{
5496+ errno = ENOSYS;
5497+ return -1;
5498+}
5499+
4df546eb 5500+int sys_acl_set_permset(UNUSED(SMB_ACL_ENTRY_T entry), UNUSED(SMB_ACL_PERMSET_T permset))
fa26e11c
WD
5501+{
5502+ errno = ENOSYS;
5503+ return -1;
5504+}
5505+
4df546eb 5506+int sys_acl_valid(UNUSED(SMB_ACL_T theacl))
fa26e11c
WD
5507+{
5508+ errno = ENOSYS;
5509+ return -1;
5510+}
5511+
4df546eb 5512+int sys_acl_set_file(UNUSED(const char *name), UNUSED(SMB_ACL_TYPE_T acltype), UNUSED(SMB_ACL_T theacl))
fa26e11c
WD
5513+{
5514+ errno = ENOSYS;
5515+ return -1;
5516+}
5517+
4df546eb 5518+int sys_acl_set_fd(UNUSED(int fd), UNUSED(SMB_ACL_T theacl))
fa26e11c
WD
5519+{
5520+ errno = ENOSYS;
5521+ return -1;
5522+}
5523+
4df546eb 5524+int sys_acl_delete_def_file(UNUSED(const char *name))
fa26e11c
WD
5525+{
5526+ errno = ENOSYS;
5527+ return -1;
5528+}
5529+
4df546eb 5530+int sys_acl_free_acl(UNUSED(SMB_ACL_T the_acl))
fa26e11c
WD
5531+{
5532+ errno = ENOSYS;
5533+ return -1;
5534+}
5535+
4df546eb 5536+int sys_acl_free_qualifier(UNUSED(void *qual), UNUSED(SMB_ACL_TAG_T tagtype))
fa26e11c
WD
5537+{
5538+ errno = ENOSYS;
5539+ return -1;
5540+}
5541+
5542+#endif /* No ACLs. */
252945ef
WD
5543+
5544+/************************************************************************
5545+ Deliberately outside the ACL defines. Return 1 if this is a "no acls"
5546+ errno, 0 if not.
5547+************************************************************************/
5548+
5549+int no_acl_syscall_error(int err)
5550+{
5551+#if defined(ENOSYS)
5552+ if (err == ENOSYS) {
5553+ return 1;
5554+ }
5555+#endif
5556+#if defined(ENOTSUP)
5557+ if (err == ENOTSUP) {
5558+ return 1;
5559+ }
5560+#endif
5561+ return 0;
5562+}
131abbd3
WD
5563+
5564+#endif /* SUPPORT_ACLS */
9a7eef96
WD
5565--- old/lib/sysacls.h
5566+++ new/lib/sysacls.h
131abbd3
WD
5567@@ -0,0 +1,40 @@
5568+#ifdef SUPPORT_ACLS
5569+
5570+#ifdef HAVE_SYS_ACL_H
a35da1c7
WD
5571+#include <sys/acl.h>
5572+#endif
0909ae28
WD
5573+#ifdef HAVE_ACL_LIBACL_H
5574+#include <acl/libacl.h>
5575+#endif
a35da1c7
WD
5576+#include "smb_acls.h"
5577+
252945ef
WD
5578+#define SMB_MALLOC(cnt) new_array(char, cnt)
5579+#define SMB_MALLOC_P(obj) new_array(obj, 1)
5580+#define SMB_MALLOC_ARRAY(obj, cnt) new_array(obj, cnt)
5581+#define SMB_REALLOC(mem, cnt) realloc_array(mem, char, cnt)
5ca9317d 5582+#define slprintf snprintf
0f6733d8
WD
5583+
5584+int sys_acl_get_entry(SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p);
5585+int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p);
5586+int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p);
5587+void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d);
5588+SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type);
5589+SMB_ACL_T sys_acl_get_fd(int fd);
5590+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset);
5591+int sys_acl_add_perm(SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm);
5592+int sys_acl_get_perm(SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm);
5593+char *sys_acl_to_text(SMB_ACL_T the_acl, ssize_t *plen);
5594+SMB_ACL_T sys_acl_init(int count);
5595+int sys_acl_create_entry(SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry);
5596+int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype);
5597+int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry, void *qual);
5598+int sys_acl_set_permset(SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset);
5599+int sys_acl_valid(SMB_ACL_T theacl);
5600+int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl);
5601+int sys_acl_set_fd(int fd, SMB_ACL_T theacl);
5602+int sys_acl_delete_def_file(const char *name);
5603+int sys_acl_free_text(char *text);
5604+int sys_acl_free_acl(SMB_ACL_T the_acl);
5605+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype);
131abbd3
WD
5606+
5607+#endif /* SUPPORT_ACLS */
0870c22a
WD
5608--- old/log.c
5609+++ new/log.c
1aa236e1 5610@@ -625,8 +625,10 @@ static void log_formatted(enum logcode c
fb11cdd7
WD
5611 c[5] = !(iflags & ITEM_REPORT_PERMS) ? '.' : 'p';
5612 c[6] = !(iflags & ITEM_REPORT_OWNER) ? '.' : 'o';
5613 c[7] = !(iflags & ITEM_REPORT_GROUP) ? '.' : 'g';
5614- c[8] = '.';
5615- c[9] = '\0';
5616+ c[8] = !(iflags & ITEM_REPORT_ATIME) ? '.' : 'u';
5617+ c[9] = !(iflags & ITEM_REPORT_ACL) ? '.' : 'a';
5618+ c[10] = !(iflags & ITEM_REPORT_XATTR) ? '.' : 'x';
5619+ c[11] = '\0';
0870c22a
WD
5620
5621 if (iflags & (ITEM_IS_NEW|ITEM_MISSING_DATA)) {
5622 char ch = iflags & ITEM_IS_NEW ? '+' : '?';
9a7eef96
WD
5623--- old/options.c
5624+++ new/options.c
c1471566 5625@@ -47,6 +47,7 @@ int copy_dirlinks = 0;
0f6733d8
WD
5626 int copy_links = 0;
5627 int preserve_links = 0;
5628 int preserve_hard_links = 0;
5629+int preserve_acls = 0;
5630 int preserve_perms = 0;
90fa6d68 5631 int preserve_executability = 0;
0f6733d8 5632 int preserve_devices = 0;
fdf967c7 5633@@ -198,6 +199,7 @@ static void print_rsync_version(enum log
0f6733d8
WD
5634 char const *got_socketpair = "no ";
5635 char const *have_inplace = "no ";
5636 char const *hardlinks = "no ";
5637+ char const *acls = "no ";
5638 char const *links = "no ";
5639 char const *ipv6 = "no ";
5640 STRUCT_STAT *dumstat;
fdf967c7 5641@@ -214,6 +216,10 @@ static void print_rsync_version(enum log
0f6733d8
WD
5642 hardlinks = "";
5643 #endif
5644
09fb8f03 5645+#ifdef SUPPORT_ACLS
0f6733d8
WD
5646+ acls = "";
5647+#endif
5648+
09fb8f03 5649 #ifdef SUPPORT_LINKS
0f6733d8
WD
5650 links = "";
5651 #endif
fdf967c7 5652@@ -232,8 +238,8 @@ static void print_rsync_version(enum log
5e3c6c93
WD
5653 (int)(sizeof (int64) * 8));
5654 rprintf(f, " %ssocketpairs, %shardlinks, %ssymlinks, %sIPv6, batchfiles, %sinplace,\n",
5655 got_socketpair, hardlinks, links, ipv6, have_inplace);
5656- rprintf(f, " %sappend\n",
5657- have_inplace);
5658+ rprintf(f, " %sappend, %sACLs\n",
5659+ have_inplace, acls);
0f6733d8 5660
131abbd3 5661 #ifdef MAINTAINER_MODE
5e3c6c93 5662 rprintf(f, "Panic Action: \"%s\"\n", get_panic_action());
fdf967c7 5663@@ -279,7 +285,7 @@ void usage(enum logcode F)
5a9d3244 5664 rprintf(F," -q, --quiet suppress non-error messages\n");
4959107f 5665 rprintf(F," --no-motd suppress daemon-mode MOTD (see manpage caveat)\n");
5a9d3244
WD
5666 rprintf(F," -c, --checksum skip based on checksum, not mod-time & size\n");
5667- rprintf(F," -a, --archive archive mode; same as -rlptgoD (no -H)\n");
5668+ rprintf(F," -a, --archive archive mode; same as -rlptgoD (no -H, -A)\n");
5669 rprintf(F," --no-OPTION turn off an implied OPTION (e.g. --no-D)\n");
5670 rprintf(F," -r, --recursive recurse into directories\n");
5671 rprintf(F," -R, --relative use relative path names\n");
fdf967c7 5672@@ -301,6 +307,9 @@ void usage(enum logcode F)
0f6733d8 5673 rprintf(F," -p, --perms preserve permissions\n");
90fa6d68 5674 rprintf(F," -E, --executability preserve the file's executability\n");
063cf77b 5675 rprintf(F," --chmod=CHMOD affect file and/or directory permissions\n");
25d385b9 5676+#ifdef SUPPORT_ACLS
0f6733d8 5677+ rprintf(F," -A, --acls preserve ACLs (implies --perms)\n");
25d385b9 5678+#endif
90fa6d68 5679 rprintf(F," -o, --owner preserve owner (super-user only)\n");
0f6733d8 5680 rprintf(F," -g, --group preserve group\n");
1ed0b5c9 5681 rprintf(F," --devices preserve device files (super-user only)\n");
fdf967c7 5682@@ -421,6 +430,9 @@ static struct poptOption long_options[]
489b0a72
WD
5683 {"no-perms", 0, POPT_ARG_VAL, &preserve_perms, 0, 0, 0 },
5684 {"no-p", 0, POPT_ARG_VAL, &preserve_perms, 0, 0, 0 },
90fa6d68 5685 {"executability", 'E', POPT_ARG_NONE, &preserve_executability, 0, 0, 0 },
489b0a72
WD
5686+ {"acls", 'A', POPT_ARG_NONE, 0, 'A', 0, 0 },
5687+ {"no-acls", 0, POPT_ARG_VAL, &preserve_acls, 0, 0, 0 },
5688+ {"no-A", 0, POPT_ARG_VAL, &preserve_acls, 0, 0, 0 },
5689 {"times", 't', POPT_ARG_VAL, &preserve_times, 1, 0, 0 },
5690 {"no-times", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 },
5691 {"no-t", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 },
fdf967c7 5692@@ -1086,6 +1098,24 @@ int parse_arguments(int *argc, const cha
3b05e91f
WD
5693 usage(FINFO);
5694 exit_cleanup(0);
0f6733d8
WD
5695
5696+ case 'A':
4df546eb 5697+#ifdef SUPPORT_ACLS
70891d26 5698+ preserve_acls = 1;
a5e3a4cc 5699+ preserve_perms = 1;
489b0a72 5700+ break;
0f6733d8
WD
5701+#else
5702+ /* FIXME: this should probably be ignored with a
5703+ * warning and then countermeasures taken to
5704+ * restrict group and other access in the presence
5705+ * of any more restrictive ACLs, but this is safe
5706+ * for now */
5707+ snprintf(err_buf,sizeof(err_buf),
5708+ "ACLs are not supported on this %s\n",
5709+ am_server ? "server" : "client");
5710+ return 0;
25d385b9 5711+#endif
0f6733d8
WD
5712+
5713+
5714 default:
5715 /* A large opt value means that set_refuse_options()
27a7053c 5716 * turned this option off. */
fdf967c7 5717@@ -1528,6 +1558,10 @@ void server_options(char **args,int *arg
c7bc7375 5718
0f6733d8
WD
5719 if (preserve_hard_links)
5720 argstr[x++] = 'H';
25d385b9 5721+#ifdef SUPPORT_ACLS
0f6733d8
WD
5722+ if (preserve_acls)
5723+ argstr[x++] = 'A';
25d385b9 5724+#endif
0f6733d8
WD
5725 if (preserve_uid)
5726 argstr[x++] = 'o';
5727 if (preserve_gid)
9a7eef96
WD
5728--- old/receiver.c
5729+++ new/receiver.c
1aa236e1 5730@@ -47,6 +47,7 @@ extern int keep_partial;
1a2fa68f
WD
5731 extern int checksum_seed;
5732 extern int inplace;
5733 extern int delay_updates;
5734+extern mode_t orig_umask;
5735 extern struct stats stats;
a859733e 5736 extern char *stdout_format;
1a2fa68f 5737 extern char *tmpdir;
1aa236e1 5738@@ -347,6 +348,10 @@ int recv_files(int f_in, struct file_lis
a859733e
WD
5739 int itemizing = am_server ? logfile_format_has_i : stdout_format_has_i;
5740 enum logcode log_code = log_before_transfer ? FLOG : FINFO;
26c810d8
WD
5741 int max_phase = protocol_version >= 29 ? 2 : 1;
5742+ int dflt_perms = (ACCESSPERMS & ~orig_umask);
5c8b4e6e 5743+#ifdef SUPPORT_ACLS
d997cb77 5744+ const char *parent_dirname = "";
5c8b4e6e 5745+#endif
81ecd8e0 5746 int ndx, recv_ok;
26c810d8
WD
5747
5748 if (verbose > 2)
7b80cd0e 5749@@ -545,7 +550,16 @@ int recv_files(int f_in, struct file_lis
90fa6d68
WD
5750 * mode based on the local permissions and some heuristics. */
5751 if (!preserve_perms) {
5752 int exists = fd1 != -1;
5753- file->mode = dest_mode(file->mode, st.st_mode, exists);
26c810d8 5754+#ifdef SUPPORT_ACLS
d997cb77 5755+ const char *dn = file->dirname ? file->dirname : ".";
5c8b4e6e
WD
5756+ if (parent_dirname != dn
5757+ && strcmp(parent_dirname, dn) != 0) {
5758+ dflt_perms = default_perms_for_dir(dn);
5759+ parent_dirname = dn;
26c810d8
WD
5760+ }
5761+#endif
5762+ file->mode = dest_mode(file->mode, st.st_mode,
5763+ dflt_perms, exists);
90fa6d68
WD
5764 }
5765
bdf1eee8 5766 /* We now check to see if we are writing the file "inplace" */
9a7eef96
WD
5767--- old/rsync.c
5768+++ new/rsync.c
74eccbb1
WD
5769@@ -32,6 +32,7 @@
5770
162234a7
WD
5771 extern int verbose;
5772 extern int dry_run;
162234a7
WD
5773+extern int preserve_acls;
5774 extern int preserve_perms;
5775 extern int preserve_executability;
5776 extern int preserve_times;
70891d26 5777@@ -48,7 +49,6 @@ extern int preserve_gid;
78b1089b
WD
5778 extern int inplace;
5779 extern int keep_dirlinks;
5780 extern int make_backups;
5781-extern mode_t orig_umask;
5782 extern struct stats stats;
70891d26 5783 extern struct file_list *the_file_list;
78b1089b 5784 extern struct chmod_mode_struct *daemon_chmod_modes;
70891d26 5785@@ -153,7 +153,8 @@ void free_sums(struct sum_struct *s)
90fa6d68
WD
5786
5787 /* This is only called when we aren't preserving permissions. Figure out what
5788 * the permissions should be and return them merged back into the mode. */
bdf1eee8
WD
5789-mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int exists)
5790+mode_t dest_mode(mode_t flist_mode, mode_t stat_mode, int dflt_perms,
26c810d8 5791+ int exists)
90fa6d68 5792 {
bdf1eee8 5793 int new_mode;
25d385b9 5794 /* If the file already exists, we'll return the local permissions,
70891d26 5795@@ -170,56 +171,65 @@ mode_t dest_mode(mode_t flist_mode, mode
bdf1eee8 5796 new_mode |= (new_mode & 0444) >> 2;
90fa6d68 5797 }
bdf1eee8
WD
5798 } else {
5799- /* Apply the umask and turn off special permissions. */
5800- new_mode = flist_mode & (~CHMOD_BITS | (ACCESSPERMS & ~orig_umask));
5801+ /* Apply destination default permissions and turn
5802+ * off special permissions. */
5803+ new_mode = flist_mode & (~CHMOD_BITS | dflt_perms);
5804 }
bdf1eee8 5805 return new_mode;
0870c22a
WD
5806 }
5807
5808-int set_file_attrs(char *fname, struct file_struct *file, STRUCT_STAT *st,
5809+int set_file_attrs(char *fname, struct file_struct *file, statx *sxp,
5810 int flags)
5811 {
5812 int updated = 0;
5813- STRUCT_STAT st2;
5814+ statx sx2;
5815 int change_uid, change_gid;
1ed0b5c9 5816 mode_t new_mode = file->mode;
0870c22a
WD
5817
5818- if (!st) {
5819+ if (!sxp) {
5820 if (dry_run)
5821 return 1;
5822- if (link_stat(fname, &st2, 0) < 0) {
5823+ if (link_stat(fname, &sx2.st, 0) < 0) {
5824 rsyserr(FERROR, errno, "stat %s failed",
5825 full_fname(fname));
5826 return 0;
5827 }
5828- st = &st2;
5829+#ifdef SUPPORT_ACLS
5830+ sx2.acc_acl = sx2.def_acl = NULL;
5831+#endif
1ed0b5c9 5832 if (!preserve_perms && S_ISDIR(new_mode)
0870c22a
WD
5833- && st->st_mode & S_ISGID) {
5834+ && sx2.st.st_mode & S_ISGID) {
5835 /* We just created this directory and its setgid
5836 * bit is on, so make sure it stays on. */
1ed0b5c9 5837 new_mode |= S_ISGID;
0870c22a
WD
5838 }
5839+ sxp = &sx2;
5840 }
5841
5842- if (!preserve_times || (S_ISDIR(st->st_mode) && omit_dir_times))
5843+#ifdef SUPPORT_ACLS
5844+ if (preserve_acls && !ACL_READY(*sxp))
98ccc74a 5845+ get_acl(fname, sxp);
0870c22a
WD
5846+#endif
5847+
5848+ if (!preserve_times || (S_ISDIR(sxp->st.st_mode) && omit_dir_times))
5849 flags |= ATTRS_SKIP_MTIME;
5850 if (!(flags & ATTRS_SKIP_MTIME)
5851- && cmp_time(st->st_mtime, file->modtime) != 0) {
5852- int ret = set_modtime(fname, file->modtime, st->st_mode);
5853+ && cmp_time(sxp->st.st_mtime, file->modtime) != 0) {
5854+ int ret = set_modtime(fname, file->modtime, sxp->st.st_mode);
5855 if (ret < 0) {
5856 rsyserr(FERROR, errno, "failed to set times on %s",
5857 full_fname(fname));
5858- return 0;
5859+ goto cleanup;
5860 }
5861 if (ret == 0) /* ret == 1 if symlink could not be set */
5862 updated = 1;
5863 }
5864
70891d26
WD
5865- change_uid = am_root && preserve_uid && st->st_uid != F_UID(file);
5866+ change_uid = am_root && preserve_uid && sxp->st.st_uid != F_UID(file);
5867 change_gid = preserve_gid && F_GID(file) != GID_NONE
5868- && st->st_gid != F_GID(file);
5869+ && sxp->st.st_gid != F_GID(file);
0870c22a
WD
5870 #if !defined HAVE_LCHOWN && !defined CHOWN_MODIFIES_SYMLINK
5871- if (S_ISLNK(st->st_mode))
5872+ if (S_ISLNK(sxp->st.st_mode))
5873 ;
5874 else
5875 #endif
70891d26 5876@@ -229,45 +239,57 @@ int set_file_attrs(char *fname, struct f
0870c22a
WD
5877 rprintf(FINFO,
5878 "set uid of %s from %ld to %ld\n",
5879 fname,
70891d26
WD
5880- (long)st->st_uid, (long)F_UID(file));
5881+ (long)sxp->st.st_uid, (long)F_UID(file));
0870c22a
WD
5882 }
5883 if (change_gid) {
5884 rprintf(FINFO,
5885 "set gid of %s from %ld to %ld\n",
5886 fname,
70891d26
WD
5887- (long)st->st_gid, (long)F_GID(file));
5888+ (long)sxp->st.st_gid, (long)F_GID(file));
0870c22a
WD
5889 }
5890 }
5891 if (do_lchown(fname,
70891d26
WD
5892- change_uid ? F_UID(file) : st->st_uid,
5893- change_gid ? F_GID(file) : st->st_gid) != 0) {
5894+ change_uid ? F_UID(file) : sxp->st.st_uid,
5895+ change_gid ? F_GID(file) : sxp->st.st_gid) != 0) {
0870c22a
WD
5896 /* shouldn't have attempted to change uid or gid
5897 * unless have the privilege */
5898 rsyserr(FERROR, errno, "%s %s failed",
5899 change_uid ? "chown" : "chgrp",
5900 full_fname(fname));
5901- return 0;
5902+ goto cleanup;
5903 }
5904 /* a lchown had been done - we have to re-stat if the
5905 * destination had the setuid or setgid bits set due
5906 * to the side effect of the chown call */
5907- if (st->st_mode & (S_ISUID | S_ISGID)) {
5908- link_stat(fname, st,
5909- keep_dirlinks && S_ISDIR(st->st_mode));
5910+ if (sxp->st.st_mode & (S_ISUID | S_ISGID)) {
5911+ link_stat(fname, &sxp->st,
5912+ keep_dirlinks && S_ISDIR(sxp->st.st_mode));
5913 }
c6437996
WD
5914 updated = 1;
5915 }
34a409bc 5916
1ed0b5c9
WD
5917 if (daemon_chmod_modes && !S_ISLNK(new_mode))
5918 new_mode = tweak_mode(new_mode, daemon_chmod_modes);
5919+
c6437996 5920+#ifdef SUPPORT_ACLS
98ccc74a 5921+ /* It's OK to call set_acl() now, even for a dir, as the generator
c6437996
WD
5922+ * will enable owner-writability using chmod, if necessary.
5923+ *
98ccc74a 5924+ * If set_acl() changes permission bits in the process of setting
0870c22a 5925+ * an access ACL, it changes sxp->st.st_mode so we know whether we
98ccc74a
WD
5926+ * need to chmod(). */
5927+ if (preserve_acls && set_acl(fname, file, sxp) == 0)
c6437996
WD
5928+ updated = 1;
5929+#endif
5930+
34a409bc 5931 #ifdef HAVE_CHMOD
3d3ad7f1
WD
5932- if (!BITS_EQUAL(st->st_mode, new_mode, CHMOD_BITS)) {
5933+ if (!BITS_EQUAL(sxp->st.st_mode, new_mode, CHMOD_BITS)) {
1ed0b5c9 5934 int ret = do_chmod(fname, new_mode);
0870c22a
WD
5935 if (ret < 0) {
5936 rsyserr(FERROR, errno,
5937 "failed to set permissions on %s",
5938 full_fname(fname));
5939- return 0;
5940+ goto cleanup;
5941 }
5942 if (ret == 0) /* ret == 1 if symlink could not be set */
5943 updated = 1;
70891d26 5944@@ -280,6 +302,11 @@ int set_file_attrs(char *fname, struct f
0870c22a 5945 else
74eccbb1 5946 rprintf(FCLIENT, "%s is uptodate\n", fname);
0870c22a
WD
5947 }
5948+ cleanup:
5949+#ifdef SUPPORT_ACLS
5950+ if (preserve_acls && sxp == &sx2)
98ccc74a 5951+ free_acl(&sx2);
0870c22a
WD
5952+#endif
5953 return updated;
5954 }
5955
9a7eef96
WD
5956--- old/rsync.h
5957+++ new/rsync.h
7e27b6c0 5958@@ -532,6 +532,14 @@ struct idev_node {
0870c22a
WD
5959 #define IN_LOOPBACKNET 127
5960 #endif
0f6733d8 5961
131abbd3 5962+#ifndef HAVE_NO_ACLS
4df546eb
WD
5963+#define SUPPORT_ACLS 1
5964+#endif
0f6733d8 5965+
4df546eb
WD
5966+#if HAVE_UNIXWARE_ACLS|HAVE_SOLARIS_ACLS|HAVE_HPUX_ACLS
5967+#define ACLS_NEED_MASK 1
5968+#endif
0f6733d8 5969+
0870c22a
WD
5970 #define GID_NONE ((gid_t)-1)
5971
590329e5 5972 union file_extras {
7e27b6c0
WD
5973@@ -551,6 +559,7 @@ struct file_struct {
5974 extern int file_extra_cnt;
3b3650bb
WD
5975 extern int preserve_uid;
5976 extern int preserve_gid;
5977+extern int preserve_acls;
5978
5979 #define FILE_STRUCT_LEN (offsetof(struct file_struct, basename))
5980 #define EXTRA_LEN (sizeof (union file_extras))
7e27b6c0 5981@@ -583,10 +592,12 @@ extern int preserve_gid;
1aa236e1 5982 /* When the associated option is on, all entries will have these present: */
fdf967c7
WD
5983 #define F_UID(f) REQ_EXTRA(f, preserve_uid)->unum
5984 #define F_GID(f) REQ_EXTRA(f, preserve_gid)->unum
1aa236e1 5985+#define F_ACL(f) REQ_EXTRA(f, preserve_acls)->unum
70891d26 5986
81ecd8e0 5987 /* These items are per-entry optional and mutally exclusive: */
7c15d5aa 5988 #define F_HL_GNUM(f) OPT_EXTRA(f, LEN64_BUMP(f))->num
7b80cd0e 5989 #define F_HL_PREV(f) OPT_EXTRA(f, LEN64_BUMP(f))->num
81ecd8e0 5990+#define F_DEF_ACL(f) OPT_EXTRA(f, LEN64_BUMP(f))->unum
70891d26 5991
81ecd8e0
WD
5992 /* This optional item might follow an F_HL_*() item.
5993 * (Note: a device doesn't need to check LEN64_BUMP(f).) */
7e27b6c0 5994@@ -722,6 +733,17 @@ struct stats {
6250eb3e
WD
5995
5996 struct chmod_mode_struct;
5997
5998+#define EMPTY_ITEM_LIST {NULL, 0, 0}
5999+
6000+typedef struct {
6001+ void *items;
6002+ size_t count;
6003+ size_t malloced;
6004+} item_list;
6005+
645e162c
WD
6006+#define EXPAND_ITEM_LIST(lp, type, incr) \
6007+ (type*)expand_item_list(lp, sizeof (type), #type, incr)
6250eb3e
WD
6008+
6009 #include "byteorder.h"
6010 #include "lib/mdfour.h"
6011 #include "lib/wildmatch.h"
7e27b6c0 6012@@ -740,6 +762,16 @@ struct chmod_mode_struct;
3758a5a5 6013 #define NORETURN __attribute__((__noreturn__))
d997cb77 6014 #endif
0870c22a 6015
0870c22a
WD
6016+typedef struct {
6017+ STRUCT_STAT st;
6018+#ifdef SUPPORT_ACLS
6019+ struct rsync_acl *acc_acl; /* access ACL */
6020+ struct rsync_acl *def_acl; /* default ACL */
6021+#endif
6022+} statx;
6023+
6024+#define ACL_READY(sx) ((sx).acc_acl != NULL)
0f6733d8
WD
6025+
6026 #include "proto.h"
6027
6028 /* We have replacement versions of these if they're missing. */
9a7eef96
WD
6029--- old/rsync.yo
6030+++ new/rsync.yo
4959107f 6031@@ -301,7 +301,7 @@ to the detailed description below for a
5a9d3244 6032 -q, --quiet suppress non-error messages
4959107f 6033 --no-motd suppress daemon-mode MOTD (see caveat)
5a9d3244
WD
6034 -c, --checksum skip based on checksum, not mod-time & size
6035- -a, --archive archive mode; same as -rlptgoD (no -H)
6036+ -a, --archive archive mode; same as -rlptgoD (no -H, -A)
6037 --no-OPTION turn off an implied OPTION (e.g. --no-D)
6038 -r, --recursive recurse into directories
6039 -R, --relative use relative path names
4959107f 6040@@ -323,6 +323,7 @@ to the detailed description below for a
0f6733d8 6041 -p, --perms preserve permissions
90fa6d68 6042 -E, --executability preserve executability
063cf77b 6043 --chmod=CHMOD affect file and/or directory permissions
90fa6d68 6044+ -A, --acls preserve ACLs (implies -p) [non-standard]
90fa6d68 6045 -o, --owner preserve owner (super-user only)
0f6733d8 6046 -g, --group preserve group
1ed0b5c9 6047 --devices preserve device files (super-user only)
d997cb77 6048@@ -754,7 +755,9 @@ quote(itemization(
90fa6d68
WD
6049 permissions, though the bf(--executability) option might change just
6050 the execute permission for the file.
03baf100
WD
6051 it() New files get their "normal" permission bits set to the source
6052- file's permissions masked with the receiving end's umask setting, and
6053+ file's permissions masked with the receiving directory's default
6054+ permissions (either the receiving process's umask, or the permissions
6055+ specified via the destination directory's default ACL), and
6056 their special permission bits disabled except in the case where a new
6057 directory inherits a setgid bit from its parent directory.
90fa6d68 6058 ))
d997cb77 6059@@ -785,9 +788,11 @@ The preservation of the destination's se
03baf100
WD
6060 directories when bf(--perms) is off was added in rsync 2.6.7. Older rsync
6061 versions erroneously preserved the three special permission bits for
6062 newly-created files when bf(--perms) was off, while overriding the
6063-destination's setgid bit setting on a newly-created directory. (Keep in
6064-mind that it is the version of the receiving rsync that affects this
6065-behavior.)
6066+destination's setgid bit setting on a newly-created directory. Default ACL
6067+observance was added to the ACL patch for rsync 2.6.7, so older (or
6068+non-ACL-enabled) rsyncs use the umask even if default ACLs are present.
6069+(Keep in mind that it is the version of the receiving rsync that affects
6070+these behaviors.)
90fa6d68 6071
90fa6d68
WD
6072 dit(bf(-E, --executability)) This option causes rsync to preserve the
6073 executability (or non-executability) of regular files when bf(--perms) is
b80daf10 6074@@ -805,6 +810,14 @@ quote(itemization(
90fa6d68
WD
6075
6076 If bf(--perms) is enabled, this option is ignored.
6077
6078+dit(bf(-A, --acls)) This option causes rsync to update the destination
6079+ACLs to be the same as the source ACLs. This nonstandard option only
6080+works if the remote rsync also supports it. bf(--acls) implies bf(--perms).
b57f8e02 6081+
b80daf10 6082+The ACL-sending protocol used by this version was first introduced in
590329e5 6083+the patch that was shipped with 2.6.8. Sending ACLs to an older version
b80daf10 6084+of the ACL patch is not supported.
90fa6d68
WD
6085+
6086 dit(bf(--chmod)) This option tells rsync to apply one or more
6087 comma-separated "chmod" strings to the permission of the files in the
6088 transfer. The resulting value is treated as though it was the permissions
b80daf10 6089@@ -1402,8 +1415,8 @@ if the receiving rsync is at least versi
0870c22a
WD
6090 with older versions of rsync, but that also turns on the output of other
6091 verbose messages).
6092
6093-The "%i" escape has a cryptic output that is 9 letters long. The general
6094-format is like the string bf(YXcstpogz), where bf(Y) is replaced by the
6095+The "%i" escape has a cryptic output that is 11 letters long. The general
6096+format is like the string bf(YXcstpoguax), where bf(Y) is replaced by the
6097 type of update being done, bf(X) is replaced by the file-type, and the
6098 other letters represent attributes that may be output if they are being
6099 modified.
b80daf10 6100@@ -1452,7 +1465,11 @@ quote(itemization(
0870c22a
WD
6101 sender's value (requires bf(--owner) and super-user privileges).
6102 it() A bf(g) means the group is different and is being updated to the
6103 sender's value (requires bf(--group) and the authority to set the group).
6104- it() The bf(z) slot is reserved for future use.
6105+ it() The bf(u) slot is reserved for reporting update (access) time changes
6106+ (a feature that is not yet released).
6107+ it() The bf(a) means that the ACL information changed.
6108+ it() The bf(x) slot is reserved for reporting extended attribute changes
6109+ (a feature that is not yet released).
6110 ))
6111
6112 One other output is possible: when deleting files, the "%i" will output
9a7eef96
WD
6113--- old/smb_acls.h
6114+++ new/smb_acls.h
0870c22a
WD
6115@@ -0,0 +1,281 @@
6116+/*
6117+ Unix SMB/Netbios implementation.
6118+ Version 2.2.x
6119+ Portable SMB ACL interface
6120+ Copyright (C) Jeremy Allison 2000
6121+
6122+ This program is free software; you can redistribute it and/or modify
6123+ it under the terms of the GNU General Public License as published by
6124+ the Free Software Foundation; either version 2 of the License, or
6125+ (at your option) any later version.
6126+
6127+ This program is distributed in the hope that it will be useful,
6128+ but WITHOUT ANY WARRANTY; without even the implied warranty of
6129+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
6130+ GNU General Public License for more details.
6131+
6132+ You should have received a copy of the GNU General Public License
6133+ along with this program; if not, write to the Free Software
6134+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
6135+*/
0f6733d8
WD
6136+
6137+#ifndef _SMB_ACLS_H
6138+#define _SMB_ACLS_H
6139+
e6a7303b 6140+#if defined HAVE_POSIX_ACLS
0f6733d8
WD
6141+
6142+/* This is an identity mapping (just remove the SMB_). */
6143+
6144+#define SMB_ACL_TAG_T acl_tag_t
6145+#define SMB_ACL_TYPE_T acl_type_t
6146+#define SMB_ACL_PERMSET_T acl_permset_t
6147+#define SMB_ACL_PERM_T acl_perm_t
6148+#define SMB_ACL_READ ACL_READ
6149+#define SMB_ACL_WRITE ACL_WRITE
6150+#define SMB_ACL_EXECUTE ACL_EXECUTE
6151+
6152+/* Types of ACLs. */
6153+#define SMB_ACL_USER ACL_USER
6154+#define SMB_ACL_USER_OBJ ACL_USER_OBJ
6155+#define SMB_ACL_GROUP ACL_GROUP
6156+#define SMB_ACL_GROUP_OBJ ACL_GROUP_OBJ
6157+#define SMB_ACL_OTHER ACL_OTHER
6158+#define SMB_ACL_MASK ACL_MASK
6159+
6160+#define SMB_ACL_T acl_t
6161+
6162+#define SMB_ACL_ENTRY_T acl_entry_t
6163+
6164+#define SMB_ACL_FIRST_ENTRY ACL_FIRST_ENTRY
6165+#define SMB_ACL_NEXT_ENTRY ACL_NEXT_ENTRY
6166+
6167+#define SMB_ACL_TYPE_ACCESS ACL_TYPE_ACCESS
6168+#define SMB_ACL_TYPE_DEFAULT ACL_TYPE_DEFAULT
6169+
e6a7303b 6170+#elif defined HAVE_TRU64_ACLS
0f6733d8
WD
6171+
6172+/* This is for DEC/Compaq Tru64 UNIX */
6173+
6174+#define SMB_ACL_TAG_T acl_tag_t
6175+#define SMB_ACL_TYPE_T acl_type_t
6176+#define SMB_ACL_PERMSET_T acl_permset_t
6177+#define SMB_ACL_PERM_T acl_perm_t
6178+#define SMB_ACL_READ ACL_READ
6179+#define SMB_ACL_WRITE ACL_WRITE
6180+#define SMB_ACL_EXECUTE ACL_EXECUTE
6181+
6182+/* Types of ACLs. */
6183+#define SMB_ACL_USER ACL_USER
6184+#define SMB_ACL_USER_OBJ ACL_USER_OBJ
6185+#define SMB_ACL_GROUP ACL_GROUP
6186+#define SMB_ACL_GROUP_OBJ ACL_GROUP_OBJ
6187+#define SMB_ACL_OTHER ACL_OTHER
6188+#define SMB_ACL_MASK ACL_MASK
6189+
6190+#define SMB_ACL_T acl_t
6191+
6192+#define SMB_ACL_ENTRY_T acl_entry_t
6193+
6194+#define SMB_ACL_FIRST_ENTRY 0
6195+#define SMB_ACL_NEXT_ENTRY 1
6196+
6197+#define SMB_ACL_TYPE_ACCESS ACL_TYPE_ACCESS
6198+#define SMB_ACL_TYPE_DEFAULT ACL_TYPE_DEFAULT
6199+
e6a7303b 6200+#elif defined HAVE_UNIXWARE_ACLS || defined HAVE_SOLARIS_ACLS
0f6733d8
WD
6201+/*
6202+ * Donated by Michael Davidson <md@sco.COM> for UnixWare / OpenUNIX.
6203+ * Modified by Toomas Soome <tsoome@ut.ee> for Solaris.
6204+ */
6205+
6206+/* SVR4.2 ES/MP ACLs */
6207+typedef int SMB_ACL_TAG_T;
6208+typedef int SMB_ACL_TYPE_T;
6209+typedef ushort *SMB_ACL_PERMSET_T;
6210+typedef ushort SMB_ACL_PERM_T;
6211+#define SMB_ACL_READ 4
6212+#define SMB_ACL_WRITE 2
6213+#define SMB_ACL_EXECUTE 1
6214+
6215+/* Types of ACLs. */
6216+#define SMB_ACL_USER USER
6217+#define SMB_ACL_USER_OBJ USER_OBJ
6218+#define SMB_ACL_GROUP GROUP
6219+#define SMB_ACL_GROUP_OBJ GROUP_OBJ
6220+#define SMB_ACL_OTHER OTHER_OBJ
6221+#define SMB_ACL_MASK CLASS_OBJ
6222+
6223+typedef struct SMB_ACL_T {
6224+ int size;
6225+ int count;
6226+ int next;
6227+ struct acl acl[1];
6228+} *SMB_ACL_T;
6229+
6230+typedef struct acl *SMB_ACL_ENTRY_T;
6231+
6232+#define SMB_ACL_FIRST_ENTRY 0
6233+#define SMB_ACL_NEXT_ENTRY 1
6234+
6235+#define SMB_ACL_TYPE_ACCESS 0
6236+#define SMB_ACL_TYPE_DEFAULT 1
6237+
53c1073a
WD
6238+#ifdef __CYGWIN__
6239+#define SMB_ACL_LOSES_SPECIAL_MODE_BITS
6240+#endif
6241+
e6a7303b 6242+#elif defined HAVE_HPUX_ACLS
0f6733d8
WD
6243+
6244+/*
6245+ * Based on the Solaris & UnixWare code.
6246+ */
6247+
6248+#undef GROUP
6249+#include <sys/aclv.h>
6250+
6251+/* SVR4.2 ES/MP ACLs */
6252+typedef int SMB_ACL_TAG_T;
6253+typedef int SMB_ACL_TYPE_T;
6254+typedef ushort *SMB_ACL_PERMSET_T;
6255+typedef ushort SMB_ACL_PERM_T;
6256+#define SMB_ACL_READ 4
6257+#define SMB_ACL_WRITE 2
6258+#define SMB_ACL_EXECUTE 1
6259+
6260+/* Types of ACLs. */
6261+#define SMB_ACL_USER USER
6262+#define SMB_ACL_USER_OBJ USER_OBJ
6263+#define SMB_ACL_GROUP GROUP
6264+#define SMB_ACL_GROUP_OBJ GROUP_OBJ
6265+#define SMB_ACL_OTHER OTHER_OBJ
6266+#define SMB_ACL_MASK CLASS_OBJ
6267+
6268+typedef struct SMB_ACL_T {
6269+ int size;
6270+ int count;
6271+ int next;
6272+ struct acl acl[1];
6273+} *SMB_ACL_T;
6274+
6275+typedef struct acl *SMB_ACL_ENTRY_T;
6276+
6277+#define SMB_ACL_FIRST_ENTRY 0
6278+#define SMB_ACL_NEXT_ENTRY 1
6279+
6280+#define SMB_ACL_TYPE_ACCESS 0
6281+#define SMB_ACL_TYPE_DEFAULT 1
6282+
e6a7303b 6283+#elif defined HAVE_IRIX_ACLS
0f6733d8
WD
6284+
6285+#define SMB_ACL_TAG_T acl_tag_t
6286+#define SMB_ACL_TYPE_T acl_type_t
6287+#define SMB_ACL_PERMSET_T acl_permset_t
6288+#define SMB_ACL_PERM_T acl_perm_t
6289+#define SMB_ACL_READ ACL_READ
6290+#define SMB_ACL_WRITE ACL_WRITE
6291+#define SMB_ACL_EXECUTE ACL_EXECUTE
6292+
6293+/* Types of ACLs. */
6294+#define SMB_ACL_USER ACL_USER
6295+#define SMB_ACL_USER_OBJ ACL_USER_OBJ
6296+#define SMB_ACL_GROUP ACL_GROUP
6297+#define SMB_ACL_GROUP_OBJ ACL_GROUP_OBJ
6298+#define SMB_ACL_OTHER ACL_OTHER_OBJ
6299+#define SMB_ACL_MASK ACL_MASK
6300+
6301+typedef struct SMB_ACL_T {
6302+ int next;
6303+ BOOL freeaclp;
6304+ struct acl *aclp;
6305+} *SMB_ACL_T;
6306+
6307+#define SMB_ACL_ENTRY_T acl_entry_t
6308+
6309+#define SMB_ACL_FIRST_ENTRY 0
6310+#define SMB_ACL_NEXT_ENTRY 1
6311+
6312+#define SMB_ACL_TYPE_ACCESS ACL_TYPE_ACCESS
6313+#define SMB_ACL_TYPE_DEFAULT ACL_TYPE_DEFAULT
6314+
e6a7303b 6315+#elif defined HAVE_AIX_ACLS
0f6733d8
WD
6316+
6317+/* Donated by Medha Date, mdate@austin.ibm.com, for IBM */
6318+
6319+#include "/usr/include/acl.h"
6320+
6321+typedef uint *SMB_ACL_PERMSET_T;
6322+
6323+struct acl_entry_link{
6324+ struct acl_entry_link *prevp;
6325+ struct new_acl_entry *entryp;
6326+ struct acl_entry_link *nextp;
6327+ int count;
6328+};
6329+
6330+struct new_acl_entry{
6331+ unsigned short ace_len;
6332+ unsigned short ace_type;
6333+ unsigned int ace_access;
6334+ struct ace_id ace_id[1];
6335+};
6336+
6337+#define SMB_ACL_ENTRY_T struct new_acl_entry*
6338+#define SMB_ACL_T struct acl_entry_link*
6339+
6340+#define SMB_ACL_TAG_T unsigned short
6341+#define SMB_ACL_TYPE_T int
6342+#define SMB_ACL_PERM_T uint
6343+#define SMB_ACL_READ S_IRUSR
6344+#define SMB_ACL_WRITE S_IWUSR
6345+#define SMB_ACL_EXECUTE S_IXUSR
6346+
6347+/* Types of ACLs. */
6348+#define SMB_ACL_USER ACEID_USER
6349+#define SMB_ACL_USER_OBJ 3
6350+#define SMB_ACL_GROUP ACEID_GROUP
6351+#define SMB_ACL_GROUP_OBJ 4
6352+#define SMB_ACL_OTHER 5
6353+#define SMB_ACL_MASK 6
6354+
6355+
6356+#define SMB_ACL_FIRST_ENTRY 1
6357+#define SMB_ACL_NEXT_ENTRY 2
6358+
6359+#define SMB_ACL_TYPE_ACCESS 0
6360+#define SMB_ACL_TYPE_DEFAULT 1
6361+
6362+#else /* No ACLs. */
6363+
6364+/* No ACLS - fake it. */
6365+#define SMB_ACL_TAG_T int
6366+#define SMB_ACL_TYPE_T int
6367+#define SMB_ACL_PERMSET_T mode_t
6368+#define SMB_ACL_PERM_T mode_t
6369+#define SMB_ACL_READ S_IRUSR
6370+#define SMB_ACL_WRITE S_IWUSR
6371+#define SMB_ACL_EXECUTE S_IXUSR
6372+
6373+/* Types of ACLs. */
6374+#define SMB_ACL_USER 0
6375+#define SMB_ACL_USER_OBJ 1
6376+#define SMB_ACL_GROUP 2
6377+#define SMB_ACL_GROUP_OBJ 3
6378+#define SMB_ACL_OTHER 4
6379+#define SMB_ACL_MASK 5
6380+
6381+typedef struct SMB_ACL_T {
6382+ int dummy;
6383+} *SMB_ACL_T;
6384+
6385+typedef struct SMB_ACL_ENTRY_T {
6386+ int dummy;
6387+} *SMB_ACL_ENTRY_T;
6388+
6389+#define SMB_ACL_FIRST_ENTRY 0
6390+#define SMB_ACL_NEXT_ENTRY 1
6391+
6392+#define SMB_ACL_TYPE_ACCESS 0
6393+#define SMB_ACL_TYPE_DEFAULT 1
6394+
6395+#endif /* No ACLs. */
6396+#endif /* _SMB_ACLS_H */
475c4a36
WD
6397--- old/testsuite/acls.test
6398+++ new/testsuite/acls.test
6399@@ -0,0 +1,34 @@
6400+#! /bin/sh
6401+
6402+# This program is distributable under the terms of the GNU GPL (see
6403+# COPYING).
6404+
6405+# Test that rsync handles basic ACL preservation.
6406+
6407+. $srcdir/testsuite/rsync.fns
6408+
6409+$RSYNC --version | grep ", ACLs" >/dev/null || test_skipped "Rsync is configured without ACL support"
6410+case "$setfacl_nodef" in
6411+true) test_skipped "I don't know how to use your setfacl command" ;;
6412+esac
6413+
6414+makepath "$fromdir/foo"
6415+echo something >"$fromdir/file1"
6416+echo else >"$fromdir/file2"
6417+
6418+files='foo file1 file2'
6419+
6420+setfacl -m u:0:7 "$fromdir/foo" || test_skipped "Your filesystem has ACLs disabled"
6421+setfacl -m u:0:5 "$fromdir/file1"
6422+setfacl -m u:0:5 "$fromdir/file2"
6423+
6424+$RSYNC -avvA "$fromdir/" "$todir/"
6425+
6426+cd "$fromdir"
6427+getfacl $files >"$scratchdir/acls.txt"
6428+
6429+cd "$todir"
6430+getfacl $files | diff $diffopt "$scratchdir/acls.txt" -
6431+
6432+# The script would have aborted on error, so getting here means we've won.
6433+exit 0
9a7eef96
WD
6434--- old/testsuite/default-acls.test
6435+++ new/testsuite/default-acls.test
475c4a36 6436@@ -0,0 +1,65 @@
90fa6d68
WD
6437+#! /bin/sh
6438+
475c4a36 6439+# This program is distributable under the terms of the GNU GPL (see
90fa6d68
WD
6440+# COPYING).
6441+
6442+# Test that rsync obeys default ACLs. -- Matt McCutchen
6443+
6444+. $srcdir/testsuite/rsync.fns
6445+
25d385b9 6446+$RSYNC --version | grep ", ACLs" >/dev/null || test_skipped "Rsync is configured without ACL support"
53c1073a 6447+case "$setfacl_nodef" in
475c4a36 6448+true) test_skipped "I don't know how to use your setfacl command" ;;
53c1073a
WD
6449+*-k*) opts='-dm u::7,g::5,o:5' ;;
6450+*) opts='-m d:u::7,d:g::5,d:o:5' ;;
6451+esac
6452+setfacl $opts "$scratchdir" || test_skipped "Your filesystem has ACLs disabled"
90fa6d68 6453+
90fa6d68 6454+# Call as: testit <dirname> <default-acl> <file-expected> <program-expected>
25d385b9 6455+testit() {
90fa6d68
WD
6456+ todir="$scratchdir/$1"
6457+ mkdir "$todir"
53c1073a
WD
6458+ $setfacl_nodef "$todir"
6459+ if [ "$2" ]; then
6460+ case "$setfacl_nodef" in
6461+ *-k*) opts="-dm $2" ;;
6462+ *) opts="-m `echo $2 | sed 's/\([ugom]:\)/d:\1/g'`"
6463+ esac
6464+ setfacl $opts "$todir"
6465+ fi
90fa6d68
WD
6466+ # Make sure we obey ACLs when creating a directory to hold multiple transferred files,
6467+ # even though the directory itself is outside the transfer
25d385b9 6468+ $RSYNC -rvv "$scratchdir/dir" "$scratchdir/file" "$scratchdir/program" "$todir/to/"
0251480d 6469+ check_perms "$todir/to" $4 "Target $1"
25d385b9 6470+ check_perms "$todir/to/dir" $4 "Target $1"
0251480d
WD
6471+ check_perms "$todir/to/file" $3 "Target $1"
6472+ check_perms "$todir/to/program" $4 "Target $1"
90fa6d68
WD
6473+ # Make sure get_local_name doesn't mess us up when transferring only one file
6474+ $RSYNC -rvv "$scratchdir/file" "$todir/to/anotherfile"
0251480d 6475+ check_perms "$todir/to/anotherfile" $3 "Target $1"
bb81ee98 6476+ # Make sure we obey default ACLs when not transferring a regular file
2578e2b6 6477+ $RSYNC -rvv "$scratchdir/dir/" "$todir/to/anotherdir/"
bb81ee98 6478+ check_perms "$todir/to/anotherdir" $4 "Target $1"
90fa6d68
WD
6479+}
6480+
25d385b9 6481+mkdir "$scratchdir/dir"
0251480d 6482+echo "File!" >"$scratchdir/file"
25d385b9
WD
6483+echo "#!/bin/sh" >"$scratchdir/program"
6484+chmod 777 "$scratchdir/dir"
0251480d
WD
6485+chmod 666 "$scratchdir/file"
6486+chmod 777 "$scratchdir/program"
6487+
90fa6d68
WD
6488+# Test some target directories
6489+umask 0077
53c1073a
WD
6490+testit da777 u::7,g::7,o:7 rw-rw-rw- rwxrwxrwx
6491+testit da775 u::7,g::7,o:5 rw-rw-r-- rwxrwxr-x
6492+testit da750 u::7,g::5,o:0 rw-r----- rwxr-x---
6493+testit da770mask u::7,u:0:7,g::0,m:7,o:0 rw-rw---- rwxrwx---
0251480d 6494+testit noda1 '' rw------- rwx------
90fa6d68 6495+umask 0000
0251480d 6496+testit noda2 '' rw-rw-rw- rwxrwxrwx
90fa6d68 6497+umask 0022
0251480d 6498+testit noda3 '' rw-r--r-- rwxr-xr-x
90fa6d68
WD
6499+
6500+# Hooray
6501+exit 0
0870c22a
WD
6502--- old/testsuite/devices.test
6503+++ new/testsuite/devices.test
6504@@ -42,14 +42,14 @@ touch -r "$fromdir/block" "$fromdir/bloc
6505 $RSYNC -ai "$fromdir/block" "$todir/block2" \
6506 | tee "$outfile"
6507 cat <<EOT >"$chkfile"
6508-cD+++++++ block
6509+cD+++++++++ block
6510 EOT
6511 diff $diffopt "$chkfile" "$outfile" || test_fail "test 1 failed"
6512
6513 $RSYNC -ai "$fromdir/block2" "$todir/block" \
6514 | tee "$outfile"
6515 cat <<EOT >"$chkfile"
6516-cD+++++++ block2
6517+cD+++++++++ block2
6518 EOT
6519 diff $diffopt "$chkfile" "$outfile" || test_fail "test 2 failed"
6520
6521@@ -58,7 +58,7 @@ sleep 1
6522 $RSYNC -Di "$fromdir/block3" "$todir/block" \
6523 | tee "$outfile"
6524 cat <<EOT >"$chkfile"
6525-cD..T.... block3
6526+cD..T...... block3
6527 EOT
6528 diff $diffopt "$chkfile" "$outfile" || test_fail "test 3 failed"
6529
6530@@ -66,15 +66,15 @@ $RSYNC -aiHvv "$fromdir/" "$todir/" \
6531 | tee "$outfile"
6532 filter_outfile
6533 cat <<EOT >"$chkfile"
6534-.d..t.... ./
6535-cD..t.... block
05031682 6536-cD block2
0870c22a
WD
6537-cD+++++++ block3
6538-hD+++++++ block2.5 => block3
6539-cD+++++++ char
6540-cD+++++++ char2
6541-cD+++++++ char3
6542-cS+++++++ fifo
6543+.d..t...... ./
6544+cD..t...... block
05031682 6545+cD block2
0870c22a
WD
6546+cD+++++++++ block3
6547+hD+++++++++ block2.5 => block3
6548+cD+++++++++ char
6549+cD+++++++++ char2
6550+cD+++++++++ char3
6551+cS+++++++++ fifo
6552 EOT
6553 if test ! -b "$fromdir/block2.5"; then
6554 sed -e '/block2\.5/d' \
05031682
WD
6555@@ -94,15 +94,15 @@ if test -b "$fromdir/block2.5"; then
6556 $RSYNC -aii --link-dest="$todir" "$fromdir/" "$chkdir/" \
6557 | tee "$outfile"
6558 cat <<EOT >"$chkfile"
6559-cd ./
6560-hD block
6561-hD block2
6562-hD block2.5
6563-hD block3
6564-hD char
6565-hD char2
6566-hD char3
6567-hS fifo
6568+cd ./
6569+hD block
6570+hD block2
6571+hD block2.5
6572+hD block3
6573+hD char
6574+hD char2
6575+hD char3
6576+hS fifo
6577 EOT
6578 diff $diffopt "$chkfile" "$outfile" || test_fail "test 4 failed"
6579 fi
0870c22a
WD
6580--- old/testsuite/itemize.test
6581+++ new/testsuite/itemize.test
d3074350 6582@@ -38,15 +38,15 @@ rm -f "$to2dir" "$to2dir.test"
0870c22a
WD
6583 $RSYNC -iplr "$fromdir/" "$todir/" \
6584 | tee "$outfile"
6585 cat <<EOT >"$chkfile"
2a787d74 6586-cd+++++++ ./
0870c22a
WD
6587-cd+++++++ bar/
6588-cd+++++++ bar/baz/
6589->f+++++++ bar/baz/rsync
6590-cd+++++++ foo/
6591->f+++++++ foo/config1
6592->f+++++++ foo/config2
6593->f+++++++ foo/extra
6594-cL+++++++ foo/sym -> ../bar/baz/rsync
2a787d74 6595+cd+++++++++ ./
0870c22a
WD
6596+cd+++++++++ bar/
6597+cd+++++++++ bar/baz/
6598+>f+++++++++ bar/baz/rsync
6599+cd+++++++++ foo/
6600+>f+++++++++ foo/config1
6601+>f+++++++++ foo/config2
6602+>f+++++++++ foo/extra
6603+cL+++++++++ foo/sym -> ../bar/baz/rsync
6604 EOT
6605 diff $diffopt "$chkfile" "$outfile" || test_fail "test 1 failed"
6606
d3074350 6607@@ -58,10 +58,10 @@ chmod 601 "$fromdir/foo/config2"
0870c22a
WD
6608 $RSYNC -iplrH "$fromdir/" "$todir/" \
6609 | tee "$outfile"
6610 cat <<EOT >"$chkfile"
6611->f..T.... bar/baz/rsync
6612->f..T.... foo/config1
6613->f.sTp... foo/config2
6614-hf..T.... foo/extra => foo/config1
6615+>f..T...... bar/baz/rsync
6616+>f..T...... foo/config1
6617+>f.sTp..... foo/config2
6618+hf..T...... foo/extra => foo/config1
6619 EOT
6620 diff $diffopt "$chkfile" "$outfile" || test_fail "test 2 failed"
6621
d3074350 6622@@ -78,11 +78,11 @@ chmod 777 "$todir/bar/baz/rsync"
0870c22a
WD
6623 $RSYNC -iplrtc "$fromdir/" "$todir/" \
6624 | tee "$outfile"
6625 cat <<EOT >"$chkfile"
6626-.f..tp... bar/baz/rsync
6627-.d..t.... foo/
6628-.f..t.... foo/config1
6629->fcstp... foo/config2
6630-cL..T.... foo/sym -> ../bar/baz/rsync
6631+.f..tp..... bar/baz/rsync
6632+.d..t...... foo/
6633+.f..t...... foo/config1
6634+>fcstp..... foo/config2
6635+cL..T...... foo/sym -> ../bar/baz/rsync
6636 EOT
6637 diff $diffopt "$chkfile" "$outfile" || test_fail "test 3 failed"
6638
d3074350 6639@@ -107,15 +107,15 @@ $RSYNC -ivvplrtH "$fromdir/" "$todir/" \
0870c22a
WD
6640 | tee "$outfile"
6641 filter_outfile
6642 cat <<EOT >"$chkfile"
6643-.d ./
6644-.d bar/
6645-.d bar/baz/
6646-.f...p... bar/baz/rsync
6647-.d foo/
6648-.f foo/config1
6649->f..t.... foo/config2
6650-hf foo/extra
6651-.L foo/sym -> ../bar/baz/rsync
6652+.d ./
6653+.d bar/
6654+.d bar/baz/
6655+.f...p..... bar/baz/rsync
6656+.d foo/
6657+.f foo/config1
6658+>f..t...... foo/config2
6659+hf foo/extra
6660+.L foo/sym -> ../bar/baz/rsync
6661 EOT
6662 diff $diffopt "$chkfile" "$outfile" || test_fail "test 5 failed"
6663
d3074350 6664@@ -134,8 +134,8 @@ touch "$todir/foo/config2"
0870c22a
WD
6665 $RSYNC -iplrtH "$fromdir/" "$todir/" \
6666 | tee "$outfile"
6667 cat <<EOT >"$chkfile"
6668-.f...p... foo/config1
6669->f..t.... foo/config2
6670+.f...p..... foo/config1
6671+>f..t...... foo/config2
6672 EOT
6673 diff $diffopt "$chkfile" "$outfile" || test_fail "test 7 failed"
6674
d3074350 6675@@ -143,15 +143,15 @@ $RSYNC -ivvplrtH --copy-dest=../to "$fro
0870c22a
WD
6676 | tee "$outfile"
6677 filter_outfile
6678 cat <<EOT >"$chkfile"
05031682
WD
6679-cd ./
6680-cd bar/
6681-cd bar/baz/
0870c22a 6682-cf bar/baz/rsync
05031682 6683-cd foo/
0870c22a
WD
6684-cf foo/config1
6685-cf foo/config2
6686-hf foo/extra => foo/config1
05031682
WD
6687-cL foo/sym -> ../bar/baz/rsync
6688+cd ./
6689+cd bar/
6690+cd bar/baz/
0870c22a 6691+cf bar/baz/rsync
05031682 6692+cd foo/
0870c22a
WD
6693+cf foo/config1
6694+cf foo/config2
6695+hf foo/extra => foo/config1
05031682 6696+cL foo/sym -> ../bar/baz/rsync
0870c22a
WD
6697 EOT
6698 diff $diffopt "$chkfile" "$outfile" || test_fail "test 8 failed"
6699
d3074350 6700@@ -159,7 +159,7 @@ rm -rf "$to2dir"
147c8f4c 6701 $RSYNC -iplrtH --copy-dest=../to "$fromdir/" "$to2dir/" \
0870c22a
WD
6702 | tee "$outfile"
6703 cat <<EOT >"$chkfile"
0870c22a 6704-hf foo/extra => foo/config1
0870c22a
WD
6705+hf foo/extra => foo/config1
6706 EOT
6707 diff $diffopt "$chkfile" "$outfile" || test_fail "test 9 failed"
6708
7b80cd0e 6709@@ -185,15 +185,15 @@ $RSYNC -ivvplrtH --link-dest="$todir" "$
0870c22a
WD
6710 | tee "$outfile"
6711 filter_outfile
6712 cat <<EOT >"$chkfile"
05031682
WD
6713-cd ./
6714-cd bar/
6715-cd bar/baz/
0870c22a 6716-hf bar/baz/rsync
05031682 6717-cd foo/
0870c22a
WD
6718-hf foo/config1
6719-hf foo/config2
6720-hf foo/extra => foo/config1
147c8f4c 6721-$L foo/sym -> ../bar/baz/rsync
05031682
WD
6722+cd ./
6723+cd bar/
6724+cd bar/baz/
0870c22a 6725+hf bar/baz/rsync
05031682 6726+cd foo/
0870c22a
WD
6727+hf foo/config1
6728+hf foo/config2
6729+hf foo/extra => foo/config1
147c8f4c 6730+$L foo/sym -> ../bar/baz/rsync
0870c22a
WD
6731 EOT
6732 diff $diffopt "$chkfile" "$outfile" || test_fail "test 11 failed"
6733
7b80cd0e
WD
6734@@ -233,15 +233,15 @@ $RSYNC -ivvplrtH --compare-dest="$todir"
6735 | tee "$outfile"
6736 filter_outfile
0870c22a 6737 cat <<EOT >"$chkfile"
05031682
WD
6738-cd ./
6739-cd bar/
6740-cd bar/baz/
0870c22a 6741-.f bar/baz/rsync
05031682 6742-cd foo/
0870c22a
WD
6743-.f foo/config1
6744-.f foo/config2
7b80cd0e 6745-.f foo/extra
0870c22a 6746-.L foo/sym -> ../bar/baz/rsync
05031682
WD
6747+cd ./
6748+cd bar/
6749+cd bar/baz/
0870c22a 6750+.f bar/baz/rsync
05031682 6751+cd foo/
0870c22a
WD
6752+.f foo/config1
6753+.f foo/config2
7b80cd0e 6754+.f foo/extra
0870c22a
WD
6755+.L foo/sym -> ../bar/baz/rsync
6756 EOT
2a787d74 6757 diff $diffopt "$chkfile" "$outfile" || test_fail "test 15 failed"
0870c22a 6758
9a7eef96
WD
6759--- old/uidlist.c
6760+++ new/uidlist.c
c1471566 6761@@ -35,6 +35,7 @@
fa26e11c
WD
6762 extern int verbose;
6763 extern int preserve_uid;
6764 extern int preserve_gid;
6765+extern int preserve_acls;
6766 extern int numeric_ids;
6767 extern int am_root;
6768
70891d26
WD
6769@@ -270,7 +271,7 @@ void send_uid_list(int f)
6770 {
6771 struct idlist *list;
fa26e11c
WD
6772
6773- if (preserve_uid) {
6774+ if (preserve_uid || preserve_acls) {
6775 int len;
6776 /* we send sequences of uid/byte-length/name */
6777 for (list = uidlist; list; list = list->next) {
70891d26 6778@@ -287,7 +288,7 @@ void send_uid_list(int f)
fa26e11c
WD
6779 write_int(f, 0);
6780 }
6781
6782- if (preserve_gid) {
6783+ if (preserve_gid || preserve_acls) {
6784 int len;
6785 for (list = gidlist; list; list = list->next) {
6786 if (!list->name)
70891d26 6787@@ -308,7 +309,7 @@ void recv_uid_list(int f, struct file_li
fa26e11c
WD
6788 int id, i;
6789 char *name;
6790
6791- if (preserve_uid && !numeric_ids) {
6792+ if ((preserve_uid || preserve_acls) && !numeric_ids) {
6793 /* read the uid list */
6794 while ((id = read_int(f)) != 0) {
6795 int len = read_byte(f);
70891d26 6796@@ -320,7 +321,7 @@ void recv_uid_list(int f, struct file_li
6849cd84 6797 }
fa26e11c
WD
6798 }
6799
fa26e11c
WD
6800- if (preserve_gid && !numeric_ids) {
6801+ if ((preserve_gid || preserve_acls) && !numeric_ids) {
6802 /* read the gid list */
6803 while ((id = read_int(f)) != 0) {
6804 int len = read_byte(f);
70891d26 6805@@ -332,6 +333,16 @@ void recv_uid_list(int f, struct file_li
fa26e11c
WD
6806 }
6807 }
125d7fca 6808
4edb99c8 6809+#ifdef SUPPORT_ACLS
fa26e11c 6810+ if (preserve_acls && !numeric_ids) {
c52977bc
WD
6811+ id_t *id;
6812+ while ((id = next_acl_uid(flist)) != NULL)
6813+ *id = match_uid(*id);
6814+ while ((id = next_acl_gid(flist)) != NULL)
6815+ *id = match_gid(*id);
fa26e11c 6816+ }
162234a7 6817+#endif
125d7fca 6818+
90fa6d68 6819 /* Now convert all the uids/gids from sender values to our values. */
125d7fca 6820 if (am_root && preserve_uid && !numeric_ids) {
90fa6d68 6821 for (i = 0; i < flist->count; i++)
6250eb3e
WD
6822--- old/util.c
6823+++ new/util.c
5e3c6c93 6824@@ -1467,3 +1467,31 @@ int bitbag_next_bit(struct bitbag *bb, i
6250eb3e
WD
6825
6826 return -1;
6827 }
6828+
6829+void *expand_item_list(item_list *lp, size_t item_size,
645e162c 6830+ const char *desc, int incr)
6250eb3e
WD
6831+{
6832+ /* First time through, 0 <= 0, so list is expanded. */
6833+ if (lp->malloced <= lp->count) {
6834+ void *new_ptr;
6835+ size_t new_size = lp->malloced;
645e162c
WD
6836+ if (incr < 0)
6837+ new_size -= incr; /* increase slowly */
98ccc74a 6838+ else if (new_size < (size_t)incr)
645e162c
WD
6839+ new_size += incr;
6840+ else
6841+ new_size *= 2;
6250eb3e
WD
6842+ new_ptr = realloc_array(lp->items, char, new_size * item_size);
6843+ if (verbose >= 4) {
6844+ rprintf(FINFO, "[%s] expand %s to %.0f bytes, did%s move\n",
6845+ who_am_i(), desc, (double)new_size * item_size,
6846+ new_ptr == lp->items ? " not" : "");
6847+ }
6848+ if (!new_ptr)
6849+ out_of_memory("expand_item_list");
6850+
6851+ lp->items = new_ptr;
6852+ lp->malloced = new_size;
6853+ }
6854+ return (char*)lp->items + (lp->count++ * item_size);
6855+}