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