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