- Made the "types" array a single static instead of a separate
[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
f05cc718
WD
7The program currently complains when the --acls (-A) option is used to copy
8from a disk that doesn't support ACLs. This should be changed to silently
9notice that no ACLs are available to copy. Of course, trying to write out
10ACLs to a non-ACL-supporting disk should complain.
fa26e11c 11
9a7eef96
WD
12--- old/Makefile.in
13+++ new/Makefile.in
4bf6f8c7 14@@ -25,15 +25,15 @@ VERSION=@VERSION@
fa26e11c
WD
15 .SUFFIXES:
16 .SUFFIXES: .c .o
17
18-HEADERS=byteorder.h config.h errcode.h proto.h rsync.h lib/pool_alloc.h
19+HEADERS=byteorder.h config.h errcode.h proto.h rsync.h smb_acls.h lib/pool_alloc.h
20 LIBOBJ=lib/wildmatch.o lib/compat.o lib/snprintf.o lib/mdfour.o \
0f6733d8
WD
21- lib/permstring.o lib/pool_alloc.o @LIBOBJS@
22+ lib/permstring.o lib/pool_alloc.o lib/sysacls.o @LIBOBJS@
4bf6f8c7
WD
23 ZLIBOBJ=zlib/deflate.o zlib/inffast.o zlib/inflate.o zlib/inftrees.o \
24 zlib/trees.o zlib/zutil.o zlib/adler32.o zlib/compress.o zlib/crc32.o
fa26e11c
WD
25 OBJS1=rsync.o generator.o receiver.o cleanup.o sender.o exclude.o util.o \
26 main.o checksum.o match.o syscall.o log.o backup.o
27 OBJS2=options.o flist.o io.o compat.o hlink.o token.o uidlist.o socket.o \
610969d1
WD
28- fileio.o batch.o clientname.o chmod.o
29+ fileio.o batch.o clientname.o chmod.o acls.o
fa26e11c
WD
30 OBJS3=progress.o pipe.o
31 DAEMON_OBJ = params.o loadparm.o clientserver.o access.o connection.o authenticate.o
32 popt_OBJS=popt/findme.o popt/popt.o popt/poptconfig.o \
9a7eef96
WD
33--- old/acls.c
34+++ new/acls.c
36aa3171 35@@ -0,0 +1,1230 @@
fa26e11c
WD
36+/* -*- c-file-style: "linux" -*-
37+ Copyright (C) Andrew Tridgell 1996
38+ Copyright (C) Paul Mackerras 1996
39+
40+ This program is free software; you can redistribute it and/or modify
41+ it under the terms of the GNU General Public License as published by
42+ the Free Software Foundation; either version 2 of the License, or
43+ (at your option) any later version.
44+
45+ This program is distributed in the hope that it will be useful,
46+ but WITHOUT ANY WARRANTY; without even the implied warranty of
47+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
48+ GNU General Public License for more details.
49+
50+ You should have received a copy of the GNU General Public License
51+ along with this program; if not, write to the Free Software
52+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
53+*/
54+
55+/* handle passing ACLs between systems */
56+
57+#include "rsync.h"
0f6733d8 58+#include "lib/sysacls.h"
fa26e11c 59+
4df546eb 60+#ifdef SUPPORT_ACLS
fa26e11c
WD
61+
62+extern int preserve_acls;
63+extern int am_root;
64+extern int dry_run;
90fa6d68 65+extern int orig_umask;
fa26e11c
WD
66+
67+typedef struct {
68+ id_t id;
69+ uchar access;
70+ SMB_ACL_TAG_T tag_type;
71+} rsync_ace;
72+
73+typedef struct {
74+ size_t count;
75+ size_t malloced;
76+ rsync_ace *races;
77+} rsync_acl;
78+
79+static const rsync_acl rsync_acl_initializer = { 0, 0, NULL };
36aa3171 80+static SMB_ACL_TYPE_T types[] = {SMB_ACL_TYPE_ACCESS, SMB_ACL_TYPE_DEFAULT};
fa26e11c
WD
81+
82+static void expand_rsync_acl(rsync_acl *racl)
83+{
4edb99c8
WD
84+ /* First time through, 0 <= 0, so list is expanded.
85+ * (Diabolical, rsync guys!) */
fa26e11c 86+ if (racl->malloced <= racl->count) {
0f6733d8
WD
87+ rsync_ace *new_ptr;
88+ size_t new_size = racl->malloced + 10;
89+ new_ptr = realloc_array(racl->races, rsync_ace, new_size);
fa26e11c
WD
90+ if (verbose >= 4) {
91+ rprintf(FINFO, "expand rsync_acl to %.0f bytes, did%s move\n",
0f6733d8 92+ (double) new_size * sizeof racl->races[0],
fa26e11c
WD
93+ racl->races ? "" : " not");
94+ }
95+
0f6733d8
WD
96+ racl->races = new_ptr;
97+ racl->malloced = new_size;
fa26e11c
WD
98+
99+ if (!racl->races)
100+ out_of_memory("expand_rsync_acl");
101+ }
102+}
103+
104+static void rsync_acl_free(rsync_acl *racl)
105+{
106+ free(racl->races);
107+ racl->races = NULL;
108+ racl->count = 0;
109+ racl->malloced = 0;
110+}
111+
112+static int rsync_ace_sorter(const void *r1, const void *r2)
113+{
114+ rsync_ace *race1 = (rsync_ace *)r1;
115+ SMB_ACL_TAG_T rtag1 = race1->tag_type;
116+ id_t rid1 = race1->id;
117+ rsync_ace *race2 = (rsync_ace *)r2;
118+ SMB_ACL_TAG_T rtag2 = race2->tag_type;
119+ id_t rid2 = race2->id;
120+ /* start at the extrema */
121+ if (rtag1 == SMB_ACL_USER_OBJ || rtag2 == SMB_ACL_MASK)
122+ return -1;
123+ if (rtag2 == SMB_ACL_USER_OBJ || rtag1 == SMB_ACL_MASK)
124+ return 1;
125+ /* work inwards */
126+ if (rtag1 == SMB_ACL_OTHER)
127+ return 1;
128+ if (rtag2 == SMB_ACL_OTHER)
129+ return -1;
130+ /* only SMB_ACL_USERs and SMB_ACL_GROUP*s left */
131+ if (rtag1 == SMB_ACL_USER) {
132+ switch (rtag2) {
133+ case SMB_ACL_GROUP:
134+ case SMB_ACL_GROUP_OBJ:
135+ case SMB_ACL_OTHER:
136+ return -1;
137+ }
138+ /* both USER */
139+ return rid1 == rid2 ? 0 : rid1 < rid2 ? -1 : 1;
140+ }
141+ if (rtag2 == SMB_ACL_USER)
142+ return 1;
143+ /* only SMB_ACL_GROUP*s to worry about; kick out GROUP_OBJs first */
144+ if (rtag1 == SMB_ACL_GROUP_OBJ)
145+ return -1;
146+ if (rtag2 == SMB_ACL_GROUP_OBJ)
147+ return 1;
148+ /* only SMB_ACL_GROUPs left */
149+ return rid1 == rid2 ? 0 : rid1 < rid2 ? -1 : 1;
150+}
151+
152+static void sort_rsync_acl(rsync_acl *racl)
153+{
154+ if (!racl->count)
155+ return;
156+ qsort((void **)racl->races, racl->count, sizeof racl->races[0],
157+ &rsync_ace_sorter);
158+}
159+
160+static BOOL unpack_smb_acl(rsync_acl *racl, SMB_ACL_T sacl)
161+{
162+ SMB_ACL_ENTRY_T entry;
163+ int rc;
164+ const char *errfun;
165+ *racl = rsync_acl_initializer;
166+ errfun = "sys_acl_get_entry";
167+ for (rc = sys_acl_get_entry(sacl, SMB_ACL_FIRST_ENTRY, &entry);
168+ rc == 1;
169+ rc = sys_acl_get_entry(sacl, SMB_ACL_NEXT_ENTRY, &entry)) {
170+ SMB_ACL_PERMSET_T permset;
171+ void *qualifier;
172+ rsync_ace *race;
173+ expand_rsync_acl(racl);
174+ race = &racl->races[racl->count++];
175+ if ((rc = sys_acl_get_tag_type(entry, &race->tag_type))) {
176+ errfun = "sys_acl_get_tag_type";
177+ break;
178+ }
179+ if ((rc = sys_acl_get_permset(entry, &permset))) {
180+ errfun = "sys_acl_get_tag_type";
181+ break;
182+ }
183+ race->access = (sys_acl_get_perm(permset, SMB_ACL_READ) ? 4 : 0)
184+ | (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? 2 : 0)
185+ | (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? 1 : 0);
186+ switch (race->tag_type) {
187+ case SMB_ACL_USER:
188+ case SMB_ACL_GROUP:
189+ break;
190+ default:
191+ continue;
192+ }
193+ if (!(qualifier = sys_acl_get_qualifier(entry))) {
194+ errfun = "sys_acl_get_tag_type";
195+ rc = EINVAL;
196+ break;
197+ }
198+ race->id = *((id_t *)qualifier);
199+ sys_acl_free_qualifier(qualifier, race->tag_type);
200+ }
201+ if (rc) {
202+ rprintf(FERROR, "unpack_smb_acl: %s(): %s\n",
203+ errfun, strerror(errno));
204+ rsync_acl_free(racl);
205+ return False;
206+ }
207+ sort_rsync_acl(racl);
208+ return True;
209+}
210+
211+static BOOL rsync_acls_equal(const rsync_acl *racl1, const rsync_acl *racl2)
212+{
213+ rsync_ace *race1, *race2;
214+ size_t count = racl1->count;
215+ if (count != racl2->count)
216+ return False;
217+ race1 = racl1->races;
218+ race2 = racl2->races;
219+ for (; count--; race1++, race2++) {
220+ if (race1->tag_type != race2->tag_type
221+ || race1->access != race2->access
222+ || ((race1->tag_type == SMB_ACL_USER
223+ || race1->tag_type == SMB_ACL_GROUP)
224+ && race1->id != race2->id))
225+ return False;
226+ }
227+ return True;
228+}
229+
230+typedef struct {
231+ size_t count;
232+ size_t malloced;
233+ rsync_acl *racls;
234+} rsync_acl_list;
235+
236+static rsync_acl_list _rsync_acl_lists[] = {
237+ { 0, 0, NULL }, /* SMB_ACL_TYPE_ACCESS */
238+ { 0, 0, NULL } /* SMB_ACL_TYPE_DEFAULT */
239+};
240+
241+static inline rsync_acl_list *rsync_acl_lists(SMB_ACL_TYPE_T type)
242+{
243+ return type == SMB_ACL_TYPE_ACCESS ? &_rsync_acl_lists[0]
244+ : &_rsync_acl_lists[1];
245+}
246+
247+static void expand_rsync_acl_list(rsync_acl_list *racl_list)
248+{
4edb99c8
WD
249+ /* First time through, 0 <= 0, so list is expanded.
250+ * (Diabolical, rsync guys!) */
fa26e11c 251+ if (racl_list->malloced <= racl_list->count) {
0f6733d8 252+ rsync_acl *new_ptr;
fa26e11c
WD
253+ size_t new_size;
254+ if (racl_list->malloced < 1000)
0f6733d8 255+ new_size = racl_list->malloced + 1000;
fa26e11c 256+ else
0f6733d8
WD
257+ new_size = racl_list->malloced * 2;
258+ new_ptr = realloc_array(racl_list->racls, rsync_acl, new_size);
fa26e11c
WD
259+ if (verbose >= 3) {
260+ rprintf(FINFO, "expand_rsync_acl_list to %.0f bytes, did%s move\n",
0f6733d8 261+ (double) new_size * sizeof racl_list->racls[0],
fa26e11c
WD
262+ racl_list->racls ? "" : " not");
263+ }
264+
0f6733d8
WD
265+ racl_list->racls = new_ptr;
266+ racl_list->malloced = new_size;
fa26e11c
WD
267+
268+ if (!racl_list->racls)
269+ out_of_memory("expand_rsync_acl_list");
270+ }
271+}
272+
273+#if 0
274+static void free_rsync_acl_list(rsync_acl_list *racl_list)
275+{
4edb99c8
WD
276+ /* Run this in reverse, so references are freed before referents,
277+ * although not currently necessary. */
fa26e11c
WD
278+ while (racl_list->count--) {
279+ rsync_acl *racl = &racl_list->racls[racl_list->count];
280+ if (racl)
281+ rsync_acl_free(racl);
282+ }
283+ free(racl_list->racls);
284+ racl_list->racls = NULL;
285+ racl_list->malloced = 0;
286+}
287+#endif
288+
289+static int find_matching_rsync_acl(SMB_ACL_TYPE_T type,
290+ const rsync_acl_list *racl_list,
291+ const rsync_acl *racl)
292+{
293+ static int access_match = -1, default_match = -1;
294+ int *match = (type == SMB_ACL_TYPE_ACCESS) ?
295+ &access_match : &default_match;
296+ size_t count = racl_list->count;
4edb99c8 297+ /* If this is the first time through or we didn't match the last
fa26e11c 298+ * time, then start at the end of the list, which should be the
4edb99c8 299+ * best place to start hunting. */
fa26e11c
WD
300+ if (*match == -1)
301+ *match = racl_list->count - 1;
302+ while (count--) {
303+ if (rsync_acls_equal(&racl_list->racls[*match], racl))
304+ return *match;
305+ if (!(*match)--)
306+ *match = racl_list->count - 1;
307+ }
308+ *match = -1;
309+ return *match;
310+}
311+
4edb99c8 312+/* The general strategy with the tag_type <-> character mapping is that
fa26e11c 313+ * lowercase implies that no qualifier follows, where uppercase does.
4edb99c8 314+ * A similar idiom for the acl type (access or default) itself, but
fa26e11c
WD
315+ * lowercase in this instance means there's no ACL following, so the
316+ * ACL is a repeat, so the receiver should reuse the last of the same
4edb99c8 317+ * type ACL. */
fa26e11c
WD
318+
319+static void send_rsync_acl(int f, const rsync_acl *racl)
320+{
321+ rsync_ace *race;
322+ size_t count = racl->count;
323+ write_int(f, count);
324+ for (race = racl->races; count--; race++) {
325+ char ch;
326+ switch (race->tag_type) {
327+ case SMB_ACL_USER_OBJ:
328+ ch = 'u';
329+ break;
330+ case SMB_ACL_USER:
331+ ch = 'U';
332+ break;
333+ case SMB_ACL_GROUP_OBJ:
334+ ch = 'g';
335+ break;
336+ case SMB_ACL_GROUP:
337+ ch = 'G';
338+ break;
339+ case SMB_ACL_OTHER:
340+ ch = 'o';
341+ break;
342+ case SMB_ACL_MASK:
343+ ch = 'm';
344+ break;
345+ default:
346+ rprintf(FERROR,
e839d833 347+ "send_rsync_acl: unknown tag_type (%02x) on ACE; disregarding\n",
fa26e11c
WD
348+ race->tag_type);
349+ continue;
350+ }
351+ write_byte(f, ch);
352+ write_byte(f, race->access);
353+ if (isupper((int)ch)) {
354+ write_int(f, race->id);
4edb99c8 355+ /* FIXME: sorta wasteful: we should maybe buffer as
fa26e11c 356+ * many ids as max(ACL_USER + ACL_GROUP) objects to
4edb99c8 357+ * keep from making so many calls. */
fa26e11c
WD
358+ if (ch == 'U')
359+ add_uid(race->id);
360+ else
361+ add_gid(race->id);
362+ }
363+ }
364+}
365+
366+static rsync_acl _curr_rsync_acls[2];
367+
368+
369+static const char *str_acl_type(SMB_ACL_TYPE_T type)
370+{
371+ return type == SMB_ACL_TYPE_ACCESS ? "SMB_ACL_TYPE_ACCESS" :
372+ type == SMB_ACL_TYPE_DEFAULT ? "SMB_ACL_TYPE_DEFAULT" :
373+ "unknown SMB_ACL_TYPE_T";
374+}
375+
b8fc785b
WD
376+/*
377+ * Overwrite racl with a new three-entry ACL from the given permissions.
378+ */
379+static void perms_to_acl(int perms, rsync_acl *racl)
380+{
381+ racl->count = 0;
382+ expand_rsync_acl(racl);
383+ racl->races[racl->count].tag_type = SMB_ACL_USER_OBJ;
384+ racl->races[racl->count++].access = (perms >> 6) & 7;
385+ expand_rsync_acl(racl);
386+ racl->races[racl->count].tag_type = SMB_ACL_GROUP_OBJ;
387+ racl->races[racl->count++].access = (perms >> 3) & 7;
388+ expand_rsync_acl(racl);
389+ racl->races[racl->count].tag_type = SMB_ACL_OTHER;
390+ racl->races[racl->count++].access = (perms >> 0) & 7;
391+}
392+
4edb99c8
WD
393+/* Generate the ACL(s) for this flist entry;
394+ * ACL(s) are either sent or cleaned-up by send_acl() below. */
fa26e11c 395+
ee12ff0e 396+int make_acl(const struct file_struct *file, const char *fname)
fa26e11c 397+{
36aa3171 398+ SMB_ACL_TYPE_T *type;
fa26e11c 399+ rsync_acl *curr_racl;
36aa3171 400+
fa26e11c 401+ if (!preserve_acls || S_ISLNK(file->mode))
05b88206 402+ return 1;
fa26e11c
WD
403+ for (type = &types[0], curr_racl = &_curr_rsync_acls[0];
404+ type < &types[0] + sizeof types / sizeof types[0]
405+ && (*type == SMB_ACL_TYPE_ACCESS || S_ISDIR(file->mode));
406+ type++, curr_racl++) {
407+ SMB_ACL_T sacl;
408+ BOOL ok;
409+ *curr_racl = rsync_acl_initializer;
b8fc785b
WD
410+ if ((sacl = sys_acl_get_file(fname, *type)) != 0) {
411+ ok = unpack_smb_acl(curr_racl, sacl);
412+ sys_acl_free_acl(sacl);
413+ if (!ok)
414+ return -1;
415+ } else if (errno == ENOTSUP) {
416+ /* ACLs are not supported. Invent an access ACL from
417+ * permissions; let the default ACL default to empty. */
418+ if (*type == SMB_ACL_TYPE_ACCESS)
419+ perms_to_acl(file->mode & ACCESSPERMS, curr_racl);
420+ } else {
c171f097 421+ rprintf(FERROR, "send_acl: sys_acl_get_file(%s, %s): %s\n",
fa26e11c 422+ fname, str_acl_type(*type), strerror(errno));
05b88206 423+ return -1;
fa26e11c 424+ }
fa26e11c 425+ }
05b88206 426+ return 0;
fa26e11c
WD
427+}
428+
4edb99c8
WD
429+/* Send the make_acl()-generated ACLs for this flist entry,
430+ * or clean up after an flist entry that's not being sent (f == -1). */
fa26e11c
WD
431+
432+void send_acl(const struct file_struct *file, int f)
433+{
36aa3171 434+ SMB_ACL_TYPE_T *type;
fa26e11c 435+ rsync_acl *curr_racl;
36aa3171 436+
fa26e11c
WD
437+ if (!preserve_acls || S_ISLNK(file->mode))
438+ return;
439+ for (type = &types[0], curr_racl = &_curr_rsync_acls[0];
440+ type < &types[0] + sizeof types / sizeof types[0]
441+ && (*type == SMB_ACL_TYPE_ACCESS || S_ISDIR(file->mode));
442+ type++, curr_racl++) {
443+ int index;
444+ rsync_acl_list *racl_list = rsync_acl_lists(*type);
445+ if (f == -1) {
446+ rsync_acl_free(curr_racl);
447+ continue;
448+ }
449+ if ((index = find_matching_rsync_acl(*type, racl_list, curr_racl))
450+ != -1) {
451+ write_byte(f, *type == SMB_ACL_TYPE_ACCESS ? 'a' : 'd');
452+ write_int(f, index);
453+ rsync_acl_free(curr_racl);
454+ } else {
455+ write_byte(f, *type == SMB_ACL_TYPE_ACCESS ? 'A' : 'D');
456+ send_rsync_acl(f, curr_racl);
457+ expand_rsync_acl_list(racl_list);
458+ racl_list->racls[racl_list->count++] = *curr_racl;
459+ }
460+ }
461+}
462+
4edb99c8 463+/* The below stuff is only used by the receiver: */
fa26e11c
WD
464+
465+/* structure to hold index to rsync_acl_list member corresponding to
466+ * flist->files[i] */
467+
468+typedef struct {
469+ const struct file_struct *file;
470+ int aclidx;
471+} file_acl_index;
472+
473+typedef struct {
474+ size_t count;
475+ size_t malloced;
476+ file_acl_index *fileaclidxs;
477+} file_acl_index_list;
478+
479+static file_acl_index_list _file_acl_index_lists[] = {
480+ {0, 0, NULL },/* SMB_ACL_TYPE_ACCESS */
481+ {0, 0, NULL } /* SMB_ACL_TYPE_DEFAULT */
482+};
483+
484+static inline file_acl_index_list *file_acl_index_lists(SMB_ACL_TYPE_T type)
485+{
486+ return type == SMB_ACL_TYPE_ACCESS ?
487+ &_file_acl_index_lists[0] : &_file_acl_index_lists[1];
488+}
489+
490+static void expand_file_acl_index_list(file_acl_index_list *fileaclidx_list)
491+{
4edb99c8
WD
492+ /* First time through, 0 <= 0, so list is expanded.
493+ * (Diabolical, rsync guys!) */
fa26e11c 494+ if (fileaclidx_list->malloced <= fileaclidx_list->count) {
0f6733d8 495+ file_acl_index *new_ptr;
fa26e11c
WD
496+ size_t new_size;
497+ if (fileaclidx_list->malloced < 1000)
0f6733d8 498+ new_size = fileaclidx_list->malloced + 1000;
fa26e11c 499+ else
0f6733d8
WD
500+ new_size = fileaclidx_list->malloced * 2;
501+ new_ptr = realloc_array(fileaclidx_list->fileaclidxs, file_acl_index, new_size);
fa26e11c
WD
502+ if (verbose >= 3) {
503+ rprintf(FINFO, "expand_file_acl_index_list to %.0f bytes, did%s move\n",
0f6733d8 504+ (double) new_size * sizeof fileaclidx_list->fileaclidxs[0],
fa26e11c
WD
505+ fileaclidx_list->fileaclidxs ? "" : " not");
506+ }
507+
0f6733d8
WD
508+ fileaclidx_list->fileaclidxs = new_ptr;
509+ fileaclidx_list->malloced = new_size;
fa26e11c
WD
510+
511+ if (!fileaclidx_list->fileaclidxs)
512+ out_of_memory("expand_file_acl_index_list");
513+ }
514+}
515+
516+#if 0
517+static void free_file_acl_index_list(file_acl_index_list *fileaclidx_list)
518+{
519+ free(fileaclidx_list->fileaclidxs);
520+ fileaclidx_list->fileaclidxs = NULL;
521+ fileaclidx_list->malloced = 0;
522+}
523+#endif
524+
525+/* lists to hold the SMB_ACL_Ts corresponding to the rsync_acl_list entries */
526+
527+typedef struct {
528+ size_t count;
529+ size_t malloced;
530+ SMB_ACL_T *sacls;
531+} smb_acl_list;
532+
533+static smb_acl_list _smb_acl_lists[] = {
534+ { 0, 0, NULL }, /* SMB_ACL_TYPE_ACCESS */
535+ { 0, 0, NULL } /* SMB_ACL_TYPE_DEFAULT */
536+};
537+
538+static inline smb_acl_list *smb_acl_lists(SMB_ACL_TYPE_T type)
539+{
540+ return type == SMB_ACL_TYPE_ACCESS ? &_smb_acl_lists[0] :
541+ &_smb_acl_lists[1];
542+}
543+
544+static void expand_smb_acl_list(smb_acl_list *sacl_list)
545+{
4edb99c8
WD
546+ /* First time through, 0 <= 0, so list is expanded.
547+ * (Diabolical, rsync guys!) */
fa26e11c 548+ if (sacl_list->malloced <= sacl_list->count) {
0f6733d8 549+ SMB_ACL_T *new_ptr;
fa26e11c
WD
550+ size_t new_size;
551+ if (sacl_list->malloced < 1000)
0f6733d8 552+ new_size = sacl_list->malloced + 1000;
fa26e11c 553+ else
0f6733d8
WD
554+ new_size = sacl_list->malloced * 2;
555+ new_ptr = realloc_array(sacl_list->sacls, SMB_ACL_T, new_size);
fa26e11c
WD
556+ if (verbose >= 3) {
557+ rprintf(FINFO, "expand_smb_acl_list to %.0f bytes, did%s move\n",
0f6733d8 558+ (double) new_size * sizeof sacl_list->sacls[0],
fa26e11c
WD
559+ sacl_list->sacls ? "" : " not");
560+ }
561+
0f6733d8
WD
562+ sacl_list->sacls = new_ptr;
563+ sacl_list->malloced = new_size;
fa26e11c
WD
564+
565+ if (!sacl_list->sacls)
566+ out_of_memory("expand_smb_acl_list");
567+ }
568+}
569+
570+#if 0
571+static void free_smb_acl_list(SMB_ACL_TYPE_T type)
572+{
573+ smb_acl_list *sacl_list = smb_acl_lists(type);
574+ SMB_ACL_T *sacl = sacl_list->sacls;
575+ while (sacl_list->count--) {
576+ if (*sacl)
577+ sys_acl_free_acl(*sacl++);
578+ }
579+ free(sacl_list->sacls);
580+ sacl_list->sacls = NULL;
581+ sacl_list->malloced = 0;
582+}
583+#endif
584+
585+/* build an SMB_ACL_T corresponding to an rsync_acl */
586+static BOOL pack_smb_acl(SMB_ACL_T *smb_acl, const rsync_acl *racl)
587+{
588+ size_t count = racl->count;
589+ rsync_ace *race = racl->races;
590+ const char *errfun = NULL;
591+ *smb_acl = sys_acl_init(count);
592+ if (!*smb_acl) {
593+ rprintf(FERROR, "pack_smb_acl: sys_acl_int(): %s\n",
594+ strerror(errno));
595+ return False;
596+ }
597+ for (; count--; race++) {
598+ SMB_ACL_ENTRY_T entry;
599+ SMB_ACL_PERMSET_T permset;
600+ if (sys_acl_create_entry(smb_acl, &entry)) {
601+ errfun = "sys_acl_create)";
602+ break;
603+ }
604+ if (sys_acl_set_tag_type(entry, race->tag_type)) {
605+ errfun = "sys_acl_set_tag";
606+ break;
607+ }
608+ if (race->tag_type == SMB_ACL_USER ||
609+ race->tag_type == SMB_ACL_GROUP)
610+ if (sys_acl_set_qualifier(entry, (void*)&race->id)) {
611+ errfun = "sys_acl_set_qualfier";
612+ break;
613+ }
614+ if (sys_acl_get_permset(entry, &permset)) {
615+ errfun = "sys_acl_get_permset";
616+ break;
617+ }
618+ if (sys_acl_clear_perms(permset)) {
619+ errfun = "sys_acl_clear_perms";
620+ break;
621+ }
622+ if (race->access & 4)
623+ if (sys_acl_add_perm(permset, SMB_ACL_READ)) {
624+ errfun = "sys_acl_add_perm";
625+ break;
626+ }
627+ if (race->access & 2)
628+ if (sys_acl_add_perm(permset, SMB_ACL_WRITE)) {
629+ errfun = "sys_acl_add_perm";
630+ break;
631+ }
632+ if (race->access & 1)
633+ if (sys_acl_add_perm(permset, SMB_ACL_EXECUTE)) {
634+ errfun = "sys_acl_add_perm";
635+ break;
636+ }
637+ if (sys_acl_set_permset(entry, permset)) {
638+ errfun = "sys_acl_set_permset";
639+ break;
640+ }
641+ }
642+ if (errfun) {
643+ sys_acl_free_acl(*smb_acl);
644+ rprintf(FERROR, "pack_smb_acl %s(): %s\n", errfun,
645+ strerror(errno));
646+ return False;
647+ }
648+ return True;
649+}
650+
651+static void receive_rsync_acl(rsync_acl *racl, int f)
652+{
653+#if ACLS_NEED_MASK
654+ uchar required_mask_perm = 0;
fa26e11c 655+#endif
1ce58df1 656+ BOOL saw_mask = False;
fa26e11c
WD
657+ BOOL saw_user_obj = False, saw_group_obj = False,
658+ saw_other = False;
659+ size_t count = read_int(f);
660+ rsync_ace *race;
661+ if (!count)
662+ return;
663+ while (count--) {
664+ uchar tag = read_byte(f);
665+ expand_rsync_acl(racl);
666+ race = &racl->races[racl->count++];
667+ switch (tag) {
668+ case 'u':
669+ race->tag_type = SMB_ACL_USER_OBJ;
670+ saw_user_obj = True;
671+ break;
672+ case 'U':
673+ race->tag_type = SMB_ACL_USER;
674+ break;
675+ case 'g':
676+ race->tag_type = SMB_ACL_GROUP_OBJ;
677+ saw_group_obj = True;
678+ break;
679+ case 'G':
680+ race->tag_type = SMB_ACL_GROUP;
681+ break;
682+ case 'o':
683+ race->tag_type = SMB_ACL_OTHER;
684+ saw_other = True;
685+ break;
686+ case 'm':
687+ race->tag_type = SMB_ACL_MASK;
fa26e11c 688+ saw_mask = True;
fa26e11c
WD
689+ break;
690+ default:
691+ rprintf(FERROR, "receive_rsync_acl: unknown tag %c\n",
692+ tag);
693+ exit_cleanup(RERR_STREAMIO);
694+ }
695+ race->access = read_byte(f);
696+ if (race->access & ~ (4 | 2 | 1)) {
697+ rprintf(FERROR, "receive_rsync_acl: bogus permset %o\n",
698+ race->access);
699+ exit_cleanup(RERR_STREAMIO);
700+ }
701+ if (race->tag_type == SMB_ACL_USER ||
702+ race->tag_type == SMB_ACL_GROUP) {
703+ race->id = read_int(f);
704+#if ACLS_NEED_MASK
705+ required_mask_perm |= race->access;
706+#endif
707+ }
708+#if ACLS_NEED_MASK
709+ else if (race->tag_type == SMB_ACL_GROUP_OBJ)
710+ required_mask_perm |= race->access;
711+#endif
712+
713+ }
714+ if (!saw_user_obj) {
715+ expand_rsync_acl(racl);
716+ race = &racl->races[racl->count++];
717+ race->tag_type = SMB_ACL_USER_OBJ;
718+ race->access = 7;
719+ }
720+ if (!saw_group_obj) {
721+ expand_rsync_acl(racl);
722+ race = &racl->races[racl->count++];
723+ race->tag_type = SMB_ACL_GROUP_OBJ;
724+ race->access = 0;
725+ }
726+ if (!saw_other) {
727+ expand_rsync_acl(racl);
728+ race = &racl->races[racl->count++];
729+ race->tag_type = SMB_ACL_OTHER;
730+ race->access = 0;
731+ }
732+#if ACLS_NEED_MASK
733+ if (!saw_mask) {
734+ expand_rsync_acl(racl);
735+ race = &racl->races[racl->count++];
736+ race->tag_type = SMB_ACL_MASK;
737+ race->access = required_mask_perm;
738+ }
1ce58df1
WD
739+#else
740+ /* If we, a system without ACLS_NEED_MASK, received data from a
741+ * system that has masks, throw away the extraneous CLASS_OBJs. */
742+ if (saw_mask && racl->count == 4) {
743+ rsync_ace *group_obj_race = NULL, *mask_race = NULL;
744+ rsync_ace *p;
745+ size_t i;
746+ for (i = 0, p = racl->races; i < racl->count; i++, p++) {
747+ if (p->tag_type == SMB_ACL_MASK)
748+ mask_race = p;
749+ else if (p->tag_type == SMB_ACL_GROUP_OBJ)
750+ group_obj_race = p;
751+ }
752+ if (mask_race == NULL || group_obj_race == NULL) {
753+ rprintf(FERROR, "receive_rsync_acl: have four ACES "
754+ "and one's ACL_MASK but missing "
755+ "either it or ACL_GROUP_OBJ, "
756+ "when pruning ACL\n");
757+ } else {
758+ /* mask off group perms with it first */
759+ group_obj_race->access &= mask_race->access;
760+ /* dump mask_race; re-slot any followers-on */
761+ racl->count--;
762+ if (mask_race != &racl->races[racl->count]) {
763+ *mask_race = racl->races[racl->count];
764+ saw_user_obj = False; /* force re-sort */
765+ }
766+ }
767+ }
fa26e11c
WD
768+#endif
769+#if ACLS_NEED_MASK
770+ if (!(saw_user_obj && saw_group_obj && saw_other && saw_mask))
771+#else
772+ if (!(saw_user_obj && saw_group_obj && saw_other))
773+#endif
774+ sort_rsync_acl(racl);
775+}
776+
777+/* receive and build the rsync_acl_lists */
778+
779+void receive_acl(struct file_struct *file, int f)
780+{
36aa3171 781+ SMB_ACL_TYPE_T *type;
fa26e11c 782+ char *fname;
36aa3171 783+
fa26e11c
WD
784+ if (!preserve_acls || S_ISLNK(file->mode))
785+ return;
36aa3171 786+
bd68c3c2 787+ fname = f_name(file, NULL);
fa26e11c
WD
788+ for (type = &types[0];
789+ type < &types[0] + sizeof types / sizeof types[0]
790+ && (*type == SMB_ACL_TYPE_ACCESS || S_ISDIR(file->mode));
791+ type++) {
792+ file_acl_index_list *fileaclidx_list =
793+ file_acl_index_lists(*type);
794+ uchar tag;
795+ expand_file_acl_index_list(fileaclidx_list);
796+
797+ tag = read_byte(f);
798+ if (tag == 'A' || tag == 'a') {
799+ if (*type != SMB_ACL_TYPE_ACCESS) {
800+ rprintf(FERROR, "receive_acl %s: duplicate access ACL\n",
801+ fname);
802+ exit_cleanup(RERR_STREAMIO);
803+ }
804+ } else if (tag == 'D' || tag == 'd') {
805+ if (*type == SMB_ACL_TYPE_ACCESS) {
806+ rprintf(FERROR, "receive_acl %s: expecting access ACL; got default\n",
807+ fname);
808+ exit_cleanup(RERR_STREAMIO);
809+ }
810+ } else {
811+ rprintf(FERROR, "receive_acl %s: unknown ACL type tag: %c\n",
812+ fname, tag);
813+ exit_cleanup(RERR_STREAMIO);
814+ }
815+ if (tag == 'A' || tag == 'D') {
816+ rsync_acl racl = rsync_acl_initializer;
817+ rsync_acl_list *racl_list = rsync_acl_lists(*type);
818+ smb_acl_list *sacl_list = smb_acl_lists(*type);
819+ fileaclidx_list->fileaclidxs[fileaclidx_list->count].
820+ aclidx = racl_list->count;
821+ fileaclidx_list->fileaclidxs[fileaclidx_list->count++].
822+ file = file;
823+ receive_rsync_acl(&racl, f);
824+ expand_rsync_acl_list(racl_list);
825+ racl_list->racls[racl_list->count++] = racl;
826+ expand_smb_acl_list(sacl_list);
827+ sacl_list->sacls[sacl_list->count++] = NULL;
828+ } else {
829+ int index = read_int(f);
830+ rsync_acl_list *racl_list = rsync_acl_lists(*type);
831+ if ((size_t) index >= racl_list->count) {
832+ rprintf(FERROR, "receive_acl %s: %s ACL index %d out of range\n",
833+ fname,
834+ str_acl_type(*type),
835+ index);
836+ exit_cleanup(RERR_STREAMIO);
837+ }
838+ fileaclidx_list->fileaclidxs[fileaclidx_list->count].
839+ aclidx = index;
840+ fileaclidx_list->fileaclidxs[fileaclidx_list->count++].
841+ file = file;
842+ }
843+ }
844+}
845+
846+static int file_acl_index_list_sorter(const void *f1, const void *f2)
847+{
848+ const file_acl_index *fileaclidx1 = (const file_acl_index *)f1;
849+ const file_acl_index *fileaclidx2 = (const file_acl_index *)f2;
850+ return fileaclidx1->file == fileaclidx2->file ? 0 :
851+ fileaclidx1->file < fileaclidx2->file ? -1 : 1;
852+}
853+
854+void sort_file_acl_index_lists()
855+{
36aa3171
WD
856+ SMB_ACL_TYPE_T *type;
857+
fa26e11c
WD
858+ if (!preserve_acls)
859+ return;
36aa3171 860+
fa26e11c
WD
861+ for (type = &types[0];
862+ type < &types[0] + sizeof types / sizeof types[0];
36aa3171 863+ type++) {
fa26e11c
WD
864+ file_acl_index_list *fileaclidx_list =
865+ file_acl_index_lists(*type);
866+ if (!fileaclidx_list->count)
867+ continue;
868+ qsort(fileaclidx_list->fileaclidxs, fileaclidx_list->count,
869+ sizeof fileaclidx_list->fileaclidxs[0],
870+ &file_acl_index_list_sorter);
871+ }
872+}
873+
874+static int find_file_acl_index(const file_acl_index_list *fileaclidx_list,
875+ const struct file_struct *file) {
876+ int low = 0, high = fileaclidx_list->count;
877+ const struct file_struct *file_mid;
878+ if (!high--)
879+ return -1;
880+ do {
881+ int mid = (high + low) / 2;
882+ file_mid = fileaclidx_list->fileaclidxs[mid].file;
883+ if (file_mid == file)
884+ return fileaclidx_list->fileaclidxs[mid].aclidx;
885+ if (file_mid > file)
886+ high = mid - 1;
887+ else
888+ low = mid + 1;
889+ } while (low < high);
890+ if (low == high) {
891+ file_mid = fileaclidx_list->fileaclidxs[low].file;
892+ if (file_mid == file)
893+ return fileaclidx_list->fileaclidxs[low].aclidx;
894+ }
895+ rprintf(FERROR,
896+ "find_file_acl_index: can't find entry for file in list\n");
897+ exit_cleanup(RERR_STREAMIO);
898+ return -1;
899+}
900+
901+/* for duplicating ACLs on backups when using backup_dir */
902+
903+int dup_acl(const char *orig, const char *bak, mode_t mode)
904+{
36aa3171 905+ SMB_ACL_TYPE_T *type;
fa26e11c 906+ int ret = 0;
36aa3171 907+
fa26e11c 908+ if (!preserve_acls)
05b88206 909+ return 1;
36aa3171 910+
fa26e11c
WD
911+ for (type = &types[0];
912+ type < &types[0] + sizeof types / sizeof types[0]
913+ && (*type == SMB_ACL_TYPE_ACCESS || S_ISDIR(mode));
914+ type++) {
915+ SMB_ACL_T sacl_orig, sacl_bak;
916+ rsync_acl racl_orig, racl_bak;
917+ if (!(sacl_orig = sys_acl_get_file(orig, *type))) {
c171f097 918+ rprintf(FERROR, "dup_acl: sys_acl_get_file(%s, %s): %s\n",
fa26e11c
WD
919+ orig, str_acl_type(*type), strerror(errno));
920+ ret = -1;
921+ continue;
922+ }
923+ if (!(sacl_bak = sys_acl_get_file(orig, *type))) {
c171f097 924+ rprintf(FERROR, "dup_acl: sys_acl_get_file(%s, %s): %s. ignoring\n",
fa26e11c
WD
925+ bak, str_acl_type(*type), strerror(errno));
926+ ret = -1;
927+ /* try to forge on through */
928+ }
929+ if (!unpack_smb_acl(&racl_orig, sacl_orig)) {
930+ ret = -1;
931+ goto out_with_sacls;
932+ }
933+ if (sacl_bak) {
934+ if (!unpack_smb_acl(&racl_bak, sacl_bak)) {
935+ ret = -1;
936+ goto out_with_one_racl;
937+ }
938+ if (rsync_acls_equal(&racl_orig, &racl_bak))
939+ goto out_with_all;
940+ } else {
941+ ; /* presume they're unequal */
942+ }
943+ if (*type == SMB_ACL_TYPE_DEFAULT && !racl_orig.count) {
e6a7303b 944+ if (sys_acl_delete_def_file(bak) < 0) {
fa26e11c
WD
945+ rprintf(FERROR, "dup_acl: sys_acl_delete_def_file(%s): %s\n",
946+ bak, strerror(errno));
947+ ret = -1;
948+ }
e6a7303b 949+ } else if (sys_acl_set_file(bak, *type, sacl_bak) < 0) {
c171f097 950+ rprintf(FERROR, "dup_acl: sys_acl_set_file(%s, %s): %s\n",
fa26e11c
WD
951+ bak, str_acl_type(*type), strerror(errno));
952+ ret = -1;
953+ }
954+ out_with_all:
955+ if (sacl_bak)
956+ rsync_acl_free(&racl_bak);
957+ out_with_one_racl:
958+ rsync_acl_free(&racl_orig);
959+ out_with_sacls:
960+ if (sacl_bak)
961+ sys_acl_free_acl(sacl_bak);
962+ /* out_with_one_sacl: */
963+ if (sacl_orig)
964+ sys_acl_free_acl(sacl_orig);
965+ }
966+ return ret;
967+}
968+
90fa6d68 969+/* Stuff for redirecting calls to set_acl() from set_file_attrs()
4edb99c8 970+ * for keep_backup(). */
fa26e11c
WD
971+static const struct file_struct *backup_orig_file = NULL;
972+static const char null_string[] = "";
973+static const char *backup_orig_fname = null_string;
974+static const char *backup_dest_fname = null_string;
975+static SMB_ACL_T _backup_sacl[] = { NULL, NULL };
976+
977+void push_keep_backup_acl(const struct file_struct *file,
978+ const char *orig, const char *dest)
979+{
980+ if (preserve_acls) {
36aa3171 981+ SMB_ACL_TYPE_T *type;
fa26e11c 982+ SMB_ACL_T *sacl;
36aa3171 983+
fa26e11c
WD
984+ backup_orig_file = file;
985+ backup_orig_fname = orig;
986+ backup_dest_fname = dest;
36aa3171 987+
fa26e11c
WD
988+ for (type = &types[0], sacl = &_backup_sacl[0];
989+ type < &types[0] + sizeof types / sizeof types[0];
990+ type++) {
991+ if (*type == SMB_ACL_TYPE_DEFAULT && !S_ISDIR(file->mode))
992+ *sacl = NULL;
993+ else {
994+ if (!(*sacl = sys_acl_get_file(orig, *type))) {
c171f097 995+ rprintf(FERROR, "push_keep_backup_acl: sys_acl_get_file(%s, %s): %s\n",
fa26e11c
WD
996+ orig, str_acl_type(*type),
997+ strerror(errno));
998+ }
999+ }
1000+ }
1001+ }
1002+}
1003+
1004+static int set_keep_backup_acl()
1005+{
1006+ if (preserve_acls) {
36aa3171 1007+ SMB_ACL_TYPE_T *type;
fa26e11c
WD
1008+ SMB_ACL_T *sacl;
1009+ int ret = 0;
36aa3171 1010+
fa26e11c
WD
1011+ for (type = &types[0], sacl = &_backup_sacl[0];
1012+ type < &types[0] + sizeof types / sizeof types[0];
1013+ type++) {
1014+ if (*sacl) {
e6a7303b
WD
1015+ if (sys_acl_set_file(backup_dest_fname,
1016+ *type, *sacl) < 0) {
c171f097 1017+ rprintf(FERROR, "push_keep_backup_acl: sys_acl_get_file(%s, %s): %s\n",
fa26e11c
WD
1018+ backup_dest_fname,
1019+ str_acl_type(*type),
1020+ strerror(errno));
1021+ ret = -1;
1022+ }
1023+ }
1024+ }
1025+ return ret;
1026+ }
05b88206 1027+ return 1;
fa26e11c
WD
1028+}
1029+
1030+void cleanup_keep_backup_acl()
1031+{
1032+ if (preserve_acls) {
36aa3171 1033+ SMB_ACL_TYPE_T *type;
fa26e11c 1034+ SMB_ACL_T *sacl;
36aa3171 1035+
fa26e11c
WD
1036+ backup_orig_file = NULL;
1037+ backup_orig_fname = null_string;
1038+ backup_dest_fname = null_string;
36aa3171 1039+
fa26e11c
WD
1040+ for (type = &types[0], sacl = &_backup_sacl[0];
1041+ type < &types[0] + sizeof types / sizeof types[0];
1042+ type++) {
1043+ if (*sacl)
1044+ sys_acl_free_acl(*sacl);
1045+ *sacl = NULL;
1046+ }
1047+ }
1048+}
1049+
1050+/* set ACL on rsync-ed or keep_backup-ed file */
1051+
1052+int set_acl(const char *fname, const struct file_struct *file)
1053+{
81ddc4dc 1054+ int unchanged = 1;
36aa3171
WD
1055+ SMB_ACL_TYPE_T *type;
1056+
fa26e11c 1057+ if (dry_run || !preserve_acls || S_ISLNK(file->mode))
05b88206 1058+ return 1;
36aa3171 1059+
fa26e11c
WD
1060+ if (file == backup_orig_file) {
1061+ if (!strcmp(fname, backup_dest_fname))
1062+ return set_keep_backup_acl();
1063+ }
1064+ for (type = &types[0];
1065+ type < &types[0] + sizeof types / sizeof types[0]
1066+ && (*type == SMB_ACL_TYPE_ACCESS || S_ISDIR(file->mode));
1067+ type++) {
1068+ SMB_ACL_T sacl_orig, *sacl_new;
1069+ rsync_acl racl_orig, *racl_new;
1070+ int aclidx = find_file_acl_index(file_acl_index_lists(*type),
1071+ file);
1072+ BOOL ok;
1073+ racl_new = &(rsync_acl_lists(*type)->racls[aclidx]);
1074+ sacl_new = &(smb_acl_lists(*type)->sacls[aclidx]);
1075+ sacl_orig = sys_acl_get_file(fname, *type);
1076+ if (!sacl_orig) {
1077+ rprintf(FERROR, "set_acl: sys_acl_get_file(%s, %s): %s\n",
1078+ fname, str_acl_type(*type), strerror(errno));
81ddc4dc 1079+ unchanged = -1;
fa26e11c
WD
1080+ continue;
1081+ }
1082+ ok = unpack_smb_acl(&racl_orig, sacl_orig);
1083+ sys_acl_free_acl(sacl_orig);
1084+ if (!ok) {
81ddc4dc 1085+ unchanged = -1;
fa26e11c
WD
1086+ continue;
1087+ }
1088+ ok = rsync_acls_equal(&racl_orig, racl_new);
1089+ rsync_acl_free(&racl_orig);
1090+ if (ok)
1091+ continue;
1092+ if (*type == SMB_ACL_TYPE_DEFAULT && !racl_new->count) {
e6a7303b 1093+ if (sys_acl_delete_def_file(fname) < 0) {
fa26e11c
WD
1094+ rprintf(FERROR, "set_acl: sys_acl_delete_def_file(%s): %s\n",
1095+ fname, strerror(errno));
81ddc4dc 1096+ unchanged = -1;
fa26e11c
WD
1097+ continue;
1098+ }
1099+ } else {
1100+ if (!*sacl_new)
1101+ if (!pack_smb_acl(sacl_new, racl_new)) {
81ddc4dc 1102+ unchanged = -1;
fa26e11c
WD
1103+ continue;
1104+ }
e6a7303b 1105+ if (sys_acl_set_file(fname, *type, *sacl_new) < 0) {
fa26e11c
WD
1106+ rprintf(FERROR, "set_acl: sys_acl_set_file(%s, %s): %s\n",
1107+ fname, str_acl_type(*type),
1108+ strerror(errno));
81ddc4dc 1109+ unchanged = -1;
fa26e11c
WD
1110+ continue;
1111+ }
1112+ }
81ddc4dc
WD
1113+ if (unchanged == 1)
1114+ unchanged = 0;
fa26e11c 1115+ }
81ddc4dc 1116+ return unchanged;
fa26e11c
WD
1117+}
1118+
4edb99c8 1119+/* Enumeration functions for uid mapping: */
fa26e11c 1120+
4edb99c8
WD
1121+/* Context -- one and only one. Should be cycled through once on uid
1122+ * mapping and once on gid mapping. */
fa26e11c
WD
1123+static rsync_acl_list *_enum_racl_lists[] = {
1124+ &_rsync_acl_lists[0], &_rsync_acl_lists[1], NULL
1125+};
1126+
1127+static rsync_acl_list **enum_racl_list = &_enum_racl_lists[0];
1128+static size_t enum_racl_index = 0;
1129+static size_t enum_race_index = 0;
1130+
4edb99c8
WD
1131+/* This returns the next tag_type id from the given acl for the next entry,
1132+ * or it returns 0 if there are no more tag_type ids in the acl. */
fa26e11c
WD
1133+
1134+static id_t next_ace_id(SMB_ACL_TAG_T tag_type, const rsync_acl *racl)
1135+{
1136+ for (; enum_race_index < racl->count; enum_race_index++) {
1137+ rsync_ace *race = &racl->races[enum_race_index];
1138+ if (race->tag_type == tag_type)
1139+ return race->id;
1140+ }
1141+ enum_race_index = 0;
1142+ return 0;
1143+}
1144+
1145+static id_t next_acl_id(SMB_ACL_TAG_T tag_type, const rsync_acl_list *racl_list)
1146+{
1147+ for (; enum_racl_index < racl_list->count; enum_racl_index++) {
1148+ rsync_acl *racl = &racl_list->racls[enum_racl_index];
1149+ id_t id = next_ace_id(tag_type, racl);
1150+ if (id)
1151+ return id;
1152+ }
1153+ enum_racl_index = 0;
1154+ return 0;
1155+}
1156+
1157+static id_t next_acl_list_id(SMB_ACL_TAG_T tag_type)
1158+{
1159+ for (; *enum_racl_list; enum_racl_list++) {
1160+ id_t id = next_acl_id(tag_type, *enum_racl_list);
1161+ if (id)
1162+ return id;
1163+ }
1164+ enum_racl_list = &_enum_racl_lists[0];
1165+ return 0;
1166+}
1167+
1168+id_t next_acl_uid()
1169+{
1170+ return next_acl_list_id(SMB_ACL_USER);
1171+}
1172+
1173+id_t next_acl_gid()
1174+{
1175+ return next_acl_list_id(SMB_ACL_GROUP);
1176+}
1177+
1178+/* referring to the global context enum_entry, sets the entry's id */
1179+static void set_acl_id(id_t id)
1180+{
1181+ (*enum_racl_list)->racls[enum_racl_index].races[enum_race_index++].id = id;
1182+}
1183+
1184+void acl_uid_map(id_t uid)
1185+{
1186+ set_acl_id(uid);
1187+}
1188+
1189+void acl_gid_map(id_t gid)
1190+{
1191+ set_acl_id(gid);
1192+}
1193+
26c810d8 1194+#define PERMS_SPLICE(perms,newbits,where) (((perms) & ~(7 << (where))) | ((newbits) << (where)))
90fa6d68 1195+
26c810d8 1196+int default_perms_for_dir(const char *dir)
90fa6d68
WD
1197+{
1198+ rsync_acl racl;
1199+ SMB_ACL_T sacl;
1200+ BOOL ok, saw_mask = False;
90fa6d68 1201+ size_t i;
26c810d8 1202+ int perms;
90fa6d68
WD
1203+
1204+ if (dir == NULL)
1205+ dir = ".";
26c810d8 1206+ perms = ACCESSPERMS & ~orig_umask;
90fa6d68
WD
1207+ /* Read the directory's default ACL. If it has none, this will successfully return an empty ACL. */
1208+ sacl = sys_acl_get_file(dir, SMB_ACL_TYPE_DEFAULT);
1209+ if (sacl == NULL) {
1210+ /* Couldn't get an ACL. Darn. */
1211+ switch (errno) {
1212+ case ENOTSUP:
1213+ /* ACLs are disabled. We could yell at the user to turn them on, but... */
1214+ break;
1215+ case ENOENT:
1216+ if (dry_run) {
1217+ /* We're doing a dry run, so the containing directory
1218+ * wasn't actually created. Don't worry about it. */
1219+ break;
1220+ }
1221+ /* Otherwise fall through. */
1222+ default:
26c810d8 1223+ rprintf(FERROR, "default_perms_for_dir: sys_acl_get_file(%s, %s): %s, falling back on umask\n",
90fa6d68
WD
1224+ dir, str_acl_type(SMB_ACL_TYPE_DEFAULT), strerror(errno));
1225+ }
26c810d8 1226+ return perms;
90fa6d68
WD
1227+ }
1228+
1229+ /* Convert it. */
1230+ ok = unpack_smb_acl(&racl, sacl);
1231+ sys_acl_free_acl(sacl);
1232+ if (!ok) {
26c810d8
WD
1233+ rprintf(FERROR, "default_perms_for_dir: unpack_smb_acl failed, falling back on umask\n");
1234+ return perms;
90fa6d68
WD
1235+ }
1236+
26c810d8
WD
1237+ /* Look at each default ACL entry and possibly modify three bits of `perms' accordingly.
1238+ * If there's "no" default ACL, there will be zero entries and the umask-based perms is unchanged. */
90fa6d68
WD
1239+ for (i = 0; i < racl.count; i++) {
1240+ switch (racl.races[i].tag_type) {
1241+ case SMB_ACL_USER_OBJ:
26c810d8 1242+ perms = PERMS_SPLICE(perms, racl.races[i].access, 6);
90fa6d68
WD
1243+ break;
1244+ case SMB_ACL_GROUP_OBJ:
1245+ if (!saw_mask)
26c810d8 1246+ perms = PERMS_SPLICE(perms, racl.races[i].access, 3);
90fa6d68
WD
1247+ break;
1248+ case SMB_ACL_MASK:
1249+ saw_mask = True;
26c810d8 1250+ perms = PERMS_SPLICE(perms, racl.races[i].access, 3);
90fa6d68
WD
1251+ break;
1252+ case SMB_ACL_OTHER:
26c810d8 1253+ perms = PERMS_SPLICE(perms, racl.races[i].access, 0);
90fa6d68
WD
1254+ break;
1255+ default:
1256+ break;
1257+ }
1258+ }
1259+ rsync_acl_free(&racl);
1260+ if (verbose > 2)
26c810d8
WD
1261+ rprintf(FINFO, "got ACL-based default perms %o for directory %s\n", perms, dir);
1262+ return perms;
90fa6d68
WD
1263+}
1264+
fa26e11c 1265+#endif /* SUPPORT_ACLS */
9a7eef96
WD
1266--- old/backup.c
1267+++ new/backup.c
e6a7303b 1268@@ -132,6 +132,9 @@ static int make_bak_dir(char *fullpath)
fa26e11c
WD
1269 } else {
1270 do_lchown(fullpath, st.st_uid, st.st_gid);
1271 do_chmod(fullpath, st.st_mode);
e6a7303b
WD
1272+#ifdef SUPPORT_ACLS
1273+ dup_acl(end, fullpath, st.st_mode);
1274+#endif
fa26e11c
WD
1275 }
1276 }
1277 *p = '/';
e6a7303b 1278@@ -185,6 +188,10 @@ static int keep_backup(char *fname)
172ad6c3 1279 if (!(buf = get_backup_name(fname)))
fa26e11c 1280 return 0;
fa26e11c 1281
e6a7303b
WD
1282+#ifdef SUPPORT_ACLS
1283+ push_keep_backup_acl(file, fname, buf);
1284+#endif
fa26e11c 1285+
fa26e11c 1286 /* Check to see if this is a device file, or link */
90fa6d68
WD
1287 if ((am_root && preserve_devices && IS_DEVICE(file->mode))
1288 || (preserve_specials && IS_SPECIAL(file->mode))) {
e6a7303b 1289@@ -260,6 +267,9 @@ static int keep_backup(char *fname)
fa26e11c
WD
1290 }
1291 }
90fa6d68 1292 set_file_attrs(buf, file, NULL, 0);
e6a7303b
WD
1293+#ifdef SUPPORT_ACLS
1294+ cleanup_keep_backup_acl();
1295+#endif
fa26e11c
WD
1296 free(file);
1297
27a7053c 1298 if (verbose > 1) {
9a7eef96
WD
1299--- old/configure.in
1300+++ new/configure.in
afcb578c 1301@@ -482,6 +482,11 @@ if test x"$ac_cv_func_strcasecmp" = x"no
fa26e11c
WD
1302 AC_CHECK_LIB(resolv, strcasecmp)
1303 fi
1304
1305+AC_CHECK_FUNCS(aclsort)
1306+if test x"$ac_cv_func_aclsort" = x"no"; then
1307+ AC_CHECK_LIB(sec, aclsort)
1308+fi
1309+
1310 dnl At the moment we don't test for a broken memcmp(), because all we
1311 dnl need to do is test for equality, not comparison, and it seems that
1312 dnl every platform has a memcmp that can do at least that.
afcb578c 1313@@ -738,6 +743,77 @@ AC_SUBST(OBJ_RESTORE)
fa26e11c
WD
1314 AC_SUBST(CC_SHOBJ_FLAG)
1315 AC_SUBST(BUILD_POPT)
125d7fca 1316
fa26e11c
WD
1317+AC_CHECK_HEADERS(sys/acl.h)
1318+AC_CHECK_FUNCS(_acl __acl _facl __facl)
1319+#################################################
1320+# check for ACL support
1321+
1322+AC_MSG_CHECKING(whether to support ACLs)
f787c90c
WD
1323+AC_ARG_ENABLE(acl-support,
1324+AC_HELP_STRING([--enable-acl-support], [Include ACL support (default=no)]),
3b05e91f 1325+[ case "$enableval" in
fa26e11c
WD
1326+ yes)
1327+
1328+ case "$host_os" in
1329+ *sysv5*)
1330+ AC_MSG_RESULT(Using UnixWare ACLs)
1331+ AC_DEFINE(HAVE_UNIXWARE_ACLS, 1, [true if you have UnixWare ACLs])
1332+ ;;
1333+ *solaris*)
1334+ AC_MSG_RESULT(Using solaris ACLs)
1335+ AC_DEFINE(HAVE_SOLARIS_ACLS, 1, [true if you have solaris ACLs])
1336+ ;;
1337+ *hpux*)
1338+ AC_MSG_RESULT(Using HPUX ACLs)
1339+ AC_DEFINE(HAVE_HPUX_ACLS, 1, [true if you have HPUX ACLs])
1340+ ;;
1341+ *irix*)
1342+ AC_MSG_RESULT(Using IRIX ACLs)
1343+ AC_DEFINE(HAVE_IRIX_ACLS, 1, [true if you have IRIX ACLs])
1344+ ;;
1345+ *aix*)
1346+ AC_MSG_RESULT(Using AIX ACLs)
1347+ AC_DEFINE(HAVE_AIX_ACLS, 1, [true if you have AIX ACLs])
1348+ ;;
1349+ *osf*)
1350+ AC_MSG_RESULT(Using Tru64 ACLs)
1351+ AC_DEFINE(HAVE_TRU64_ACLS, 1, [true if you have Tru64 ACLs])
1352+ LIBS="$LIBS -lpacl"
1353+ ;;
1354+ *)
81549708 1355+ AC_MSG_RESULT(ACLs requested -- running tests)
fa26e11c
WD
1356+ AC_CHECK_LIB(acl,acl_get_file)
1357+ AC_CACHE_CHECK([for ACL support],samba_cv_HAVE_POSIX_ACLS,[
1358+ AC_TRY_LINK([#include <sys/types.h>
1359+#include <sys/acl.h>],
1360+[ acl_t acl; int entry_id; acl_entry_t *entry_p; return acl_get_entry( acl, entry_id, entry_p);],
1361+samba_cv_HAVE_POSIX_ACLS=yes,samba_cv_HAVE_POSIX_ACLS=no)])
1362+ if test x"$samba_cv_HAVE_POSIX_ACLS" = x"yes"; then
1363+ AC_MSG_RESULT(Using posix ACLs)
1364+ AC_DEFINE(HAVE_POSIX_ACLS, 1, [true if you have posix ACLs])
81549708 1365+ AC_CACHE_CHECK([for acl_get_perm_np],samba_cv_HAVE_ACL_GET_PERM_NP,[
fa26e11c
WD
1366+ AC_TRY_LINK([#include <sys/types.h>
1367+#include <sys/acl.h>],
1368+[ acl_permset_t permset_d; acl_perm_t perm; return acl_get_perm_np( permset_d, perm);],
1369+samba_cv_HAVE_ACL_GET_PERM_NP=yes,samba_cv_HAVE_ACL_GET_PERM_NP=no)])
81549708
WD
1370+ if test x"$samba_cv_HAVE_ACL_GET_PERM_NP" = x"yes"; then
1371+ AC_DEFINE(HAVE_ACL_GET_PERM_NP, 1, [true if you have acl_get_perm_np])
1372+ fi
1373+ else
1374+ AC_MSG_ERROR(Failed to find ACL support)
fa26e11c
WD
1375+ fi
1376+ ;;
1377+ esac
1378+ ;;
1379+ *)
1380+ AC_MSG_RESULT(no)
1381+ AC_DEFINE(HAVE_NO_ACLS, 1, [true if you don't have ACLs])
1382+ ;;
1383+ esac ],
1384+ AC_DEFINE(HAVE_NO_ACLS, 1, [true if you don't have ACLs])
1385+ AC_MSG_RESULT(no)
1386+)
125d7fca 1387+
fa26e11c
WD
1388 AC_CONFIG_FILES([Makefile lib/dummy zlib/dummy popt/dummy shconfig])
1389 AC_OUTPUT
125d7fca 1390
9a7eef96
WD
1391--- old/flist.c
1392+++ new/flist.c
e6a7303b 1393@@ -966,6 +966,10 @@ static struct file_struct *send_file_nam
e0e47893 1394 f == -2 ? SERVER_FILTERS : ALL_FILTERS);
09fb8f03 1395 if (!file)
5e048c14 1396 return NULL;
e6a7303b
WD
1397+#ifdef SUPPORT_ACLS
1398+ if (make_acl(file, fname) < 0)
4df546eb 1399+ return NULL;
e6a7303b 1400+#endif
fa26e11c 1401
3b05e91f 1402 if (chmod_modes && !S_ISLNK(file->mode))
e0e47893 1403 file->mode = tweak_mode(file->mode, chmod_modes);
e6a7303b 1404@@ -977,6 +981,12 @@ static struct file_struct *send_file_nam
fa26e11c
WD
1405 if (file->basename[0]) {
1406 flist->files[flist->count++] = file;
e0e47893 1407 send_file_entry(file, f);
e6a7303b
WD
1408+#ifdef SUPPORT_ACLS
1409+ send_acl(file, f);
fa26e11c
WD
1410+ } else {
1411+ /* Cleanup unsent ACL(s). */
e6a7303b
WD
1412+ send_acl(file, -1);
1413+#endif
fa26e11c 1414 }
5e048c14
WD
1415 return file;
1416 }
e6a7303b 1417@@ -1365,6 +1375,10 @@ struct file_list *recv_file_list(int f)
fa26e11c 1418 flags |= read_byte(f) << 8;
618752a7 1419 file = receive_file_entry(flist, flags, f);
fa26e11c 1420
e6a7303b
WD
1421+#ifdef SUPPORT_ACLS
1422+ receive_acl(file, f);
1423+#endif
fa26e11c 1424+
ae6834e1 1425 if (S_ISREG(file->mode) || S_ISLNK(file->mode))
618752a7 1426 stats.total_size += file->length;
fa26e11c 1427
e6a7303b 1428@@ -1387,6 +1401,10 @@ struct file_list *recv_file_list(int f)
fa26e11c
WD
1429
1430 clean_flist(flist, relative_paths, 1);
fa26e11c 1431
e6a7303b
WD
1432+#ifdef SUPPORT_ACLS
1433+ sort_file_acl_index_lists();
1434+#endif
125d7fca 1435+
09fb8f03 1436 if (f >= 0) {
90fa6d68
WD
1437 recv_uid_list(f, flist);
1438
9a7eef96
WD
1439--- old/generator.c
1440+++ new/generator.c
2578e2b6 1441@@ -85,6 +85,7 @@ extern long block_size; /* "long" becaus
1a2fa68f
WD
1442 extern int max_delete;
1443 extern int force_delete;
1444 extern int one_file_system;
1445+extern mode_t orig_umask;
1446 extern struct stats stats;
1447 extern dev_t filesystem_dev;
1448 extern char *backup_dir;
2578e2b6 1449@@ -753,6 +754,7 @@ static int try_dests_non(struct file_str
26c810d8
WD
1450 }
1451
1452 static int phase = 0;
1453+static int dflt_perms;
1454
1455 /* Acts on the_file_list->file's ndx'th item, whose name is fname. If a dir,
1456 * make sure it exists, and has the right permissions/timestamp info. For
1a2fa68f 1457@@ -844,6 +846,10 @@ static void recv_generator(char *fname,
01deb4dc
WD
1458 }
1459 if (fuzzy_basis)
63673ef2 1460 need_fuzzy_dirlist = 1;
26c810d8 1461+#ifdef SUPPORT_ACLS
01deb4dc
WD
1462+ if (!preserve_perms)
1463+ dflt_perms = default_perms_for_dir(dn);
26c810d8 1464+#endif
26c810d8 1465 }
01deb4dc 1466 parent_dirname = dn;
26c810d8 1467
1a2fa68f 1468@@ -871,7 +877,8 @@ static void recv_generator(char *fname,
90fa6d68
WD
1469 if (!preserve_perms) {
1470 int exists = statret == 0
1471 && S_ISDIR(st.st_mode) == S_ISDIR(file->mode);
1472- file->mode = dest_mode(file->mode, st.st_mode, exists);
26c810d8
WD
1473+ file->mode = dest_mode(file->mode, st.st_mode, dflt_perms,
1474+ exists);
90fa6d68
WD
1475 }
1476
1477 if (S_ISDIR(file->mode)) {
81ddc4dc 1478@@ -1342,6 +1349,8 @@ void generate_files(int f_out, struct fi
26c810d8
WD
1479 * notice that and let us know via the redo pipe (or its closing). */
1480 ignore_timeout = 1;
1481
1482+ dflt_perms = (ACCESSPERMS & ~orig_umask);
1483+
1484 for (i = 0; i < flist->count; i++) {
1485 struct file_struct *file = flist->files[i];
1486
9a7eef96
WD
1487--- old/lib/sysacls.c
1488+++ new/lib/sysacls.c
252945ef 1489@@ -0,0 +1,3242 @@
fa26e11c 1490+/*
5ca9317d 1491+ Unix SMB/CIFS implementation.
0f6733d8
WD
1492+ Samba system utilities for ACL support.
1493+ Copyright (C) Jeremy Allison 2000.
fa26e11c
WD
1494+
1495+ This program is free software; you can redistribute it and/or modify
1496+ it under the terms of the GNU General Public License as published by
1497+ the Free Software Foundation; either version 2 of the License, or
1498+ (at your option) any later version.
1499+
1500+ This program is distributed in the hope that it will be useful,
1501+ but WITHOUT ANY WARRANTY; without even the implied warranty of
1502+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
1503+ GNU General Public License for more details.
1504+
1505+ You should have received a copy of the GNU General Public License
1506+ along with this program; if not, write to the Free Software
1507+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
1508+*/
1509+
0f6733d8 1510+#include "rsync.h"
252945ef 1511+#include "sysacls.h" /****** ADDED ******/
fa26e11c 1512+
252945ef 1513+/****** EXTRAS -- THESE ITEMS ARE NOT FROM THE SAMBA SOURCE ******/
0f6733d8
WD
1514+void SAFE_FREE(void *mem)
1515+{
1516+ if (mem)
1517+ free(mem);
1518+}
fa26e11c 1519+
5ca9317d
WD
1520+char *uidtoname(uid_t uid)
1521+{
1522+ static char idbuf[12];
1523+ struct passwd *pw;
1524+
1525+ if ((pw = getpwuid(uid)) == NULL) {
1526+ slprintf(idbuf, sizeof(idbuf)-1, "%ld", (long)uid);
1527+ return idbuf;
1528+ }
1529+ return pw->pw_name;
1530+}
252945ef 1531+/****** EXTRAS -- END ******/
5ca9317d 1532+
0f6733d8
WD
1533+/*
1534+ This file wraps all differing system ACL interfaces into a consistent
1535+ one based on the POSIX interface. It also returns the correct errors
1536+ for older UNIX systems that don't support ACLs.
fa26e11c 1537+
0f6733d8 1538+ The interfaces that each ACL implementation must support are as follows :
fa26e11c 1539+
0f6733d8
WD
1540+ int sys_acl_get_entry( SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
1541+ int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
1542+ int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p
1543+ void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
1544+ SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
1545+ SMB_ACL_T sys_acl_get_fd(int fd)
1546+ int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset);
1547+ int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm);
1548+ char *sys_acl_to_text( SMB_ACL_T theacl, ssize_t *plen)
1549+ SMB_ACL_T sys_acl_init( int count)
1550+ int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
1551+ int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
1552+ int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
1553+ int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
1554+ int sys_acl_valid( SMB_ACL_T theacl )
1555+ int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
1556+ int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
1557+ int sys_acl_delete_def_file(const char *path)
fa26e11c 1558+
0f6733d8
WD
1559+ This next one is not POSIX complient - but we *have* to have it !
1560+ More POSIX braindamage.
fa26e11c 1561+
0f6733d8 1562+ int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
fa26e11c 1563+
0f6733d8
WD
1564+ The generic POSIX free is the following call. We split this into
1565+ several different free functions as we may need to add tag info
1566+ to structures when emulating the POSIX interface.
fa26e11c 1567+
0f6733d8 1568+ int sys_acl_free( void *obj_p)
fa26e11c 1569+
0f6733d8 1570+ The calls we actually use are :
fa26e11c 1571+
0f6733d8
WD
1572+ int sys_acl_free_text(char *text) - free acl_to_text
1573+ int sys_acl_free_acl(SMB_ACL_T posix_acl)
1574+ int sys_acl_free_qualifier(void *qualifier, SMB_ACL_TAG_T tagtype)
fa26e11c 1575+
0f6733d8 1576+*/
fa26e11c 1577+
0f6733d8 1578+#if defined(HAVE_POSIX_ACLS)
fa26e11c 1579+
0f6733d8 1580+/* Identity mapping - easy. */
fa26e11c 1581+
0f6733d8 1582+int sys_acl_get_entry( SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
fa26e11c 1583+{
0f6733d8 1584+ return acl_get_entry( the_acl, entry_id, entry_p);
fa26e11c
WD
1585+}
1586+
0f6733d8 1587+int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
fa26e11c 1588+{
0f6733d8 1589+ return acl_get_tag_type( entry_d, tag_type_p);
fa26e11c
WD
1590+}
1591+
0f6733d8 1592+int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
fa26e11c 1593+{
0f6733d8 1594+ return acl_get_permset( entry_d, permset_p);
fa26e11c
WD
1595+}
1596+
0f6733d8 1597+void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
fa26e11c 1598+{
0f6733d8 1599+ return acl_get_qualifier( entry_d);
fa26e11c
WD
1600+}
1601+
0f6733d8 1602+SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
fa26e11c 1603+{
0f6733d8 1604+ return acl_get_file( path_p, type);
fa26e11c
WD
1605+}
1606+
1607+SMB_ACL_T sys_acl_get_fd(int fd)
1608+{
1609+ return acl_get_fd(fd);
1610+}
1611+
1612+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
1613+{
1614+ return acl_clear_perms(permset);
1615+}
1616+
0f6733d8 1617+int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
fa26e11c
WD
1618+{
1619+ return acl_add_perm(permset, perm);
1620+}
1621+
0f6733d8 1622+int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
fa26e11c
WD
1623+{
1624+#if defined(HAVE_ACL_GET_PERM_NP)
0f6733d8
WD
1625+ /*
1626+ * Required for TrustedBSD-based ACL implementations where
fa26e11c 1627+ * non-POSIX.1e functions are denoted by a _np (non-portable)
0f6733d8
WD
1628+ * suffix.
1629+ */
fa26e11c
WD
1630+ return acl_get_perm_np(permset, perm);
1631+#else
1632+ return acl_get_perm(permset, perm);
1633+#endif
1634+}
1635+
0f6733d8 1636+char *sys_acl_to_text( SMB_ACL_T the_acl, ssize_t *plen)
fa26e11c 1637+{
0f6733d8 1638+ return acl_to_text( the_acl, plen);
fa26e11c
WD
1639+}
1640+
0f6733d8 1641+SMB_ACL_T sys_acl_init( int count)
fa26e11c
WD
1642+{
1643+ return acl_init(count);
1644+}
1645+
0f6733d8 1646+int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
fa26e11c
WD
1647+{
1648+ return acl_create_entry(pacl, pentry);
1649+}
1650+
0f6733d8 1651+int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
fa26e11c
WD
1652+{
1653+ return acl_set_tag_type(entry, tagtype);
1654+}
1655+
0f6733d8 1656+int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
fa26e11c
WD
1657+{
1658+ return acl_set_qualifier(entry, qual);
1659+}
1660+
0f6733d8 1661+int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
fa26e11c
WD
1662+{
1663+ return acl_set_permset(entry, permset);
1664+}
1665+
0f6733d8 1666+int sys_acl_valid( SMB_ACL_T theacl )
fa26e11c
WD
1667+{
1668+ return acl_valid(theacl);
1669+}
1670+
1671+int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
1672+{
1673+ return acl_set_file(name, acltype, theacl);
1674+}
1675+
0f6733d8 1676+int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
fa26e11c
WD
1677+{
1678+ return acl_set_fd(fd, theacl);
1679+}
1680+
1681+int sys_acl_delete_def_file(const char *name)
1682+{
1683+ return acl_delete_def_file(name);
1684+}
1685+
1686+int sys_acl_free_text(char *text)
1687+{
1688+ return acl_free(text);
1689+}
1690+
0f6733d8 1691+int sys_acl_free_acl(SMB_ACL_T the_acl)
fa26e11c
WD
1692+{
1693+ return acl_free(the_acl);
1694+}
1695+
1f839b40 1696+int sys_acl_free_qualifier(void *qual, UNUSED(SMB_ACL_TAG_T tagtype))
fa26e11c
WD
1697+{
1698+ return acl_free(qual);
1699+}
1700+
1701+#elif defined(HAVE_TRU64_ACLS)
0f6733d8
WD
1702+/*
1703+ * The interface to DEC/Compaq Tru64 UNIX ACLs
fa26e11c
WD
1704+ * is based on Draft 13 of the POSIX spec which is
1705+ * slightly different from the Draft 16 interface.
0f6733d8 1706+ *
fa26e11c
WD
1707+ * Also, some of the permset manipulation functions
1708+ * such as acl_clear_perm() and acl_add_perm() appear
1709+ * to be broken on Tru64 so we have to manipulate
0f6733d8
WD
1710+ * the permission bits in the permset directly.
1711+ */
1712+int sys_acl_get_entry( SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
fa26e11c 1713+{
0f6733d8 1714+ SMB_ACL_ENTRY_T entry;
fa26e11c
WD
1715+
1716+ if (entry_id == SMB_ACL_FIRST_ENTRY && acl_first_entry(the_acl) != 0) {
1717+ return -1;
1718+ }
1719+
1720+ errno = 0;
1721+ if ((entry = acl_get_entry(the_acl)) != NULL) {
1722+ *entry_p = entry;
1723+ return 1;
1724+ }
1725+
1726+ return errno ? -1 : 0;
1727+}
1728+
0f6733d8 1729+int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
fa26e11c 1730+{
0f6733d8 1731+ return acl_get_tag_type( entry_d, tag_type_p);
fa26e11c
WD
1732+}
1733+
0f6733d8 1734+int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
fa26e11c 1735+{
0f6733d8 1736+ return acl_get_permset( entry_d, permset_p);
fa26e11c
WD
1737+}
1738+
0f6733d8 1739+void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
fa26e11c 1740+{
0f6733d8 1741+ return acl_get_qualifier( entry_d);
fa26e11c
WD
1742+}
1743+
0f6733d8 1744+SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
fa26e11c
WD
1745+{
1746+ return acl_get_file((char *)path_p, type);
1747+}
1748+
0f6733d8 1749+SMB_ACL_T sys_acl_get_fd(int fd)
fa26e11c
WD
1750+{
1751+ return acl_get_fd(fd, ACL_TYPE_ACCESS);
1752+}
1753+
0f6733d8 1754+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
fa26e11c 1755+{
0f6733d8 1756+ *permset = 0; /* acl_clear_perm() is broken on Tru64 */
fa26e11c
WD
1757+
1758+ return 0;
1759+}
1760+
0f6733d8 1761+int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
fa26e11c
WD
1762+{
1763+ if (perm & ~(SMB_ACL_READ | SMB_ACL_WRITE | SMB_ACL_EXECUTE)) {
1764+ errno = EINVAL;
1765+ return -1;
1766+ }
1767+
0f6733d8 1768+ *permset |= perm; /* acl_add_perm() is broken on Tru64 */
fa26e11c
WD
1769+
1770+ return 0;
1771+}
1772+
0f6733d8 1773+int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
fa26e11c
WD
1774+{
1775+ return *permset & perm; /* Tru64 doesn't have acl_get_perm() */
1776+}
1777+
0f6733d8 1778+char *sys_acl_to_text( SMB_ACL_T the_acl, ssize_t *plen)
fa26e11c 1779+{
0f6733d8 1780+ return acl_to_text( the_acl, plen);
fa26e11c
WD
1781+}
1782+
0f6733d8 1783+SMB_ACL_T sys_acl_init( int count)
fa26e11c
WD
1784+{
1785+ return acl_init(count);
1786+}
1787+
0f6733d8 1788+int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
fa26e11c
WD
1789+{
1790+ SMB_ACL_ENTRY_T entry;
1791+
1792+ if ((entry = acl_create_entry(pacl)) == NULL) {
1793+ return -1;
1794+ }
1795+
1796+ *pentry = entry;
1797+ return 0;
1798+}
1799+
0f6733d8 1800+int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
fa26e11c
WD
1801+{
1802+ return acl_set_tag_type(entry, tagtype);
1803+}
1804+
0f6733d8 1805+int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
fa26e11c
WD
1806+{
1807+ return acl_set_qualifier(entry, qual);
1808+}
1809+
0f6733d8 1810+int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
fa26e11c
WD
1811+{
1812+ return acl_set_permset(entry, permset);
1813+}
1814+
0f6733d8 1815+int sys_acl_valid( SMB_ACL_T theacl )
fa26e11c 1816+{
0f6733d8 1817+ acl_entry_t entry;
fa26e11c
WD
1818+
1819+ return acl_valid(theacl, &entry);
1820+}
1821+
0f6733d8 1822+int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
fa26e11c
WD
1823+{
1824+ return acl_set_file((char *)name, acltype, theacl);
1825+}
1826+
0f6733d8 1827+int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
fa26e11c
WD
1828+{
1829+ return acl_set_fd(fd, ACL_TYPE_ACCESS, theacl);
1830+}
1831+
0f6733d8 1832+int sys_acl_delete_def_file(const char *name)
fa26e11c
WD
1833+{
1834+ return acl_delete_def_file((char *)name);
1835+}
1836+
0f6733d8 1837+int sys_acl_free_text(char *text)
fa26e11c 1838+{
0f6733d8
WD
1839+ /*
1840+ * (void) cast and explicit return 0 are for DEC UNIX
1841+ * which just #defines acl_free_text() to be free()
1842+ */
fa26e11c
WD
1843+ (void) acl_free_text(text);
1844+ return 0;
1845+}
1846+
0f6733d8 1847+int sys_acl_free_acl(SMB_ACL_T the_acl)
fa26e11c
WD
1848+{
1849+ return acl_free(the_acl);
1850+}
1851+
0f6733d8 1852+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
fa26e11c
WD
1853+{
1854+ return acl_free_qualifier(qual, tagtype);
1855+}
1856+
1857+#elif defined(HAVE_UNIXWARE_ACLS) || defined(HAVE_SOLARIS_ACLS)
1858+
0f6733d8
WD
1859+/*
1860+ * Donated by Michael Davidson <md@sco.COM> for UnixWare / OpenUNIX.
1861+ * Modified by Toomas Soome <tsoome@ut.ee> for Solaris.
1862+ */
fa26e11c 1863+
0f6733d8
WD
1864+/*
1865+ * Note that while this code implements sufficient functionality
fa26e11c
WD
1866+ * to support the sys_acl_* interfaces it does not provide all
1867+ * of the semantics of the POSIX ACL interfaces.
1868+ *
1869+ * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned
1870+ * from a call to sys_acl_get_entry() should not be assumed to be
1871+ * valid after calling any of the following functions, which may
1872+ * reorder the entries in the ACL.
1873+ *
1874+ * sys_acl_valid()
1875+ * sys_acl_set_file()
1876+ * sys_acl_set_fd()
1877+ */
1878+
0f6733d8
WD
1879+/*
1880+ * The only difference between Solaris and UnixWare / OpenUNIX is
1881+ * that the #defines for the ACL operations have different names
1882+ */
fa26e11c
WD
1883+#if defined(HAVE_UNIXWARE_ACLS)
1884+
0f6733d8
WD
1885+#define SETACL ACL_SET
1886+#define GETACL ACL_GET
1887+#define GETACLCNT ACL_CNT
fa26e11c
WD
1888+
1889+#endif
1890+
1891+
0f6733d8 1892+int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
fa26e11c
WD
1893+{
1894+ if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
1895+ errno = EINVAL;
1896+ return -1;
1897+ }
1898+
1899+ if (entry_p == NULL) {
1900+ errno = EINVAL;
1901+ return -1;
1902+ }
1903+
1904+ if (entry_id == SMB_ACL_FIRST_ENTRY) {
1905+ acl_d->next = 0;
1906+ }
1907+
1908+ if (acl_d->next < 0) {
1909+ errno = EINVAL;
1910+ return -1;
1911+ }
1912+
1913+ if (acl_d->next >= acl_d->count) {
1914+ return 0;
1915+ }
1916+
1917+ *entry_p = &acl_d->acl[acl_d->next++];
1918+
1919+ return 1;
1920+}
1921+
0f6733d8 1922+int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
fa26e11c
WD
1923+{
1924+ *type_p = entry_d->a_type;
1925+
1926+ return 0;
1927+}
1928+
0f6733d8 1929+int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
fa26e11c
WD
1930+{
1931+ *permset_p = &entry_d->a_perm;
1932+
1933+ return 0;
1934+}
1935+
0f6733d8 1936+void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
fa26e11c
WD
1937+{
1938+ if (entry_d->a_type != SMB_ACL_USER
1939+ && entry_d->a_type != SMB_ACL_GROUP) {
1940+ errno = EINVAL;
1941+ return NULL;
1942+ }
1943+
1944+ return &entry_d->a_id;
1945+}
1946+
0f6733d8
WD
1947+/*
1948+ * There is no way of knowing what size the ACL returned by
fa26e11c
WD
1949+ * GETACL will be unless you first call GETACLCNT which means
1950+ * making an additional system call.
1951+ *
1952+ * In the hope of avoiding the cost of the additional system
1953+ * call in most cases, we initially allocate enough space for
1954+ * an ACL with INITIAL_ACL_SIZE entries. If this turns out to
1955+ * be too small then we use GETACLCNT to find out the actual
0f6733d8
WD
1956+ * size, reallocate the ACL buffer, and then call GETACL again.
1957+ */
fa26e11c 1958+
0f6733d8 1959+#define INITIAL_ACL_SIZE 16
fa26e11c 1960+
0f6733d8 1961+SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
fa26e11c 1962+{
0f6733d8
WD
1963+ SMB_ACL_T acl_d;
1964+ int count; /* # of ACL entries allocated */
1965+ int naccess; /* # of access ACL entries */
1966+ int ndefault; /* # of default ACL entries */
fa26e11c
WD
1967+
1968+ if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
1969+ errno = EINVAL;
1970+ return NULL;
1971+ }
1972+
1973+ count = INITIAL_ACL_SIZE;
1974+ if ((acl_d = sys_acl_init(count)) == NULL) {
1975+ return NULL;
1976+ }
1977+
0f6733d8
WD
1978+ /*
1979+ * If there isn't enough space for the ACL entries we use
fa26e11c
WD
1980+ * GETACLCNT to determine the actual number of ACL entries
1981+ * reallocate and try again. This is in a loop because it
1982+ * is possible that someone else could modify the ACL and
1983+ * increase the number of entries between the call to
0f6733d8
WD
1984+ * GETACLCNT and the call to GETACL.
1985+ */
fa26e11c
WD
1986+ while ((count = acl(path_p, GETACL, count, &acl_d->acl[0])) < 0
1987+ && errno == ENOSPC) {
1988+
1989+ sys_acl_free_acl(acl_d);
1990+
1991+ if ((count = acl(path_p, GETACLCNT, 0, NULL)) < 0) {
1992+ return NULL;
1993+ }
1994+
1995+ if ((acl_d = sys_acl_init(count)) == NULL) {
1996+ return NULL;
1997+ }
1998+ }
1999+
2000+ if (count < 0) {
2001+ sys_acl_free_acl(acl_d);
2002+ return NULL;
2003+ }
2004+
0f6733d8
WD
2005+ /*
2006+ * calculate the number of access and default ACL entries
fa26e11c
WD
2007+ *
2008+ * Note: we assume that the acl() system call returned a
2009+ * well formed ACL which is sorted so that all of the
0f6733d8
WD
2010+ * access ACL entries preceed any default ACL entries
2011+ */
fa26e11c
WD
2012+ for (naccess = 0; naccess < count; naccess++) {
2013+ if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
2014+ break;
2015+ }
2016+ ndefault = count - naccess;
0f6733d8
WD
2017+
2018+ /*
2019+ * if the caller wants the default ACL we have to copy
fa26e11c 2020+ * the entries down to the start of the acl[] buffer
0f6733d8
WD
2021+ * and mask out the ACL_DEFAULT flag from the type field
2022+ */
fa26e11c 2023+ if (type == SMB_ACL_TYPE_DEFAULT) {
0f6733d8 2024+ int i, j;
fa26e11c
WD
2025+
2026+ for (i = 0, j = naccess; i < ndefault; i++, j++) {
2027+ acl_d->acl[i] = acl_d->acl[j];
2028+ acl_d->acl[i].a_type &= ~ACL_DEFAULT;
2029+ }
2030+
2031+ acl_d->count = ndefault;
2032+ } else {
2033+ acl_d->count = naccess;
2034+ }
2035+
2036+ return acl_d;
2037+}
2038+
0f6733d8 2039+SMB_ACL_T sys_acl_get_fd(int fd)
fa26e11c 2040+{
0f6733d8
WD
2041+ SMB_ACL_T acl_d;
2042+ int count; /* # of ACL entries allocated */
2043+ int naccess; /* # of access ACL entries */
fa26e11c
WD
2044+
2045+ count = INITIAL_ACL_SIZE;
2046+ if ((acl_d = sys_acl_init(count)) == NULL) {
2047+ return NULL;
2048+ }
2049+
2050+ while ((count = facl(fd, GETACL, count, &acl_d->acl[0])) < 0
2051+ && errno == ENOSPC) {
2052+
2053+ sys_acl_free_acl(acl_d);
2054+
2055+ if ((count = facl(fd, GETACLCNT, 0, NULL)) < 0) {
2056+ return NULL;
2057+ }
2058+
2059+ if ((acl_d = sys_acl_init(count)) == NULL) {
2060+ return NULL;
2061+ }
2062+ }
2063+
2064+ if (count < 0) {
2065+ sys_acl_free_acl(acl_d);
2066+ return NULL;
2067+ }
2068+
0f6733d8
WD
2069+ /*
2070+ * calculate the number of access ACL entries
2071+ */
fa26e11c
WD
2072+ for (naccess = 0; naccess < count; naccess++) {
2073+ if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
2074+ break;
2075+ }
0f6733d8 2076+
fa26e11c
WD
2077+ acl_d->count = naccess;
2078+
2079+ return acl_d;
2080+}
2081+
0f6733d8 2082+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
fa26e11c
WD
2083+{
2084+ *permset_d = 0;
2085+
2086+ return 0;
2087+}
2088+
0f6733d8 2089+int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
fa26e11c
WD
2090+{
2091+ if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
2092+ && perm != SMB_ACL_EXECUTE) {
2093+ errno = EINVAL;
2094+ return -1;
2095+ }
2096+
2097+ if (permset_d == NULL) {
2098+ errno = EINVAL;
2099+ return -1;
2100+ }
2101+
2102+ *permset_d |= perm;
2103+
2104+ return 0;
2105+}
2106+
0f6733d8 2107+int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
fa26e11c
WD
2108+{
2109+ return *permset_d & perm;
2110+}
2111+
0f6733d8 2112+char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p)
fa26e11c 2113+{
0f6733d8
WD
2114+ int i;
2115+ int len, maxlen;
2116+ char *text;
fa26e11c 2117+
0f6733d8
WD
2118+ /*
2119+ * use an initial estimate of 20 bytes per ACL entry
fa26e11c 2120+ * when allocating memory for the text representation
0f6733d8
WD
2121+ * of the ACL
2122+ */
2123+ len = 0;
2124+ maxlen = 20 * acl_d->count;
252945ef 2125+ if ((text = SMB_MALLOC(maxlen)) == NULL) {
fa26e11c
WD
2126+ errno = ENOMEM;
2127+ return NULL;
2128+ }
2129+
2130+ for (i = 0; i < acl_d->count; i++) {
0f6733d8
WD
2131+ struct acl *ap = &acl_d->acl[i];
2132+ struct passwd *pw;
2133+ struct group *gr;
2134+ char tagbuf[12];
2135+ char idbuf[12];
2136+ char *tag;
2137+ char *id = "";
2138+ char perms[4];
2139+ int nbytes;
fa26e11c
WD
2140+
2141+ switch (ap->a_type) {
0f6733d8
WD
2142+ /*
2143+ * for debugging purposes it's probably more
fa26e11c 2144+ * useful to dump unknown tag types rather
0f6733d8
WD
2145+ * than just returning an error
2146+ */
fa26e11c 2147+ default:
0f6733d8 2148+ slprintf(tagbuf, sizeof(tagbuf)-1, "0x%x",
fa26e11c
WD
2149+ ap->a_type);
2150+ tag = tagbuf;
0f6733d8 2151+ slprintf(idbuf, sizeof(idbuf)-1, "%ld",
fa26e11c
WD
2152+ (long)ap->a_id);
2153+ id = idbuf;
2154+ break;
2155+
2156+ case SMB_ACL_USER:
5ca9317d 2157+ id = uidtoname(ap->a_id);
fa26e11c
WD
2158+ case SMB_ACL_USER_OBJ:
2159+ tag = "user";
2160+ break;
2161+
2162+ case SMB_ACL_GROUP:
2163+ if ((gr = getgrgid(ap->a_id)) == NULL) {
0f6733d8 2164+ slprintf(idbuf, sizeof(idbuf)-1, "%ld",
fa26e11c
WD
2165+ (long)ap->a_id);
2166+ id = idbuf;
2167+ } else {
2168+ id = gr->gr_name;
2169+ }
2170+ case SMB_ACL_GROUP_OBJ:
2171+ tag = "group";
2172+ break;
2173+
2174+ case SMB_ACL_OTHER:
2175+ tag = "other";
2176+ break;
2177+
2178+ case SMB_ACL_MASK:
2179+ tag = "mask";
2180+ break;
2181+
2182+ }
2183+
2184+ perms[0] = (ap->a_perm & SMB_ACL_READ) ? 'r' : '-';
2185+ perms[1] = (ap->a_perm & SMB_ACL_WRITE) ? 'w' : '-';
2186+ perms[2] = (ap->a_perm & SMB_ACL_EXECUTE) ? 'x' : '-';
2187+ perms[3] = '\0';
2188+
2189+ /* <tag> : <qualifier> : rwx \n \0 */
2190+ nbytes = strlen(tag) + 1 + strlen(id) + 1 + 3 + 1 + 1;
2191+
0f6733d8
WD
2192+ /*
2193+ * If this entry would overflow the buffer
fa26e11c
WD
2194+ * allocate enough additional memory for this
2195+ * entry and an estimate of another 20 bytes
0f6733d8
WD
2196+ * for each entry still to be processed
2197+ */
fa26e11c
WD
2198+ if ((len + nbytes) > maxlen) {
2199+ char *oldtext = text;
2200+
2201+ maxlen += nbytes + 20 * (acl_d->count - i);
2202+
252945ef 2203+ if ((text = SMB_REALLOC(oldtext, maxlen)) == NULL) {
0f6733d8 2204+ SAFE_FREE(oldtext);
fa26e11c
WD
2205+ errno = ENOMEM;
2206+ return NULL;
2207+ }
2208+ }
2209+
0f6733d8 2210+ slprintf(&text[len], nbytes-1, "%s:%s:%s\n", tag, id, perms);
fa26e11c
WD
2211+ len += nbytes - 1;
2212+ }
2213+
2214+ if (len_p)
2215+ *len_p = len;
2216+
2217+ return text;
2218+}
2219+
0f6733d8 2220+SMB_ACL_T sys_acl_init(int count)
fa26e11c 2221+{
0f6733d8 2222+ SMB_ACL_T a;
fa26e11c
WD
2223+
2224+ if (count < 0) {
2225+ errno = EINVAL;
2226+ return NULL;
2227+ }
2228+
0f6733d8
WD
2229+ /*
2230+ * note that since the definition of the structure pointed
fa26e11c
WD
2231+ * to by the SMB_ACL_T includes the first element of the
2232+ * acl[] array, this actually allocates an ACL with room
0f6733d8
WD
2233+ * for (count+1) entries
2234+ */
252945ef 2235+ if ((a = SMB_MALLOC(sizeof(struct SMB_ACL_T) + count * sizeof(struct acl))) == NULL) {
fa26e11c
WD
2236+ errno = ENOMEM;
2237+ return NULL;
2238+ }
2239+
2240+ a->size = count + 1;
2241+ a->count = 0;
2242+ a->next = -1;
2243+
2244+ return a;
2245+}
2246+
2247+
0f6733d8 2248+int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
fa26e11c 2249+{
0f6733d8
WD
2250+ SMB_ACL_T acl_d;
2251+ SMB_ACL_ENTRY_T entry_d;
fa26e11c
WD
2252+
2253+ if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
2254+ errno = EINVAL;
2255+ return -1;
2256+ }
2257+
2258+ if (acl_d->count >= acl_d->size) {
2259+ errno = ENOSPC;
2260+ return -1;
2261+ }
2262+
0f6733d8
WD
2263+ entry_d = &acl_d->acl[acl_d->count++];
2264+ entry_d->a_type = 0;
2265+ entry_d->a_id = -1;
2266+ entry_d->a_perm = 0;
2267+ *entry_p = entry_d;
fa26e11c
WD
2268+
2269+ return 0;
2270+}
2271+
0f6733d8 2272+int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
fa26e11c
WD
2273+{
2274+ switch (tag_type) {
2275+ case SMB_ACL_USER:
2276+ case SMB_ACL_USER_OBJ:
2277+ case SMB_ACL_GROUP:
2278+ case SMB_ACL_GROUP_OBJ:
2279+ case SMB_ACL_OTHER:
2280+ case SMB_ACL_MASK:
2281+ entry_d->a_type = tag_type;
2282+ break;
2283+ default:
2284+ errno = EINVAL;
2285+ return -1;
2286+ }
2287+
2288+ return 0;
2289+}
2290+
0f6733d8 2291+int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
fa26e11c
WD
2292+{
2293+ if (entry_d->a_type != SMB_ACL_GROUP
2294+ && entry_d->a_type != SMB_ACL_USER) {
2295+ errno = EINVAL;
2296+ return -1;
2297+ }
2298+
2299+ entry_d->a_id = *((id_t *)qual_p);
2300+
2301+ return 0;
2302+}
2303+
0f6733d8 2304+int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
fa26e11c
WD
2305+{
2306+ if (*permset_d & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
2307+ return EINVAL;
2308+ }
2309+
2310+ entry_d->a_perm = *permset_d;
2311+
2312+ return 0;
2313+}
2314+
0f6733d8
WD
2315+/*
2316+ * sort the ACL and check it for validity
fa26e11c 2317+ *
0f6733d8 2318+ * if it's a minimal ACL with only 4 entries then we
fa26e11c
WD
2319+ * need to recalculate the mask permissions to make
2320+ * sure that they are the same as the GROUP_OBJ
2321+ * permissions as required by the UnixWare acl() system call.
2322+ *
0f6733d8 2323+ * (note: since POSIX allows minimal ACLs which only contain
fa26e11c
WD
2324+ * 3 entries - ie there is no mask entry - we should, in theory,
2325+ * check for this and add a mask entry if necessary - however
2326+ * we "know" that the caller of this interface always specifies
2327+ * a mask so, in practice "this never happens" (tm) - if it *does*
2328+ * happen aclsort() will fail and return an error and someone will
0f6733d8
WD
2329+ * have to fix it ...)
2330+ */
fa26e11c
WD
2331+
2332+static int acl_sort(SMB_ACL_T acl_d)
2333+{
2334+ int fixmask = (acl_d->count <= 4);
2335+
2336+ if (aclsort(acl_d->count, fixmask, acl_d->acl) != 0) {
2337+ errno = EINVAL;
2338+ return -1;
2339+ }
2340+ return 0;
2341+}
0f6733d8
WD
2342+
2343+int sys_acl_valid(SMB_ACL_T acl_d)
fa26e11c
WD
2344+{
2345+ return acl_sort(acl_d);
2346+}
2347+
0f6733d8 2348+int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
fa26e11c 2349+{
0f6733d8
WD
2350+ struct stat s;
2351+ struct acl *acl_p;
2352+ int acl_count;
2353+ struct acl *acl_buf = NULL;
2354+ int ret;
fa26e11c
WD
2355+
2356+ if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
2357+ errno = EINVAL;
2358+ return -1;
2359+ }
2360+
2361+ if (acl_sort(acl_d) != 0) {
2362+ return -1;
2363+ }
2364+
0f6733d8
WD
2365+ acl_p = &acl_d->acl[0];
2366+ acl_count = acl_d->count;
fa26e11c 2367+
0f6733d8
WD
2368+ /*
2369+ * if it's a directory there is extra work to do
2370+ * since the acl() system call will replace both
2371+ * the access ACLs and the default ACLs (if any)
2372+ */
fa26e11c
WD
2373+ if (stat(name, &s) != 0) {
2374+ return -1;
2375+ }
2376+ if (S_ISDIR(s.st_mode)) {
0f6733d8
WD
2377+ SMB_ACL_T acc_acl;
2378+ SMB_ACL_T def_acl;
2379+ SMB_ACL_T tmp_acl;
2380+ int i;
fa26e11c
WD
2381+
2382+ if (type == SMB_ACL_TYPE_ACCESS) {
2383+ acc_acl = acl_d;
2384+ def_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT);
2385+
2386+ } else {
2387+ def_acl = acl_d;
2388+ acc_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS);
2389+ }
2390+
2391+ if (tmp_acl == NULL) {
2392+ return -1;
2393+ }
2394+
0f6733d8
WD
2395+ /*
2396+ * allocate a temporary buffer for the complete ACL
2397+ */
fa26e11c 2398+ acl_count = acc_acl->count + def_acl->count;
252945ef 2399+ acl_p = acl_buf = SMB_MALLOC_ARRAY(struct acl, acl_count);
fa26e11c
WD
2400+
2401+ if (acl_buf == NULL) {
2402+ sys_acl_free_acl(tmp_acl);
2403+ errno = ENOMEM;
2404+ return -1;
2405+ }
2406+
0f6733d8
WD
2407+ /*
2408+ * copy the access control and default entries into the buffer
2409+ */
fa26e11c 2410+ memcpy(&acl_buf[0], &acc_acl->acl[0],
0f6733d8 2411+ acc_acl->count * sizeof(acl_buf[0]));
fa26e11c
WD
2412+
2413+ memcpy(&acl_buf[acc_acl->count], &def_acl->acl[0],
0f6733d8 2414+ def_acl->count * sizeof(acl_buf[0]));
fa26e11c 2415+
0f6733d8
WD
2416+ /*
2417+ * set the ACL_DEFAULT flag on the default entries
2418+ */
fa26e11c
WD
2419+ for (i = acc_acl->count; i < acl_count; i++) {
2420+ acl_buf[i].a_type |= ACL_DEFAULT;
2421+ }
2422+
2423+ sys_acl_free_acl(tmp_acl);
2424+
2425+ } else if (type != SMB_ACL_TYPE_ACCESS) {
2426+ errno = EINVAL;
2427+ return -1;
2428+ }
2429+
2430+ ret = acl(name, SETACL, acl_count, acl_p);
2431+
0f6733d8 2432+ SAFE_FREE(acl_buf);
fa26e11c
WD
2433+
2434+ return ret;
2435+}
2436+
0f6733d8 2437+int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
fa26e11c
WD
2438+{
2439+ if (acl_sort(acl_d) != 0) {
2440+ return -1;
2441+ }
2442+
2443+ return facl(fd, SETACL, acl_d->count, &acl_d->acl[0]);
2444+}
2445+
0f6733d8 2446+int sys_acl_delete_def_file(const char *path)
fa26e11c 2447+{
0f6733d8
WD
2448+ SMB_ACL_T acl_d;
2449+ int ret;
fa26e11c 2450+
0f6733d8
WD
2451+ /*
2452+ * fetching the access ACL and rewriting it has
2453+ * the effect of deleting the default ACL
2454+ */
fa26e11c
WD
2455+ if ((acl_d = sys_acl_get_file(path, SMB_ACL_TYPE_ACCESS)) == NULL) {
2456+ return -1;
2457+ }
2458+
2459+ ret = acl(path, SETACL, acl_d->count, acl_d->acl);
2460+
2461+ sys_acl_free_acl(acl_d);
0f6733d8 2462+
fa26e11c
WD
2463+ return ret;
2464+}
2465+
0f6733d8 2466+int sys_acl_free_text(char *text)
fa26e11c 2467+{
0f6733d8 2468+ SAFE_FREE(text);
fa26e11c
WD
2469+ return 0;
2470+}
2471+
0f6733d8 2472+int sys_acl_free_acl(SMB_ACL_T acl_d)
fa26e11c 2473+{
0f6733d8 2474+ SAFE_FREE(acl_d);
fa26e11c
WD
2475+ return 0;
2476+}
2477+
0f6733d8 2478+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
fa26e11c
WD
2479+{
2480+ return 0;
2481+}
2482+
2483+#elif defined(HAVE_HPUX_ACLS)
2484+#include <dl.h>
2485+
0f6733d8
WD
2486+/*
2487+ * Based on the Solaris/SCO code - with modifications.
2488+ */
fa26e11c 2489+
0f6733d8
WD
2490+/*
2491+ * Note that while this code implements sufficient functionality
fa26e11c
WD
2492+ * to support the sys_acl_* interfaces it does not provide all
2493+ * of the semantics of the POSIX ACL interfaces.
2494+ *
2495+ * In particular, an ACL entry descriptor (SMB_ACL_ENTRY_T) returned
2496+ * from a call to sys_acl_get_entry() should not be assumed to be
2497+ * valid after calling any of the following functions, which may
2498+ * reorder the entries in the ACL.
2499+ *
2500+ * sys_acl_valid()
2501+ * sys_acl_set_file()
2502+ * sys_acl_set_fd()
2503+ */
2504+
0f6733d8
WD
2505+/* This checks if the POSIX ACL system call is defined */
2506+/* which basically corresponds to whether JFS 3.3 or */
2507+/* higher is installed. If acl() was called when it */
2508+/* isn't defined, it causes the process to core dump */
2509+/* so it is important to check this and avoid acl() */
2510+/* calls if it isn't there. */
fa26e11c
WD
2511+
2512+static BOOL hpux_acl_call_presence(void)
2513+{
2514+
2515+ shl_t handle = NULL;
2516+ void *value;
2517+ int ret_val=0;
2518+ static BOOL already_checked=0;
2519+
0f6733d8 2520+ if(already_checked)
fa26e11c
WD
2521+ return True;
2522+
2523+
2524+ ret_val = shl_findsym(&handle, "acl", TYPE_PROCEDURE, &value);
2525+
0f6733d8 2526+ if(ret_val != 0) {
fa26e11c
WD
2527+ DEBUG(5, ("hpux_acl_call_presence: shl_findsym() returned %d, errno = %d, error %s\n",
2528+ ret_val, errno, strerror(errno)));
2529+ DEBUG(5,("hpux_acl_call_presence: acl() system call is not present. Check if you have JFS 3.3 and above?\n"));
2530+ return False;
2531+ }
2532+
2533+ DEBUG(10,("hpux_acl_call_presence: acl() system call is present. We have JFS 3.3 or above \n"));
2534+
2535+ already_checked = True;
2536+ return True;
2537+}
2538+
0f6733d8 2539+int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
fa26e11c
WD
2540+{
2541+ if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
2542+ errno = EINVAL;
2543+ return -1;
2544+ }
2545+
2546+ if (entry_p == NULL) {
2547+ errno = EINVAL;
2548+ return -1;
2549+ }
2550+
2551+ if (entry_id == SMB_ACL_FIRST_ENTRY) {
2552+ acl_d->next = 0;
2553+ }
2554+
2555+ if (acl_d->next < 0) {
2556+ errno = EINVAL;
2557+ return -1;
2558+ }
2559+
2560+ if (acl_d->next >= acl_d->count) {
2561+ return 0;
2562+ }
2563+
2564+ *entry_p = &acl_d->acl[acl_d->next++];
2565+
2566+ return 1;
2567+}
2568+
0f6733d8 2569+int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
fa26e11c
WD
2570+{
2571+ *type_p = entry_d->a_type;
2572+
2573+ return 0;
2574+}
2575+
0f6733d8 2576+int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
fa26e11c
WD
2577+{
2578+ *permset_p = &entry_d->a_perm;
2579+
2580+ return 0;
2581+}
2582+
0f6733d8 2583+void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
fa26e11c
WD
2584+{
2585+ if (entry_d->a_type != SMB_ACL_USER
2586+ && entry_d->a_type != SMB_ACL_GROUP) {
2587+ errno = EINVAL;
2588+ return NULL;
2589+ }
2590+
2591+ return &entry_d->a_id;
2592+}
2593+
0f6733d8
WD
2594+/*
2595+ * There is no way of knowing what size the ACL returned by
fa26e11c
WD
2596+ * ACL_GET will be unless you first call ACL_CNT which means
2597+ * making an additional system call.
2598+ *
2599+ * In the hope of avoiding the cost of the additional system
2600+ * call in most cases, we initially allocate enough space for
2601+ * an ACL with INITIAL_ACL_SIZE entries. If this turns out to
2602+ * be too small then we use ACL_CNT to find out the actual
2603+ * size, reallocate the ACL buffer, and then call ACL_GET again.
2604+ */
2605+
0f6733d8 2606+#define INITIAL_ACL_SIZE 16
fa26e11c 2607+
0f6733d8 2608+SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
fa26e11c 2609+{
0f6733d8
WD
2610+ SMB_ACL_T acl_d;
2611+ int count; /* # of ACL entries allocated */
2612+ int naccess; /* # of access ACL entries */
2613+ int ndefault; /* # of default ACL entries */
fa26e11c 2614+
0f6733d8
WD
2615+ if(hpux_acl_call_presence() == False) {
2616+ /* Looks like we don't have the acl() system call on HPUX.
2617+ * May be the system doesn't have the latest version of JFS.
2618+ */
2619+ return NULL;
fa26e11c
WD
2620+ }
2621+
2622+ if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
2623+ errno = EINVAL;
2624+ return NULL;
2625+ }
2626+
2627+ count = INITIAL_ACL_SIZE;
2628+ if ((acl_d = sys_acl_init(count)) == NULL) {
2629+ return NULL;
2630+ }
2631+
0f6733d8
WD
2632+ /*
2633+ * If there isn't enough space for the ACL entries we use
fa26e11c
WD
2634+ * ACL_CNT to determine the actual number of ACL entries
2635+ * reallocate and try again. This is in a loop because it
2636+ * is possible that someone else could modify the ACL and
2637+ * increase the number of entries between the call to
0f6733d8
WD
2638+ * ACL_CNT and the call to ACL_GET.
2639+ */
fa26e11c
WD
2640+ while ((count = acl(path_p, ACL_GET, count, &acl_d->acl[0])) < 0 && errno == ENOSPC) {
2641+
2642+ sys_acl_free_acl(acl_d);
2643+
2644+ if ((count = acl(path_p, ACL_CNT, 0, NULL)) < 0) {
2645+ return NULL;
2646+ }
2647+
2648+ if ((acl_d = sys_acl_init(count)) == NULL) {
2649+ return NULL;
2650+ }
2651+ }
2652+
2653+ if (count < 0) {
2654+ sys_acl_free_acl(acl_d);
2655+ return NULL;
2656+ }
2657+
0f6733d8
WD
2658+ /*
2659+ * calculate the number of access and default ACL entries
fa26e11c
WD
2660+ *
2661+ * Note: we assume that the acl() system call returned a
2662+ * well formed ACL which is sorted so that all of the
0f6733d8
WD
2663+ * access ACL entries preceed any default ACL entries
2664+ */
fa26e11c
WD
2665+ for (naccess = 0; naccess < count; naccess++) {
2666+ if (acl_d->acl[naccess].a_type & ACL_DEFAULT)
2667+ break;
2668+ }
2669+ ndefault = count - naccess;
0f6733d8
WD
2670+
2671+ /*
2672+ * if the caller wants the default ACL we have to copy
fa26e11c 2673+ * the entries down to the start of the acl[] buffer
0f6733d8
WD
2674+ * and mask out the ACL_DEFAULT flag from the type field
2675+ */
fa26e11c 2676+ if (type == SMB_ACL_TYPE_DEFAULT) {
0f6733d8 2677+ int i, j;
fa26e11c
WD
2678+
2679+ for (i = 0, j = naccess; i < ndefault; i++, j++) {
2680+ acl_d->acl[i] = acl_d->acl[j];
2681+ acl_d->acl[i].a_type &= ~ACL_DEFAULT;
2682+ }
2683+
2684+ acl_d->count = ndefault;
2685+ } else {
2686+ acl_d->count = naccess;
2687+ }
2688+
2689+ return acl_d;
2690+}
2691+
0f6733d8 2692+SMB_ACL_T sys_acl_get_fd(int fd)
fa26e11c 2693+{
0f6733d8
WD
2694+ /*
2695+ * HPUX doesn't have the facl call. Fake it using the path.... JRA.
2696+ */
fa26e11c
WD
2697+
2698+ files_struct *fsp = file_find_fd(fd);
2699+
2700+ if (fsp == NULL) {
2701+ errno = EBADF;
2702+ return NULL;
2703+ }
2704+
0f6733d8
WD
2705+ /*
2706+ * We know we're in the same conn context. So we
2707+ * can use the relative path.
2708+ */
fa26e11c 2709+
5ca9317d 2710+ return sys_acl_get_file(fsp->fsp_name, SMB_ACL_TYPE_ACCESS);
fa26e11c
WD
2711+}
2712+
0f6733d8 2713+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
fa26e11c
WD
2714+{
2715+ *permset_d = 0;
2716+
2717+ return 0;
2718+}
2719+
0f6733d8 2720+int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
fa26e11c
WD
2721+{
2722+ if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
2723+ && perm != SMB_ACL_EXECUTE) {
2724+ errno = EINVAL;
2725+ return -1;
2726+ }
2727+
2728+ if (permset_d == NULL) {
2729+ errno = EINVAL;
2730+ return -1;
2731+ }
2732+
2733+ *permset_d |= perm;
2734+
2735+ return 0;
2736+}
2737+
0f6733d8 2738+int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
fa26e11c
WD
2739+{
2740+ return *permset_d & perm;
2741+}
2742+
0f6733d8 2743+char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p)
fa26e11c 2744+{
0f6733d8
WD
2745+ int i;
2746+ int len, maxlen;
2747+ char *text;
fa26e11c 2748+
0f6733d8
WD
2749+ /*
2750+ * use an initial estimate of 20 bytes per ACL entry
2751+ * when allocating memory for the text representation
2752+ * of the ACL
2753+ */
2754+ len = 0;
2755+ maxlen = 20 * acl_d->count;
252945ef 2756+ if ((text = SMB_MALLOC(maxlen)) == NULL) {
fa26e11c
WD
2757+ errno = ENOMEM;
2758+ return NULL;
2759+ }
2760+
2761+ for (i = 0; i < acl_d->count; i++) {
0f6733d8
WD
2762+ struct acl *ap = &acl_d->acl[i];
2763+ struct passwd *pw;
2764+ struct group *gr;
2765+ char tagbuf[12];
2766+ char idbuf[12];
2767+ char *tag;
2768+ char *id = "";
2769+ char perms[4];
2770+ int nbytes;
fa26e11c
WD
2771+
2772+ switch (ap->a_type) {
0f6733d8
WD
2773+ /*
2774+ * for debugging purposes it's probably more
fa26e11c 2775+ * useful to dump unknown tag types rather
0f6733d8
WD
2776+ * than just returning an error
2777+ */
fa26e11c 2778+ default:
0f6733d8 2779+ slprintf(tagbuf, sizeof(tagbuf)-1, "0x%x",
fa26e11c
WD
2780+ ap->a_type);
2781+ tag = tagbuf;
0f6733d8 2782+ slprintf(idbuf, sizeof(idbuf)-1, "%ld",
fa26e11c
WD
2783+ (long)ap->a_id);
2784+ id = idbuf;
2785+ break;
2786+
2787+ case SMB_ACL_USER:
5ca9317d 2788+ id = uidtoname(ap->a_id);
fa26e11c
WD
2789+ case SMB_ACL_USER_OBJ:
2790+ tag = "user";
2791+ break;
2792+
2793+ case SMB_ACL_GROUP:
2794+ if ((gr = getgrgid(ap->a_id)) == NULL) {
0f6733d8 2795+ slprintf(idbuf, sizeof(idbuf)-1, "%ld",
fa26e11c
WD
2796+ (long)ap->a_id);
2797+ id = idbuf;
2798+ } else {
2799+ id = gr->gr_name;
2800+ }
2801+ case SMB_ACL_GROUP_OBJ:
2802+ tag = "group";
2803+ break;
2804+
2805+ case SMB_ACL_OTHER:
2806+ tag = "other";
2807+ break;
2808+
2809+ case SMB_ACL_MASK:
2810+ tag = "mask";
2811+ break;
2812+
2813+ }
2814+
2815+ perms[0] = (ap->a_perm & SMB_ACL_READ) ? 'r' : '-';
2816+ perms[1] = (ap->a_perm & SMB_ACL_WRITE) ? 'w' : '-';
2817+ perms[2] = (ap->a_perm & SMB_ACL_EXECUTE) ? 'x' : '-';
2818+ perms[3] = '\0';
2819+
2820+ /* <tag> : <qualifier> : rwx \n \0 */
2821+ nbytes = strlen(tag) + 1 + strlen(id) + 1 + 3 + 1 + 1;
2822+
0f6733d8
WD
2823+ /*
2824+ * If this entry would overflow the buffer
fa26e11c
WD
2825+ * allocate enough additional memory for this
2826+ * entry and an estimate of another 20 bytes
0f6733d8
WD
2827+ * for each entry still to be processed
2828+ */
fa26e11c
WD
2829+ if ((len + nbytes) > maxlen) {
2830+ char *oldtext = text;
2831+
2832+ maxlen += nbytes + 20 * (acl_d->count - i);
2833+
252945ef 2834+ if ((text = SMB_REALLOC(oldtext, maxlen)) == NULL) {
fa26e11c
WD
2835+ free(oldtext);
2836+ errno = ENOMEM;
2837+ return NULL;
2838+ }
2839+ }
2840+
0f6733d8 2841+ slprintf(&text[len], nbytes-1, "%s:%s:%s\n", tag, id, perms);
fa26e11c
WD
2842+ len += nbytes - 1;
2843+ }
2844+
2845+ if (len_p)
2846+ *len_p = len;
2847+
2848+ return text;
2849+}
2850+
0f6733d8 2851+SMB_ACL_T sys_acl_init(int count)
fa26e11c 2852+{
0f6733d8 2853+ SMB_ACL_T a;
fa26e11c
WD
2854+
2855+ if (count < 0) {
2856+ errno = EINVAL;
2857+ return NULL;
2858+ }
2859+
0f6733d8
WD
2860+ /*
2861+ * note that since the definition of the structure pointed
fa26e11c
WD
2862+ * to by the SMB_ACL_T includes the first element of the
2863+ * acl[] array, this actually allocates an ACL with room
0f6733d8
WD
2864+ * for (count+1) entries
2865+ */
252945ef 2866+ if ((a = SMB_MALLOC(sizeof(struct SMB_ACL_T) + count * sizeof(struct acl))) == NULL) {
fa26e11c
WD
2867+ errno = ENOMEM;
2868+ return NULL;
2869+ }
2870+
2871+ a->size = count + 1;
2872+ a->count = 0;
2873+ a->next = -1;
2874+
2875+ return a;
2876+}
2877+
2878+
0f6733d8 2879+int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
fa26e11c 2880+{
0f6733d8
WD
2881+ SMB_ACL_T acl_d;
2882+ SMB_ACL_ENTRY_T entry_d;
fa26e11c
WD
2883+
2884+ if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
2885+ errno = EINVAL;
2886+ return -1;
2887+ }
2888+
2889+ if (acl_d->count >= acl_d->size) {
2890+ errno = ENOSPC;
2891+ return -1;
2892+ }
2893+
0f6733d8
WD
2894+ entry_d = &acl_d->acl[acl_d->count++];
2895+ entry_d->a_type = 0;
2896+ entry_d->a_id = -1;
2897+ entry_d->a_perm = 0;
2898+ *entry_p = entry_d;
fa26e11c
WD
2899+
2900+ return 0;
2901+}
2902+
0f6733d8 2903+int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
fa26e11c
WD
2904+{
2905+ switch (tag_type) {
2906+ case SMB_ACL_USER:
2907+ case SMB_ACL_USER_OBJ:
2908+ case SMB_ACL_GROUP:
2909+ case SMB_ACL_GROUP_OBJ:
2910+ case SMB_ACL_OTHER:
2911+ case SMB_ACL_MASK:
2912+ entry_d->a_type = tag_type;
2913+ break;
2914+ default:
2915+ errno = EINVAL;
2916+ return -1;
2917+ }
2918+
2919+ return 0;
2920+}
2921+
0f6733d8 2922+int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
fa26e11c
WD
2923+{
2924+ if (entry_d->a_type != SMB_ACL_GROUP
2925+ && entry_d->a_type != SMB_ACL_USER) {
2926+ errno = EINVAL;
2927+ return -1;
2928+ }
2929+
2930+ entry_d->a_id = *((id_t *)qual_p);
2931+
2932+ return 0;
2933+}
2934+
0f6733d8 2935+int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
fa26e11c
WD
2936+{
2937+ if (*permset_d & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
2938+ return EINVAL;
2939+ }
2940+
2941+ entry_d->a_perm = *permset_d;
2942+
2943+ return 0;
2944+}
2945+
2946+/* Structure to capture the count for each type of ACE. */
2947+
2948+struct hpux_acl_types {
2949+ int n_user;
2950+ int n_def_user;
2951+ int n_user_obj;
2952+ int n_def_user_obj;
2953+
2954+ int n_group;
2955+ int n_def_group;
2956+ int n_group_obj;
2957+ int n_def_group_obj;
2958+
2959+ int n_other;
2960+ int n_other_obj;
2961+ int n_def_other_obj;
2962+
2963+ int n_class_obj;
2964+ int n_def_class_obj;
2965+
2966+ int n_illegal_obj;
2967+};
2968+
2969+/* count_obj:
2970+ * Counts the different number of objects in a given array of ACL
2971+ * structures.
2972+ * Inputs:
2973+ *
2974+ * acl_count - Count of ACLs in the array of ACL strucutres.
2975+ * aclp - Array of ACL structures.
2976+ * acl_type_count - Pointer to acl_types structure. Should already be
2977+ * allocated.
0f6733d8 2978+ * Output:
fa26e11c 2979+ *
0f6733d8 2980+ * acl_type_count - This structure is filled up with counts of various
fa26e11c
WD
2981+ * acl types.
2982+ */
2983+
2984+static int hpux_count_obj(int acl_count, struct acl *aclp, struct hpux_acl_types *acl_type_count)
2985+{
2986+ int i;
2987+
0f6733d8 2988+ memset(acl_type_count, 0, sizeof(struct hpux_acl_types));
fa26e11c 2989+
0f6733d8
WD
2990+ for(i=0;i<acl_count;i++) {
2991+ switch(aclp[i].a_type) {
2992+ case USER:
fa26e11c
WD
2993+ acl_type_count->n_user++;
2994+ break;
0f6733d8 2995+ case USER_OBJ:
fa26e11c
WD
2996+ acl_type_count->n_user_obj++;
2997+ break;
0f6733d8 2998+ case DEF_USER_OBJ:
fa26e11c
WD
2999+ acl_type_count->n_def_user_obj++;
3000+ break;
0f6733d8 3001+ case GROUP:
fa26e11c
WD
3002+ acl_type_count->n_group++;
3003+ break;
0f6733d8 3004+ case GROUP_OBJ:
fa26e11c
WD
3005+ acl_type_count->n_group_obj++;
3006+ break;
0f6733d8 3007+ case DEF_GROUP_OBJ:
fa26e11c
WD
3008+ acl_type_count->n_def_group_obj++;
3009+ break;
0f6733d8 3010+ case OTHER_OBJ:
fa26e11c
WD
3011+ acl_type_count->n_other_obj++;
3012+ break;
0f6733d8 3013+ case DEF_OTHER_OBJ:
fa26e11c
WD
3014+ acl_type_count->n_def_other_obj++;
3015+ break;
3016+ case CLASS_OBJ:
3017+ acl_type_count->n_class_obj++;
3018+ break;
3019+ case DEF_CLASS_OBJ:
3020+ acl_type_count->n_def_class_obj++;
3021+ break;
3022+ case DEF_USER:
3023+ acl_type_count->n_def_user++;
3024+ break;
3025+ case DEF_GROUP:
3026+ acl_type_count->n_def_group++;
3027+ break;
0f6733d8 3028+ default:
fa26e11c
WD
3029+ acl_type_count->n_illegal_obj++;
3030+ break;
3031+ }
3032+ }
3033+}
3034+
0f6733d8 3035+/* swap_acl_entries: Swaps two ACL entries.
fa26e11c
WD
3036+ *
3037+ * Inputs: aclp0, aclp1 - ACL entries to be swapped.
3038+ */
3039+
3040+static void hpux_swap_acl_entries(struct acl *aclp0, struct acl *aclp1)
3041+{
3042+ struct acl temp_acl;
3043+
3044+ temp_acl.a_type = aclp0->a_type;
3045+ temp_acl.a_id = aclp0->a_id;
3046+ temp_acl.a_perm = aclp0->a_perm;
3047+
3048+ aclp0->a_type = aclp1->a_type;
3049+ aclp0->a_id = aclp1->a_id;
3050+ aclp0->a_perm = aclp1->a_perm;
3051+
3052+ aclp1->a_type = temp_acl.a_type;
3053+ aclp1->a_id = temp_acl.a_id;
3054+ aclp1->a_perm = temp_acl.a_perm;
3055+}
3056+
3057+/* prohibited_duplicate_type
0f6733d8 3058+ * Identifies if given ACL type can have duplicate entries or
fa26e11c
WD
3059+ * not.
3060+ *
3061+ * Inputs: acl_type - ACL Type.
3062+ *
0f6733d8 3063+ * Outputs:
fa26e11c 3064+ *
0f6733d8 3065+ * Return..
fa26e11c
WD
3066+ *
3067+ * True - If the ACL type matches any of the prohibited types.
3068+ * False - If the ACL type doesn't match any of the prohibited types.
0f6733d8 3069+ */
fa26e11c
WD
3070+
3071+static BOOL hpux_prohibited_duplicate_type(int acl_type)
3072+{
0f6733d8 3073+ switch(acl_type) {
fa26e11c
WD
3074+ case USER:
3075+ case GROUP:
0f6733d8 3076+ case DEF_USER:
fa26e11c
WD
3077+ case DEF_GROUP:
3078+ return True;
0f6733d8
WD
3079+ default:
3080+ return False;
fa26e11c 3081+ }
fa26e11c
WD
3082+}
3083+
3084+/* get_needed_class_perm
3085+ * Returns the permissions of a ACL structure only if the ACL
0f6733d8 3086+ * type matches one of the pre-determined types for computing
fa26e11c
WD
3087+ * CLASS_OBJ permissions.
3088+ *
3089+ * Inputs: aclp - Pointer to ACL structure.
3090+ */
3091+
3092+static int hpux_get_needed_class_perm(struct acl *aclp)
3093+{
0f6733d8
WD
3094+ switch(aclp->a_type) {
3095+ case USER:
3096+ case GROUP_OBJ:
3097+ case GROUP:
3098+ case DEF_USER_OBJ:
fa26e11c 3099+ case DEF_USER:
0f6733d8 3100+ case DEF_GROUP_OBJ:
fa26e11c
WD
3101+ case DEF_GROUP:
3102+ case DEF_CLASS_OBJ:
0f6733d8 3103+ case DEF_OTHER_OBJ:
fa26e11c 3104+ return aclp->a_perm;
0f6733d8 3105+ default:
fa26e11c
WD
3106+ return 0;
3107+ }
3108+}
3109+
3110+/* acl_sort for HPUX.
3111+ * Sorts the array of ACL structures as per the description in
3112+ * aclsort man page. Refer to aclsort man page for more details
3113+ *
3114+ * Inputs:
3115+ *
3116+ * acl_count - Count of ACLs in the array of ACL structures.
3117+ * calclass - If this is not zero, then we compute the CLASS_OBJ
3118+ * permissions.
3119+ * aclp - Array of ACL structures.
3120+ *
3121+ * Outputs:
3122+ *
3123+ * aclp - Sorted array of ACL structures.
3124+ *
3125+ * Outputs:
3126+ *
3127+ * Returns 0 for success -1 for failure. Prints a message to the Samba
3128+ * debug log in case of failure.
3129+ */
3130+
3131+static int hpux_acl_sort(int acl_count, int calclass, struct acl *aclp)
3132+{
3133+#if !defined(HAVE_HPUX_ACLSORT)
0f6733d8
WD
3134+ /*
3135+ * The aclsort() system call is availabe on the latest HPUX General
3136+ * Patch Bundles. So for HPUX, we developed our version of acl_sort
3137+ * function. Because, we don't want to update to a new
3138+ * HPUX GR bundle just for aclsort() call.
3139+ */
fa26e11c
WD
3140+
3141+ struct hpux_acl_types acl_obj_count;
3142+ int n_class_obj_perm = 0;
3143+ int i, j;
0f6733d8
WD
3144+
3145+ if(!acl_count) {
fa26e11c
WD
3146+ DEBUG(10,("Zero acl count passed. Returning Success\n"));
3147+ return 0;
3148+ }
3149+
0f6733d8 3150+ if(aclp == NULL) {
fa26e11c
WD
3151+ DEBUG(0,("Null ACL pointer in hpux_acl_sort. Returning Failure. \n"));
3152+ return -1;
3153+ }
3154+
3155+ /* Count different types of ACLs in the ACLs array */
3156+
3157+ hpux_count_obj(acl_count, aclp, &acl_obj_count);
3158+
0f6733d8
WD
3159+ /* There should be only one entry each of type USER_OBJ, GROUP_OBJ,
3160+ * CLASS_OBJ and OTHER_OBJ
fa26e11c
WD
3161+ */
3162+
0f6733d8
WD
3163+ if( (acl_obj_count.n_user_obj != 1) ||
3164+ (acl_obj_count.n_group_obj != 1) ||
3165+ (acl_obj_count.n_class_obj != 1) ||
3166+ (acl_obj_count.n_other_obj != 1)
3167+ ) {
fa26e11c
WD
3168+ DEBUG(0,("hpux_acl_sort: More than one entry or no entries for \
3169+USER OBJ or GROUP_OBJ or OTHER_OBJ or CLASS_OBJ\n"));
3170+ return -1;
3171+ }
3172+
3173+ /* If any of the default objects are present, there should be only
3174+ * one of them each.
3175+ */
3176+
0f6733d8
WD
3177+ if( (acl_obj_count.n_def_user_obj > 1) || (acl_obj_count.n_def_group_obj > 1) ||
3178+ (acl_obj_count.n_def_other_obj > 1) || (acl_obj_count.n_def_class_obj > 1) ) {
fa26e11c
WD
3179+ DEBUG(0,("hpux_acl_sort: More than one entry for DEF_CLASS_OBJ \
3180+or DEF_USER_OBJ or DEF_GROUP_OBJ or DEF_OTHER_OBJ\n"));
3181+ return -1;
3182+ }
3183+
0f6733d8
WD
3184+ /* We now have proper number of OBJ and DEF_OBJ entries. Now sort the acl
3185+ * structures.
fa26e11c
WD
3186+ *
3187+ * Sorting crieteria - First sort by ACL type. If there are multiple entries of
3188+ * same ACL type, sort by ACL id.
3189+ *
0f6733d8 3190+ * I am using the trival kind of sorting method here because, performance isn't
fa26e11c 3191+ * really effected by the ACLs feature. More over there aren't going to be more
0f6733d8 3192+ * than 17 entries on HPUX.
fa26e11c
WD
3193+ */
3194+
0f6733d8 3195+ for(i=0; i<acl_count;i++) {
fa26e11c 3196+ for (j=i+1; j<acl_count; j++) {
0f6733d8 3197+ if( aclp[i].a_type > aclp[j].a_type ) {
fa26e11c
WD
3198+ /* ACL entries out of order, swap them */
3199+
3200+ hpux_swap_acl_entries((aclp+i), (aclp+j));
3201+
0f6733d8 3202+ } else if ( aclp[i].a_type == aclp[j].a_type ) {
fa26e11c
WD
3203+
3204+ /* ACL entries of same type, sort by id */
3205+
0f6733d8 3206+ if(aclp[i].a_id > aclp[j].a_id) {
fa26e11c
WD
3207+ hpux_swap_acl_entries((aclp+i), (aclp+j));
3208+ } else if (aclp[i].a_id == aclp[j].a_id) {
3209+ /* We have a duplicate entry. */
0f6733d8 3210+ if(hpux_prohibited_duplicate_type(aclp[i].a_type)) {
fa26e11c
WD
3211+ DEBUG(0, ("hpux_acl_sort: Duplicate entry: Type(hex): %x Id: %d\n",
3212+ aclp[i].a_type, aclp[i].a_id));
3213+ return -1;
3214+ }
3215+ }
3216+
3217+ }
3218+ }
3219+ }
3220+
3221+ /* set the class obj permissions to the computed one. */
0f6733d8 3222+ if(calclass) {
fa26e11c
WD
3223+ int n_class_obj_index = -1;
3224+
0f6733d8 3225+ for(i=0;i<acl_count;i++) {
fa26e11c
WD
3226+ n_class_obj_perm |= hpux_get_needed_class_perm((aclp+i));
3227+
0f6733d8 3228+ if(aclp[i].a_type == CLASS_OBJ)
fa26e11c
WD
3229+ n_class_obj_index = i;
3230+ }
3231+ aclp[n_class_obj_index].a_perm = n_class_obj_perm;
3232+ }
3233+
3234+ return 0;
3235+#else
3236+ return aclsort(acl_count, calclass, aclp);
3237+#endif
3238+}
3239+
0f6733d8
WD
3240+/*
3241+ * sort the ACL and check it for validity
fa26e11c 3242+ *
0f6733d8 3243+ * if it's a minimal ACL with only 4 entries then we
fa26e11c
WD
3244+ * need to recalculate the mask permissions to make
3245+ * sure that they are the same as the GROUP_OBJ
3246+ * permissions as required by the UnixWare acl() system call.
3247+ *
0f6733d8 3248+ * (note: since POSIX allows minimal ACLs which only contain
fa26e11c
WD
3249+ * 3 entries - ie there is no mask entry - we should, in theory,
3250+ * check for this and add a mask entry if necessary - however
3251+ * we "know" that the caller of this interface always specifies
3252+ * a mask so, in practice "this never happens" (tm) - if it *does*
3253+ * happen aclsort() will fail and return an error and someone will
0f6733d8
WD
3254+ * have to fix it ...)
3255+ */
fa26e11c
WD
3256+
3257+static int acl_sort(SMB_ACL_T acl_d)
3258+{
3259+ int fixmask = (acl_d->count <= 4);
3260+
3261+ if (hpux_acl_sort(acl_d->count, fixmask, acl_d->acl) != 0) {
3262+ errno = EINVAL;
3263+ return -1;
3264+ }
3265+ return 0;
3266+}
0f6733d8
WD
3267+
3268+int sys_acl_valid(SMB_ACL_T acl_d)
fa26e11c
WD
3269+{
3270+ return acl_sort(acl_d);
3271+}
3272+
0f6733d8 3273+int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
fa26e11c 3274+{
0f6733d8
WD
3275+ struct stat s;
3276+ struct acl *acl_p;
3277+ int acl_count;
3278+ struct acl *acl_buf = NULL;
3279+ int ret;
fa26e11c 3280+
0f6733d8
WD
3281+ if(hpux_acl_call_presence() == False) {
3282+ /* Looks like we don't have the acl() system call on HPUX.
3283+ * May be the system doesn't have the latest version of JFS.
3284+ */
3285+ errno=ENOSYS;
3286+ return -1;
fa26e11c
WD
3287+ }
3288+
3289+ if (type != SMB_ACL_TYPE_ACCESS && type != SMB_ACL_TYPE_DEFAULT) {
3290+ errno = EINVAL;
3291+ return -1;
3292+ }
3293+
3294+ if (acl_sort(acl_d) != 0) {
3295+ return -1;
3296+ }
3297+
0f6733d8
WD
3298+ acl_p = &acl_d->acl[0];
3299+ acl_count = acl_d->count;
fa26e11c 3300+
0f6733d8
WD
3301+ /*
3302+ * if it's a directory there is extra work to do
3303+ * since the acl() system call will replace both
3304+ * the access ACLs and the default ACLs (if any)
3305+ */
fa26e11c
WD
3306+ if (stat(name, &s) != 0) {
3307+ return -1;
3308+ }
3309+ if (S_ISDIR(s.st_mode)) {
0f6733d8
WD
3310+ SMB_ACL_T acc_acl;
3311+ SMB_ACL_T def_acl;
3312+ SMB_ACL_T tmp_acl;
3313+ int i;
fa26e11c
WD
3314+
3315+ if (type == SMB_ACL_TYPE_ACCESS) {
3316+ acc_acl = acl_d;
3317+ def_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_DEFAULT);
3318+
3319+ } else {
3320+ def_acl = acl_d;
3321+ acc_acl = tmp_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS);
3322+ }
3323+
3324+ if (tmp_acl == NULL) {
3325+ return -1;
3326+ }
3327+
0f6733d8
WD
3328+ /*
3329+ * allocate a temporary buffer for the complete ACL
3330+ */
fa26e11c 3331+ acl_count = acc_acl->count + def_acl->count;
252945ef 3332+ acl_p = acl_buf = SMB_MALLOC_ARRAY(struct acl, acl_count);
fa26e11c
WD
3333+
3334+ if (acl_buf == NULL) {
3335+ sys_acl_free_acl(tmp_acl);
3336+ errno = ENOMEM;
3337+ return -1;
3338+ }
3339+
0f6733d8
WD
3340+ /*
3341+ * copy the access control and default entries into the buffer
3342+ */
fa26e11c 3343+ memcpy(&acl_buf[0], &acc_acl->acl[0],
0f6733d8 3344+ acc_acl->count * sizeof(acl_buf[0]));
fa26e11c
WD
3345+
3346+ memcpy(&acl_buf[acc_acl->count], &def_acl->acl[0],
0f6733d8 3347+ def_acl->count * sizeof(acl_buf[0]));
fa26e11c 3348+
0f6733d8
WD
3349+ /*
3350+ * set the ACL_DEFAULT flag on the default entries
3351+ */
fa26e11c
WD
3352+ for (i = acc_acl->count; i < acl_count; i++) {
3353+ acl_buf[i].a_type |= ACL_DEFAULT;
3354+ }
3355+
3356+ sys_acl_free_acl(tmp_acl);
3357+
3358+ } else if (type != SMB_ACL_TYPE_ACCESS) {
3359+ errno = EINVAL;
3360+ return -1;
3361+ }
3362+
3363+ ret = acl(name, ACL_SET, acl_count, acl_p);
3364+
0f6733d8
WD
3365+ if (acl_buf) {
3366+ free(acl_buf);
3367+ }
fa26e11c
WD
3368+
3369+ return ret;
3370+}
3371+
0f6733d8 3372+int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
fa26e11c 3373+{
0f6733d8
WD
3374+ /*
3375+ * HPUX doesn't have the facl call. Fake it using the path.... JRA.
3376+ */
fa26e11c
WD
3377+
3378+ files_struct *fsp = file_find_fd(fd);
3379+
3380+ if (fsp == NULL) {
3381+ errno = EBADF;
3382+ return NULL;
3383+ }
3384+
3385+ if (acl_sort(acl_d) != 0) {
3386+ return -1;
3387+ }
3388+
0f6733d8
WD
3389+ /*
3390+ * We know we're in the same conn context. So we
3391+ * can use the relative path.
3392+ */
fa26e11c 3393+
5ca9317d 3394+ return sys_acl_set_file(fsp->fsp_name, SMB_ACL_TYPE_ACCESS, acl_d);
fa26e11c
WD
3395+}
3396+
0f6733d8 3397+int sys_acl_delete_def_file(const char *path)
fa26e11c 3398+{
0f6733d8
WD
3399+ SMB_ACL_T acl_d;
3400+ int ret;
fa26e11c 3401+
0f6733d8
WD
3402+ /*
3403+ * fetching the access ACL and rewriting it has
3404+ * the effect of deleting the default ACL
3405+ */
fa26e11c
WD
3406+ if ((acl_d = sys_acl_get_file(path, SMB_ACL_TYPE_ACCESS)) == NULL) {
3407+ return -1;
3408+ }
3409+
3410+ ret = acl(path, ACL_SET, acl_d->count, acl_d->acl);
3411+
3412+ sys_acl_free_acl(acl_d);
0f6733d8 3413+
fa26e11c
WD
3414+ return ret;
3415+}
3416+
0f6733d8 3417+int sys_acl_free_text(char *text)
fa26e11c
WD
3418+{
3419+ free(text);
3420+ return 0;
3421+}
3422+
0f6733d8 3423+int sys_acl_free_acl(SMB_ACL_T acl_d)
fa26e11c
WD
3424+{
3425+ free(acl_d);
3426+ return 0;
3427+}
3428+
0f6733d8 3429+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
fa26e11c
WD
3430+{
3431+ return 0;
3432+}
3433+
3434+#elif defined(HAVE_IRIX_ACLS)
3435+
0f6733d8 3436+int sys_acl_get_entry(SMB_ACL_T acl_d, int entry_id, SMB_ACL_ENTRY_T *entry_p)
fa26e11c
WD
3437+{
3438+ if (entry_id != SMB_ACL_FIRST_ENTRY && entry_id != SMB_ACL_NEXT_ENTRY) {
3439+ errno = EINVAL;
3440+ return -1;
3441+ }
3442+
3443+ if (entry_p == NULL) {
3444+ errno = EINVAL;
3445+ return -1;
3446+ }
3447+
3448+ if (entry_id == SMB_ACL_FIRST_ENTRY) {
3449+ acl_d->next = 0;
3450+ }
3451+
3452+ if (acl_d->next < 0) {
3453+ errno = EINVAL;
3454+ return -1;
3455+ }
3456+
3457+ if (acl_d->next >= acl_d->aclp->acl_cnt) {
3458+ return 0;
3459+ }
3460+
3461+ *entry_p = &acl_d->aclp->acl_entry[acl_d->next++];
3462+
3463+ return 1;
3464+}
3465+
0f6733d8 3466+int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *type_p)
fa26e11c
WD
3467+{
3468+ *type_p = entry_d->ae_tag;
3469+
3470+ return 0;
3471+}
3472+
0f6733d8 3473+int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
fa26e11c
WD
3474+{
3475+ *permset_p = entry_d;
3476+
3477+ return 0;
3478+}
3479+
0f6733d8 3480+void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d)
fa26e11c
WD
3481+{
3482+ if (entry_d->ae_tag != SMB_ACL_USER
3483+ && entry_d->ae_tag != SMB_ACL_GROUP) {
3484+ errno = EINVAL;
3485+ return NULL;
3486+ }
3487+
3488+ return &entry_d->ae_id;
3489+}
3490+
0f6733d8 3491+SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type)
fa26e11c 3492+{
0f6733d8 3493+ SMB_ACL_T a;
fa26e11c 3494+
252945ef 3495+ if ((a = SMB_MALLOC_P(struct SMB_ACL_T)) == NULL) {
fa26e11c
WD
3496+ errno = ENOMEM;
3497+ return NULL;
3498+ }
3499+ if ((a->aclp = acl_get_file(path_p, type)) == NULL) {
0f6733d8 3500+ SAFE_FREE(a);
fa26e11c
WD
3501+ return NULL;
3502+ }
3503+ a->next = -1;
3504+ a->freeaclp = True;
3505+ return a;
3506+}
3507+
0f6733d8 3508+SMB_ACL_T sys_acl_get_fd(int fd)
fa26e11c 3509+{
0f6733d8 3510+ SMB_ACL_T a;
fa26e11c 3511+
252945ef 3512+ if ((a = SMB_MALLOC_P(struct SMB_ACL_T)) == NULL) {
fa26e11c
WD
3513+ errno = ENOMEM;
3514+ return NULL;
3515+ }
3516+ if ((a->aclp = acl_get_fd(fd)) == NULL) {
0f6733d8 3517+ SAFE_FREE(a);
fa26e11c
WD
3518+ return NULL;
3519+ }
3520+ a->next = -1;
3521+ a->freeaclp = True;
3522+ return a;
3523+}
3524+
0f6733d8 3525+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset_d)
fa26e11c
WD
3526+{
3527+ permset_d->ae_perm = 0;
3528+
3529+ return 0;
3530+}
3531+
0f6733d8 3532+int sys_acl_add_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
fa26e11c
WD
3533+{
3534+ if (perm != SMB_ACL_READ && perm != SMB_ACL_WRITE
3535+ && perm != SMB_ACL_EXECUTE) {
3536+ errno = EINVAL;
3537+ return -1;
3538+ }
3539+
3540+ if (permset_d == NULL) {
3541+ errno = EINVAL;
3542+ return -1;
3543+ }
3544+
3545+ permset_d->ae_perm |= perm;
3546+
3547+ return 0;
3548+}
3549+
0f6733d8 3550+int sys_acl_get_perm(SMB_ACL_PERMSET_T permset_d, SMB_ACL_PERM_T perm)
fa26e11c
WD
3551+{
3552+ return permset_d->ae_perm & perm;
3553+}
3554+
0f6733d8 3555+char *sys_acl_to_text(SMB_ACL_T acl_d, ssize_t *len_p)
fa26e11c
WD
3556+{
3557+ return acl_to_text(acl_d->aclp, len_p);
3558+}
3559+
0f6733d8 3560+SMB_ACL_T sys_acl_init(int count)
fa26e11c 3561+{
0f6733d8 3562+ SMB_ACL_T a;
fa26e11c
WD
3563+
3564+ if (count < 0) {
3565+ errno = EINVAL;
3566+ return NULL;
3567+ }
3568+
252945ef 3569+ if ((a = SMB_MALLOC(sizeof(struct SMB_ACL_T) + sizeof(struct acl))) == NULL) {
fa26e11c
WD
3570+ errno = ENOMEM;
3571+ return NULL;
3572+ }
3573+
3574+ a->next = -1;
3575+ a->freeaclp = False;
0f6733d8 3576+ a->aclp = (struct acl *)(&a->aclp + sizeof(struct acl *));
fa26e11c
WD
3577+ a->aclp->acl_cnt = 0;
3578+
3579+ return a;
3580+}
3581+
3582+
0f6733d8 3583+int sys_acl_create_entry(SMB_ACL_T *acl_p, SMB_ACL_ENTRY_T *entry_p)
fa26e11c 3584+{
0f6733d8
WD
3585+ SMB_ACL_T acl_d;
3586+ SMB_ACL_ENTRY_T entry_d;
fa26e11c
WD
3587+
3588+ if (acl_p == NULL || entry_p == NULL || (acl_d = *acl_p) == NULL) {
3589+ errno = EINVAL;
3590+ return -1;
3591+ }
3592+
3593+ if (acl_d->aclp->acl_cnt >= ACL_MAX_ENTRIES) {
3594+ errno = ENOSPC;
3595+ return -1;
3596+ }
3597+
0f6733d8
WD
3598+ entry_d = &acl_d->aclp->acl_entry[acl_d->aclp->acl_cnt++];
3599+ entry_d->ae_tag = 0;
3600+ entry_d->ae_id = 0;
3601+ entry_d->ae_perm = 0;
3602+ *entry_p = entry_d;
fa26e11c
WD
3603+
3604+ return 0;
3605+}
3606+
0f6733d8 3607+int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T tag_type)
fa26e11c
WD
3608+{
3609+ switch (tag_type) {
3610+ case SMB_ACL_USER:
3611+ case SMB_ACL_USER_OBJ:
3612+ case SMB_ACL_GROUP:
3613+ case SMB_ACL_GROUP_OBJ:
3614+ case SMB_ACL_OTHER:
3615+ case SMB_ACL_MASK:
3616+ entry_d->ae_tag = tag_type;
3617+ break;
3618+ default:
3619+ errno = EINVAL;
3620+ return -1;
3621+ }
3622+
3623+ return 0;
3624+}
3625+
0f6733d8 3626+int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry_d, void *qual_p)
fa26e11c
WD
3627+{
3628+ if (entry_d->ae_tag != SMB_ACL_GROUP
3629+ && entry_d->ae_tag != SMB_ACL_USER) {
3630+ errno = EINVAL;
3631+ return -1;
3632+ }
3633+
3634+ entry_d->ae_id = *((id_t *)qual_p);
3635+
3636+ return 0;
3637+}
3638+
0f6733d8 3639+int sys_acl_set_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T permset_d)
fa26e11c
WD
3640+{
3641+ if (permset_d->ae_perm & ~(SMB_ACL_READ|SMB_ACL_WRITE|SMB_ACL_EXECUTE)) {
3642+ return EINVAL;
3643+ }
3644+
3645+ entry_d->ae_perm = permset_d->ae_perm;
3646+
3647+ return 0;
3648+}
3649+
0f6733d8 3650+int sys_acl_valid(SMB_ACL_T acl_d)
fa26e11c
WD
3651+{
3652+ return acl_valid(acl_d->aclp);
3653+}
3654+
0f6733d8 3655+int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T type, SMB_ACL_T acl_d)
fa26e11c
WD
3656+{
3657+ return acl_set_file(name, type, acl_d->aclp);
3658+}
3659+
0f6733d8 3660+int sys_acl_set_fd(int fd, SMB_ACL_T acl_d)
fa26e11c
WD
3661+{
3662+ return acl_set_fd(fd, acl_d->aclp);
3663+}
3664+
0f6733d8 3665+int sys_acl_delete_def_file(const char *name)
fa26e11c
WD
3666+{
3667+ return acl_delete_def_file(name);
3668+}
3669+
0f6733d8 3670+int sys_acl_free_text(char *text)
fa26e11c
WD
3671+{
3672+ return acl_free(text);
3673+}
3674+
0f6733d8 3675+int sys_acl_free_acl(SMB_ACL_T acl_d)
fa26e11c
WD
3676+{
3677+ if (acl_d->freeaclp) {
3678+ acl_free(acl_d->aclp);
3679+ }
3680+ acl_free(acl_d);
3681+ return 0;
3682+}
3683+
0f6733d8 3684+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
fa26e11c
WD
3685+{
3686+ return 0;
3687+}
3688+
3689+#elif defined(HAVE_AIX_ACLS)
3690+
3691+/* Donated by Medha Date, mdate@austin.ibm.com, for IBM */
3692+
0f6733d8 3693+int sys_acl_get_entry( SMB_ACL_T theacl, int entry_id, SMB_ACL_ENTRY_T *entry_p)
fa26e11c
WD
3694+{
3695+ struct acl_entry_link *link;
3696+ struct new_acl_entry *entry;
3697+ int keep_going;
3698+
3699+ DEBUG(10,("This is the count: %d\n",theacl->count));
3700+
0f6733d8
WD
3701+ /* Check if count was previously set to -1. *
3702+ * If it was, that means we reached the end *
3703+ * of the acl last time. */
3704+ if(theacl->count == -1)
3705+ return(0);
fa26e11c
WD
3706+
3707+ link = theacl;
0f6733d8
WD
3708+ /* To get to the next acl, traverse linked list until index *
3709+ * of acl matches the count we are keeping. This count is *
3710+ * incremented each time we return an acl entry. */
fa26e11c 3711+
0f6733d8 3712+ for(keep_going = 0; keep_going < theacl->count; keep_going++)
fa26e11c
WD
3713+ link = link->nextp;
3714+
3715+ entry = *entry_p = link->entryp;
3716+
3717+ DEBUG(10,("*entry_p is %d\n",entry_p));
3718+ DEBUG(10,("*entry_p->ace_access is %d\n",entry->ace_access));
3719+
3720+ /* Increment count */
3721+ theacl->count++;
0f6733d8 3722+ if(link->nextp == NULL)
fa26e11c
WD
3723+ theacl->count = -1;
3724+
0f6733d8 3725+ return(1);
fa26e11c
WD
3726+}
3727+
0f6733d8 3728+int sys_acl_get_tag_type( SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p)
fa26e11c
WD
3729+{
3730+ /* Initialize tag type */
3731+
3732+ *tag_type_p = -1;
3733+ DEBUG(10,("the tagtype is %d\n",entry_d->ace_id->id_type));
3734+
0f6733d8
WD
3735+ /* Depending on what type of entry we have, *
3736+ * return tag type. */
3737+ switch(entry_d->ace_id->id_type) {
fa26e11c
WD
3738+ case ACEID_USER:
3739+ *tag_type_p = SMB_ACL_USER;
3740+ break;
3741+ case ACEID_GROUP:
3742+ *tag_type_p = SMB_ACL_GROUP;
3743+ break;
3744+
3745+ case SMB_ACL_USER_OBJ:
3746+ case SMB_ACL_GROUP_OBJ:
3747+ case SMB_ACL_OTHER:
3748+ *tag_type_p = entry_d->ace_id->id_type;
3749+ break;
0f6733d8 3750+
fa26e11c 3751+ default:
0f6733d8 3752+ return(-1);
fa26e11c
WD
3753+ }
3754+
0f6733d8 3755+ return(0);
fa26e11c
WD
3756+}
3757+
0f6733d8 3758+int sys_acl_get_permset( SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p)
fa26e11c
WD
3759+{
3760+ DEBUG(10,("Starting AIX sys_acl_get_permset\n"));
3761+ *permset_p = &entry_d->ace_access;
3762+ DEBUG(10,("**permset_p is %d\n",**permset_p));
0f6733d8
WD
3763+ if(!(**permset_p & S_IXUSR) &&
3764+ !(**permset_p & S_IWUSR) &&
3765+ !(**permset_p & S_IRUSR) &&
3766+ (**permset_p != 0))
3767+ return(-1);
fa26e11c
WD
3768+
3769+ DEBUG(10,("Ending AIX sys_acl_get_permset\n"));
0f6733d8 3770+ return(0);
fa26e11c
WD
3771+}
3772+
0f6733d8 3773+void *sys_acl_get_qualifier( SMB_ACL_ENTRY_T entry_d)
fa26e11c 3774+{
0f6733d8 3775+ return(entry_d->ace_id->id_data);
fa26e11c
WD
3776+}
3777+
0f6733d8 3778+SMB_ACL_T sys_acl_get_file( const char *path_p, SMB_ACL_TYPE_T type)
fa26e11c
WD
3779+{
3780+ struct acl *file_acl = (struct acl *)NULL;
3781+ struct acl_entry *acl_entry;
3782+ struct new_acl_entry *new_acl_entry;
3783+ struct ace_id *idp;
3784+ struct acl_entry_link *acl_entry_link;
3785+ struct acl_entry_link *acl_entry_link_head;
3786+ int i;
3787+ int rc = 0;
3788+ uid_t user_id;
3789+
252945ef
WD
3790+ /* AIX has no DEFAULT */
3791+ if ( type == SMB_ACL_TYPE_DEFAULT )
3792+ return NULL;
3793+
fa26e11c 3794+ /* Get the acl using statacl */
0f6733d8 3795+
fa26e11c
WD
3796+ DEBUG(10,("Entering sys_acl_get_file\n"));
3797+ DEBUG(10,("path_p is %s\n",path_p));
3798+
252945ef 3799+ file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
0f6733d8
WD
3800+
3801+ if(file_acl == NULL) {
fa26e11c
WD
3802+ errno=ENOMEM;
3803+ DEBUG(0,("Error in AIX sys_acl_get_file: %d\n",errno));
0f6733d8 3804+ return(NULL);
fa26e11c
WD
3805+ }
3806+
3807+ memset(file_acl,0,BUFSIZ);
3808+
3809+ rc = statacl((char *)path_p,0,file_acl,BUFSIZ);
0f6733d8 3810+ if(rc == -1) {
fa26e11c 3811+ DEBUG(0,("statacl returned %d with errno %d\n",rc,errno));
0f6733d8
WD
3812+ SAFE_FREE(file_acl);
3813+ return(NULL);
fa26e11c
WD
3814+ }
3815+
3816+ DEBUG(10,("Got facl and returned it\n"));
3817+
3818+ /* Point to the first acl entry in the acl */
3819+ acl_entry = file_acl->acl_ext;
3820+
0f6733d8
WD
3821+ /* Begin setting up the head of the linked list *
3822+ * that will be used for the storing the acl *
3823+ * in a way that is useful for the posix_acls.c *
3824+ * code. */
fa26e11c
WD
3825+
3826+ acl_entry_link_head = acl_entry_link = sys_acl_init(0);
0f6733d8
WD
3827+ if(acl_entry_link_head == NULL)
3828+ return(NULL);
fa26e11c 3829+
252945ef 3830+ acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
0f6733d8
WD
3831+ if(acl_entry_link->entryp == NULL) {
3832+ SAFE_FREE(file_acl);
fa26e11c
WD
3833+ errno = ENOMEM;
3834+ DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
0f6733d8 3835+ return(NULL);
fa26e11c
WD
3836+ }
3837+
3838+ DEBUG(10,("acl_entry is %d\n",acl_entry));
3839+ DEBUG(10,("acl_last(file_acl) id %d\n",acl_last(file_acl)));
3840+
0f6733d8
WD
3841+ /* Check if the extended acl bit is on. *
3842+ * If it isn't, do not show the *
3843+ * contents of the acl since AIX intends *
3844+ * the extended info to remain unused */
fa26e11c 3845+
0f6733d8 3846+ if(file_acl->acl_mode & S_IXACL){
fa26e11c 3847+ /* while we are not pointing to the very end */
0f6733d8 3848+ while(acl_entry < acl_last(file_acl)) {
fa26e11c
WD
3849+ /* before we malloc anything, make sure this is */
3850+ /* a valid acl entry and one that we want to map */
3851+ idp = id_nxt(acl_entry->ace_id);
0f6733d8
WD
3852+ if((acl_entry->ace_type == ACC_SPECIFY ||
3853+ (acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) {
3854+ acl_entry = acl_nxt(acl_entry);
3855+ continue;
fa26e11c
WD
3856+ }
3857+
3858+ idp = acl_entry->ace_id;
3859+
0f6733d8
WD
3860+ /* Check if this is the first entry in the linked list. *
3861+ * The first entry needs to keep prevp pointing to NULL *
3862+ * and already has entryp allocated. */
fa26e11c 3863+
0f6733d8 3864+ if(acl_entry_link_head->count != 0) {
252945ef 3865+ acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
fa26e11c 3866+
0f6733d8
WD
3867+ if(acl_entry_link->nextp == NULL) {
3868+ SAFE_FREE(file_acl);
fa26e11c
WD
3869+ errno = ENOMEM;
3870+ DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
0f6733d8 3871+ return(NULL);
fa26e11c
WD
3872+ }
3873+
3874+ acl_entry_link->nextp->prevp = acl_entry_link;
3875+ acl_entry_link = acl_entry_link->nextp;
252945ef 3876+ acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
0f6733d8
WD
3877+ if(acl_entry_link->entryp == NULL) {
3878+ SAFE_FREE(file_acl);
fa26e11c
WD
3879+ errno = ENOMEM;
3880+ DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
0f6733d8 3881+ return(NULL);
fa26e11c
WD
3882+ }
3883+ acl_entry_link->nextp = NULL;
3884+ }
3885+
3886+ acl_entry_link->entryp->ace_len = acl_entry->ace_len;
3887+
0f6733d8
WD
3888+ /* Don't really need this since all types are going *
3889+ * to be specified but, it's better than leaving it 0 */
fa26e11c
WD
3890+
3891+ acl_entry_link->entryp->ace_type = acl_entry->ace_type;
0f6733d8 3892+
fa26e11c 3893+ acl_entry_link->entryp->ace_access = acl_entry->ace_access;
0f6733d8
WD
3894+
3895+ memcpy(acl_entry_link->entryp->ace_id,idp,sizeof(struct ace_id));
fa26e11c 3896+
0f6733d8
WD
3897+ /* The access in the acl entries must be left shifted by *
3898+ * three bites, because they will ultimately be compared *
3899+ * to S_IRUSR, S_IWUSR, and S_IXUSR. */
fa26e11c 3900+
0f6733d8 3901+ switch(acl_entry->ace_type){
fa26e11c
WD
3902+ case ACC_PERMIT:
3903+ case ACC_SPECIFY:
3904+ acl_entry_link->entryp->ace_access = acl_entry->ace_access;
3905+ acl_entry_link->entryp->ace_access <<= 6;
3906+ acl_entry_link_head->count++;
3907+ break;
3908+ case ACC_DENY:
0f6733d8
WD
3909+ /* Since there is no way to return a DENY acl entry *
3910+ * change to PERMIT and then shift. */
fa26e11c
WD
3911+ DEBUG(10,("acl_entry->ace_access is %d\n",acl_entry->ace_access));
3912+ acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7;
3913+ DEBUG(10,("acl_entry_link->entryp->ace_access is %d\n",acl_entry_link->entryp->ace_access));
3914+ acl_entry_link->entryp->ace_access <<= 6;
3915+ acl_entry_link_head->count++;
3916+ break;
3917+ default:
0f6733d8 3918+ return(0);
fa26e11c
WD
3919+ }
3920+
3921+ DEBUG(10,("acl_entry = %d\n",acl_entry));
3922+ DEBUG(10,("The ace_type is %d\n",acl_entry->ace_type));
0f6733d8 3923+
fa26e11c
WD
3924+ acl_entry = acl_nxt(acl_entry);
3925+ }
3926+ } /* end of if enabled */
3927+
0f6733d8
WD
3928+ /* Since owner, group, other acl entries are not *
3929+ * part of the acl entries in an acl, they must *
3930+ * be dummied up to become part of the list. */
fa26e11c 3931+
0f6733d8 3932+ for( i = 1; i < 4; i++) {
fa26e11c 3933+ DEBUG(10,("i is %d\n",i));
0f6733d8 3934+ if(acl_entry_link_head->count != 0) {
252945ef 3935+ acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
0f6733d8
WD
3936+ if(acl_entry_link->nextp == NULL) {
3937+ SAFE_FREE(file_acl);
fa26e11c
WD
3938+ errno = ENOMEM;
3939+ DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
0f6733d8 3940+ return(NULL);
fa26e11c
WD
3941+ }
3942+
3943+ acl_entry_link->nextp->prevp = acl_entry_link;
3944+ acl_entry_link = acl_entry_link->nextp;
252945ef 3945+ acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
0f6733d8
WD
3946+ if(acl_entry_link->entryp == NULL) {
3947+ SAFE_FREE(file_acl);
fa26e11c
WD
3948+ errno = ENOMEM;
3949+ DEBUG(0,("Error in AIX sys_acl_get_file is %d\n",errno));
0f6733d8 3950+ return(NULL);
fa26e11c
WD
3951+ }
3952+ }
3953+
3954+ acl_entry_link->nextp = NULL;
3955+
3956+ new_acl_entry = acl_entry_link->entryp;
3957+ idp = new_acl_entry->ace_id;
3958+
0f6733d8 3959+ new_acl_entry->ace_len = sizeof(struct acl_entry);
fa26e11c 3960+ new_acl_entry->ace_type = ACC_PERMIT;
0f6733d8 3961+ idp->id_len = sizeof(struct ace_id);
fa26e11c 3962+ DEBUG(10,("idp->id_len = %d\n",idp->id_len));
0f6733d8 3963+ memset(idp->id_data,0,sizeof(uid_t));
fa26e11c 3964+
0f6733d8 3965+ switch(i) {
fa26e11c
WD
3966+ case 2:
3967+ new_acl_entry->ace_access = file_acl->g_access << 6;
3968+ idp->id_type = SMB_ACL_GROUP_OBJ;
3969+ break;
3970+
3971+ case 3:
3972+ new_acl_entry->ace_access = file_acl->o_access << 6;
3973+ idp->id_type = SMB_ACL_OTHER;
3974+ break;
0f6733d8 3975+
fa26e11c
WD
3976+ case 1:
3977+ new_acl_entry->ace_access = file_acl->u_access << 6;
3978+ idp->id_type = SMB_ACL_USER_OBJ;
3979+ break;
0f6733d8 3980+
fa26e11c 3981+ default:
0f6733d8 3982+ return(NULL);
fa26e11c
WD
3983+
3984+ }
3985+
3986+ acl_entry_link_head->count++;
3987+ DEBUG(10,("new_acl_entry->ace_access = %d\n",new_acl_entry->ace_access));
3988+ }
3989+
3990+ acl_entry_link_head->count = 0;
0f6733d8 3991+ SAFE_FREE(file_acl);
fa26e11c 3992+
0f6733d8 3993+ return(acl_entry_link_head);
fa26e11c
WD
3994+}
3995+
0f6733d8 3996+SMB_ACL_T sys_acl_get_fd(int fd)
fa26e11c
WD
3997+{
3998+ struct acl *file_acl = (struct acl *)NULL;
3999+ struct acl_entry *acl_entry;
4000+ struct new_acl_entry *new_acl_entry;
4001+ struct ace_id *idp;
4002+ struct acl_entry_link *acl_entry_link;
4003+ struct acl_entry_link *acl_entry_link_head;
4004+ int i;
4005+ int rc = 0;
4006+ uid_t user_id;
4007+
4008+ /* Get the acl using fstatacl */
0f6733d8 4009+
fa26e11c
WD
4010+ DEBUG(10,("Entering sys_acl_get_fd\n"));
4011+ DEBUG(10,("fd is %d\n",fd));
252945ef 4012+ file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
fa26e11c 4013+
0f6733d8 4014+ if(file_acl == NULL) {
fa26e11c
WD
4015+ errno=ENOMEM;
4016+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
0f6733d8 4017+ return(NULL);
fa26e11c
WD
4018+ }
4019+
4020+ memset(file_acl,0,BUFSIZ);
4021+
4022+ rc = fstatacl(fd,0,file_acl,BUFSIZ);
0f6733d8 4023+ if(rc == -1) {
fa26e11c 4024+ DEBUG(0,("The fstatacl call returned %d with errno %d\n",rc,errno));
0f6733d8
WD
4025+ SAFE_FREE(file_acl);
4026+ return(NULL);
fa26e11c
WD
4027+ }
4028+
4029+ DEBUG(10,("Got facl and returned it\n"));
4030+
4031+ /* Point to the first acl entry in the acl */
4032+
4033+ acl_entry = file_acl->acl_ext;
0f6733d8
WD
4034+ /* Begin setting up the head of the linked list *
4035+ * that will be used for the storing the acl *
4036+ * in a way that is useful for the posix_acls.c *
4037+ * code. */
fa26e11c
WD
4038+
4039+ acl_entry_link_head = acl_entry_link = sys_acl_init(0);
0f6733d8
WD
4040+ if(acl_entry_link_head == NULL){
4041+ SAFE_FREE(file_acl);
4042+ return(NULL);
fa26e11c
WD
4043+ }
4044+
252945ef 4045+ acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
fa26e11c 4046+
0f6733d8 4047+ if(acl_entry_link->entryp == NULL) {
fa26e11c
WD
4048+ errno = ENOMEM;
4049+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
0f6733d8
WD
4050+ SAFE_FREE(file_acl);
4051+ return(NULL);
fa26e11c
WD
4052+ }
4053+
4054+ DEBUG(10,("acl_entry is %d\n",acl_entry));
4055+ DEBUG(10,("acl_last(file_acl) id %d\n",acl_last(file_acl)));
0f6733d8
WD
4056+
4057+ /* Check if the extended acl bit is on. *
4058+ * If it isn't, do not show the *
4059+ * contents of the acl since AIX intends *
4060+ * the extended info to remain unused */
4061+
4062+ if(file_acl->acl_mode & S_IXACL){
fa26e11c 4063+ /* while we are not pointing to the very end */
0f6733d8 4064+ while(acl_entry < acl_last(file_acl)) {
fa26e11c
WD
4065+ /* before we malloc anything, make sure this is */
4066+ /* a valid acl entry and one that we want to map */
4067+
4068+ idp = id_nxt(acl_entry->ace_id);
0f6733d8
WD
4069+ if((acl_entry->ace_type == ACC_SPECIFY ||
4070+ (acl_entry->ace_type == ACC_PERMIT)) && (idp != id_last(acl_entry))) {
4071+ acl_entry = acl_nxt(acl_entry);
4072+ continue;
fa26e11c
WD
4073+ }
4074+
4075+ idp = acl_entry->ace_id;
0f6733d8
WD
4076+
4077+ /* Check if this is the first entry in the linked list. *
4078+ * The first entry needs to keep prevp pointing to NULL *
4079+ * and already has entryp allocated. */
fa26e11c 4080+
0f6733d8 4081+ if(acl_entry_link_head->count != 0) {
252945ef 4082+ acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
0f6733d8 4083+ if(acl_entry_link->nextp == NULL) {
fa26e11c
WD
4084+ errno = ENOMEM;
4085+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
0f6733d8
WD
4086+ SAFE_FREE(file_acl);
4087+ return(NULL);
fa26e11c
WD
4088+ }
4089+ acl_entry_link->nextp->prevp = acl_entry_link;
4090+ acl_entry_link = acl_entry_link->nextp;
252945ef 4091+ acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
0f6733d8 4092+ if(acl_entry_link->entryp == NULL) {
fa26e11c
WD
4093+ errno = ENOMEM;
4094+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
0f6733d8
WD
4095+ SAFE_FREE(file_acl);
4096+ return(NULL);
fa26e11c
WD
4097+ }
4098+
4099+ acl_entry_link->nextp = NULL;
4100+ }
4101+
4102+ acl_entry_link->entryp->ace_len = acl_entry->ace_len;
4103+
0f6733d8
WD
4104+ /* Don't really need this since all types are going *
4105+ * to be specified but, it's better than leaving it 0 */
fa26e11c
WD
4106+
4107+ acl_entry_link->entryp->ace_type = acl_entry->ace_type;
4108+ acl_entry_link->entryp->ace_access = acl_entry->ace_access;
4109+
0f6733d8 4110+ memcpy(acl_entry_link->entryp->ace_id, idp, sizeof(struct ace_id));
fa26e11c 4111+
0f6733d8
WD
4112+ /* The access in the acl entries must be left shifted by *
4113+ * three bites, because they will ultimately be compared *
4114+ * to S_IRUSR, S_IWUSR, and S_IXUSR. */
fa26e11c 4115+
0f6733d8 4116+ switch(acl_entry->ace_type){
fa26e11c
WD
4117+ case ACC_PERMIT:
4118+ case ACC_SPECIFY:
4119+ acl_entry_link->entryp->ace_access = acl_entry->ace_access;
4120+ acl_entry_link->entryp->ace_access <<= 6;
4121+ acl_entry_link_head->count++;
4122+ break;
4123+ case ACC_DENY:
0f6733d8
WD
4124+ /* Since there is no way to return a DENY acl entry *
4125+ * change to PERMIT and then shift. */
fa26e11c
WD
4126+ DEBUG(10,("acl_entry->ace_access is %d\n",acl_entry->ace_access));
4127+ acl_entry_link->entryp->ace_access = ~acl_entry->ace_access & 7;
4128+ DEBUG(10,("acl_entry_link->entryp->ace_access is %d\n",acl_entry_link->entryp->ace_access));
4129+ acl_entry_link->entryp->ace_access <<= 6;
4130+ acl_entry_link_head->count++;
4131+ break;
4132+ default:
0f6733d8 4133+ return(0);
fa26e11c
WD
4134+ }
4135+
4136+ DEBUG(10,("acl_entry = %d\n",acl_entry));
4137+ DEBUG(10,("The ace_type is %d\n",acl_entry->ace_type));
0f6733d8 4138+
fa26e11c
WD
4139+ acl_entry = acl_nxt(acl_entry);
4140+ }
4141+ } /* end of if enabled */
4142+
0f6733d8
WD
4143+ /* Since owner, group, other acl entries are not *
4144+ * part of the acl entries in an acl, they must *
4145+ * be dummied up to become part of the list. */
fa26e11c 4146+
0f6733d8 4147+ for( i = 1; i < 4; i++) {
fa26e11c 4148+ DEBUG(10,("i is %d\n",i));
0f6733d8 4149+ if(acl_entry_link_head->count != 0){
252945ef 4150+ acl_entry_link->nextp = SMB_MALLOC_P(struct acl_entry_link);
0f6733d8 4151+ if(acl_entry_link->nextp == NULL) {
fa26e11c
WD
4152+ errno = ENOMEM;
4153+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
0f6733d8
WD
4154+ SAFE_FREE(file_acl);
4155+ return(NULL);
fa26e11c
WD
4156+ }
4157+
4158+ acl_entry_link->nextp->prevp = acl_entry_link;
4159+ acl_entry_link = acl_entry_link->nextp;
252945ef 4160+ acl_entry_link->entryp = SMB_MALLOC_P(struct new_acl_entry);
fa26e11c 4161+
0f6733d8
WD
4162+ if(acl_entry_link->entryp == NULL) {
4163+ SAFE_FREE(file_acl);
fa26e11c
WD
4164+ errno = ENOMEM;
4165+ DEBUG(0,("Error in sys_acl_get_fd is %d\n",errno));
0f6733d8 4166+ return(NULL);
fa26e11c
WD
4167+ }
4168+ }
4169+
4170+ acl_entry_link->nextp = NULL;
0f6733d8 4171+
fa26e11c
WD
4172+ new_acl_entry = acl_entry_link->entryp;
4173+ idp = new_acl_entry->ace_id;
0f6733d8
WD
4174+
4175+ new_acl_entry->ace_len = sizeof(struct acl_entry);
fa26e11c 4176+ new_acl_entry->ace_type = ACC_PERMIT;
0f6733d8 4177+ idp->id_len = sizeof(struct ace_id);
fa26e11c 4178+ DEBUG(10,("idp->id_len = %d\n",idp->id_len));
0f6733d8
WD
4179+ memset(idp->id_data,0,sizeof(uid_t));
4180+
4181+ switch(i) {
fa26e11c
WD
4182+ case 2:
4183+ new_acl_entry->ace_access = file_acl->g_access << 6;
4184+ idp->id_type = SMB_ACL_GROUP_OBJ;
4185+ break;
0f6733d8 4186+
fa26e11c
WD
4187+ case 3:
4188+ new_acl_entry->ace_access = file_acl->o_access << 6;
4189+ idp->id_type = SMB_ACL_OTHER;
4190+ break;
0f6733d8 4191+
fa26e11c
WD
4192+ case 1:
4193+ new_acl_entry->ace_access = file_acl->u_access << 6;
4194+ idp->id_type = SMB_ACL_USER_OBJ;
4195+ break;
0f6733d8 4196+
fa26e11c 4197+ default:
0f6733d8 4198+ return(NULL);
fa26e11c 4199+ }
0f6733d8 4200+
fa26e11c
WD
4201+ acl_entry_link_head->count++;
4202+ DEBUG(10,("new_acl_entry->ace_access = %d\n",new_acl_entry->ace_access));
4203+ }
4204+
4205+ acl_entry_link_head->count = 0;
0f6733d8
WD
4206+ SAFE_FREE(file_acl);
4207+
4208+ return(acl_entry_link_head);
fa26e11c
WD
4209+}
4210+
0f6733d8 4211+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset)
fa26e11c
WD
4212+{
4213+ *permset = *permset & ~0777;
0f6733d8 4214+ return(0);
fa26e11c
WD
4215+}
4216+
0f6733d8 4217+int sys_acl_add_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
fa26e11c 4218+{
0f6733d8
WD
4219+ if((perm != 0) &&
4220+ (perm & (S_IXUSR | S_IWUSR | S_IRUSR)) == 0)
4221+ return(-1);
fa26e11c
WD
4222+
4223+ *permset |= perm;
4224+ DEBUG(10,("This is the permset now: %d\n",*permset));
0f6733d8 4225+ return(0);
fa26e11c
WD
4226+}
4227+
0f6733d8 4228+char *sys_acl_to_text( SMB_ACL_T theacl, ssize_t *plen)
fa26e11c 4229+{
0f6733d8 4230+ return(NULL);
fa26e11c
WD
4231+}
4232+
0f6733d8 4233+SMB_ACL_T sys_acl_init( int count)
fa26e11c
WD
4234+{
4235+ struct acl_entry_link *theacl = NULL;
0f6733d8 4236+
fa26e11c
WD
4237+ DEBUG(10,("Entering sys_acl_init\n"));
4238+
252945ef 4239+ theacl = SMB_MALLOC_P(struct acl_entry_link);
0f6733d8 4240+ if(theacl == NULL) {
fa26e11c
WD
4241+ errno = ENOMEM;
4242+ DEBUG(0,("Error in sys_acl_init is %d\n",errno));
0f6733d8 4243+ return(NULL);
fa26e11c
WD
4244+ }
4245+
4246+ theacl->count = 0;
4247+ theacl->nextp = NULL;
4248+ theacl->prevp = NULL;
4249+ theacl->entryp = NULL;
4250+ DEBUG(10,("Exiting sys_acl_init\n"));
0f6733d8 4251+ return(theacl);
fa26e11c
WD
4252+}
4253+
0f6733d8 4254+int sys_acl_create_entry( SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry)
fa26e11c
WD
4255+{
4256+ struct acl_entry_link *theacl;
4257+ struct acl_entry_link *acl_entryp;
4258+ struct acl_entry_link *temp_entry;
4259+ int counting;
4260+
4261+ DEBUG(10,("Entering the sys_acl_create_entry\n"));
4262+
4263+ theacl = acl_entryp = *pacl;
4264+
4265+ /* Get to the end of the acl before adding entry */
4266+
0f6733d8 4267+ for(counting=0; counting < theacl->count; counting++){
fa26e11c
WD
4268+ DEBUG(10,("The acl_entryp is %d\n",acl_entryp));
4269+ temp_entry = acl_entryp;
4270+ acl_entryp = acl_entryp->nextp;
4271+ }
4272+
0f6733d8 4273+ if(theacl->count != 0){
252945ef 4274+ temp_entry->nextp = acl_entryp = SMB_MALLOC_P(struct acl_entry_link);
0f6733d8 4275+ if(acl_entryp == NULL) {
fa26e11c
WD
4276+ errno = ENOMEM;
4277+ DEBUG(0,("Error in sys_acl_create_entry is %d\n",errno));
0f6733d8 4278+ return(-1);
fa26e11c
WD
4279+ }
4280+
4281+ DEBUG(10,("The acl_entryp is %d\n",acl_entryp));
4282+ acl_entryp->prevp = temp_entry;
4283+ DEBUG(10,("The acl_entryp->prevp is %d\n",acl_entryp->prevp));
4284+ }
4285+
252945ef 4286+ *pentry = acl_entryp->entryp = SMB_MALLOC_P(struct new_acl_entry);
0f6733d8 4287+ if(*pentry == NULL) {
fa26e11c
WD
4288+ errno = ENOMEM;
4289+ DEBUG(0,("Error in sys_acl_create_entry is %d\n",errno));
0f6733d8 4290+ return(-1);
fa26e11c
WD
4291+ }
4292+
0f6733d8
WD
4293+ memset(*pentry,0,sizeof(struct new_acl_entry));
4294+ acl_entryp->entryp->ace_len = sizeof(struct acl_entry);
fa26e11c 4295+ acl_entryp->entryp->ace_type = ACC_PERMIT;
0f6733d8 4296+ acl_entryp->entryp->ace_id->id_len = sizeof(struct ace_id);
fa26e11c
WD
4297+ acl_entryp->nextp = NULL;
4298+ theacl->count++;
4299+ DEBUG(10,("Exiting sys_acl_create_entry\n"));
0f6733d8 4300+ return(0);
fa26e11c
WD
4301+}
4302+
0f6733d8 4303+int sys_acl_set_tag_type( SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype)
fa26e11c
WD
4304+{
4305+ DEBUG(10,("Starting AIX sys_acl_set_tag_type\n"));
4306+ entry->ace_id->id_type = tagtype;
4307+ DEBUG(10,("The tag type is %d\n",entry->ace_id->id_type));
4308+ DEBUG(10,("Ending AIX sys_acl_set_tag_type\n"));
4309+}
4310+
0f6733d8 4311+int sys_acl_set_qualifier( SMB_ACL_ENTRY_T entry, void *qual)
fa26e11c
WD
4312+{
4313+ DEBUG(10,("Starting AIX sys_acl_set_qualifier\n"));
0f6733d8 4314+ memcpy(entry->ace_id->id_data,qual,sizeof(uid_t));
fa26e11c 4315+ DEBUG(10,("Ending AIX sys_acl_set_qualifier\n"));
0f6733d8 4316+ return(0);
fa26e11c
WD
4317+}
4318+
0f6733d8 4319+int sys_acl_set_permset( SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset)
fa26e11c
WD
4320+{
4321+ DEBUG(10,("Starting AIX sys_acl_set_permset\n"));
0f6733d8
WD
4322+ if(!(*permset & S_IXUSR) &&
4323+ !(*permset & S_IWUSR) &&
4324+ !(*permset & S_IRUSR) &&
4325+ (*permset != 0))
4326+ return(-1);
fa26e11c
WD
4327+
4328+ entry->ace_access = *permset;
4329+ DEBUG(10,("entry->ace_access = %d\n",entry->ace_access));
4330+ DEBUG(10,("Ending AIX sys_acl_set_permset\n"));
0f6733d8 4331+ return(0);
fa26e11c
WD
4332+}
4333+
0f6733d8 4334+int sys_acl_valid( SMB_ACL_T theacl )
fa26e11c
WD
4335+{
4336+ int user_obj = 0;
4337+ int group_obj = 0;
4338+ int other_obj = 0;
4339+ struct acl_entry_link *acl_entry;
4340+
0f6733d8 4341+ for(acl_entry=theacl; acl_entry != NULL; acl_entry = acl_entry->nextp) {
fa26e11c
WD
4342+ user_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_USER_OBJ);
4343+ group_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_GROUP_OBJ);
4344+ other_obj += (acl_entry->entryp->ace_id->id_type == SMB_ACL_OTHER);
4345+ }
4346+
4347+ DEBUG(10,("user_obj=%d, group_obj=%d, other_obj=%d\n",user_obj,group_obj,other_obj));
0f6733d8
WD
4348+
4349+ if(user_obj != 1 || group_obj != 1 || other_obj != 1)
4350+ return(-1);
fa26e11c 4351+
0f6733d8 4352+ return(0);
fa26e11c
WD
4353+}
4354+
0f6733d8 4355+int sys_acl_set_file( const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl)
fa26e11c
WD
4356+{
4357+ struct acl_entry_link *acl_entry_link = NULL;
4358+ struct acl *file_acl = NULL;
4359+ struct acl *file_acl_temp = NULL;
4360+ struct acl_entry *acl_entry = NULL;
4361+ struct ace_id *ace_id = NULL;
4362+ uint id_type;
4363+ uint ace_access;
4364+ uint user_id;
4365+ uint acl_length;
4366+ uint rc;
4367+
4368+ DEBUG(10,("Entering sys_acl_set_file\n"));
4369+ DEBUG(10,("File name is %s\n",name));
0f6733d8 4370+
fa26e11c 4371+ /* AIX has no default ACL */
0f6733d8
WD
4372+ if(acltype == SMB_ACL_TYPE_DEFAULT)
4373+ return(0);
fa26e11c
WD
4374+
4375+ acl_length = BUFSIZ;
252945ef 4376+ file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
fa26e11c 4377+
0f6733d8 4378+ if(file_acl == NULL) {
fa26e11c
WD
4379+ errno = ENOMEM;
4380+ DEBUG(0,("Error in sys_acl_set_file is %d\n",errno));
0f6733d8 4381+ return(-1);
fa26e11c
WD
4382+ }
4383+
4384+ memset(file_acl,0,BUFSIZ);
4385+
4386+ file_acl->acl_len = ACL_SIZ;
4387+ file_acl->acl_mode = S_IXACL;
4388+
0f6733d8 4389+ for(acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) {
fa26e11c
WD
4390+ acl_entry_link->entryp->ace_access >>= 6;
4391+ id_type = acl_entry_link->entryp->ace_id->id_type;
4392+
0f6733d8 4393+ switch(id_type) {
fa26e11c
WD
4394+ case SMB_ACL_USER_OBJ:
4395+ file_acl->u_access = acl_entry_link->entryp->ace_access;
4396+ continue;
4397+ case SMB_ACL_GROUP_OBJ:
4398+ file_acl->g_access = acl_entry_link->entryp->ace_access;
4399+ continue;
4400+ case SMB_ACL_OTHER:
4401+ file_acl->o_access = acl_entry_link->entryp->ace_access;
4402+ continue;
4403+ case SMB_ACL_MASK:
4404+ continue;
4405+ }
4406+
0f6733d8
WD
4407+ if((file_acl->acl_len + sizeof(struct acl_entry)) > acl_length) {
4408+ acl_length += sizeof(struct acl_entry);
252945ef 4409+ file_acl_temp = (struct acl *)SMB_MALLOC(acl_length);
0f6733d8
WD
4410+ if(file_acl_temp == NULL) {
4411+ SAFE_FREE(file_acl);
fa26e11c
WD
4412+ errno = ENOMEM;
4413+ DEBUG(0,("Error in sys_acl_set_file is %d\n",errno));
0f6733d8
WD
4414+ return(-1);
4415+ }
fa26e11c
WD
4416+
4417+ memcpy(file_acl_temp,file_acl,file_acl->acl_len);
0f6733d8 4418+ SAFE_FREE(file_acl);
fa26e11c
WD
4419+ file_acl = file_acl_temp;
4420+ }
4421+
4422+ acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len);
0f6733d8 4423+ file_acl->acl_len += sizeof(struct acl_entry);
fa26e11c
WD
4424+ acl_entry->ace_len = acl_entry_link->entryp->ace_len;
4425+ acl_entry->ace_access = acl_entry_link->entryp->ace_access;
0f6733d8 4426+
fa26e11c 4427+ /* In order to use this, we'll need to wait until we can get denies */
0f6733d8
WD
4428+ /* if(!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
4429+ acl_entry->ace_type = ACC_SPECIFY; */
fa26e11c
WD
4430+
4431+ acl_entry->ace_type = ACC_SPECIFY;
0f6733d8 4432+
fa26e11c 4433+ ace_id = acl_entry->ace_id;
0f6733d8 4434+
fa26e11c
WD
4435+ ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
4436+ DEBUG(10,("The id type is %d\n",ace_id->id_type));
4437+ ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
0f6733d8
WD
4438+ memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof(uid_t));
4439+ memcpy(acl_entry->ace_id->id_data, &user_id, sizeof(uid_t));
fa26e11c
WD
4440+ }
4441+
0f6733d8 4442+ rc = chacl(name,file_acl,file_acl->acl_len);
fa26e11c
WD
4443+ DEBUG(10,("errno is %d\n",errno));
4444+ DEBUG(10,("return code is %d\n",rc));
0f6733d8 4445+ SAFE_FREE(file_acl);
fa26e11c 4446+ DEBUG(10,("Exiting the sys_acl_set_file\n"));
0f6733d8 4447+ return(rc);
fa26e11c
WD
4448+}
4449+
0f6733d8 4450+int sys_acl_set_fd( int fd, SMB_ACL_T theacl)
fa26e11c
WD
4451+{
4452+ struct acl_entry_link *acl_entry_link = NULL;
4453+ struct acl *file_acl = NULL;
4454+ struct acl *file_acl_temp = NULL;
4455+ struct acl_entry *acl_entry = NULL;
4456+ struct ace_id *ace_id = NULL;
4457+ uint id_type;
4458+ uint user_id;
4459+ uint acl_length;
4460+ uint rc;
0f6733d8 4461+
fa26e11c
WD
4462+ DEBUG(10,("Entering sys_acl_set_fd\n"));
4463+ acl_length = BUFSIZ;
252945ef 4464+ file_acl = (struct acl *)SMB_MALLOC(BUFSIZ);
fa26e11c 4465+
0f6733d8 4466+ if(file_acl == NULL) {
fa26e11c
WD
4467+ errno = ENOMEM;
4468+ DEBUG(0,("Error in sys_acl_set_fd is %d\n",errno));
0f6733d8 4469+ return(-1);
fa26e11c
WD
4470+ }
4471+
4472+ memset(file_acl,0,BUFSIZ);
0f6733d8 4473+
fa26e11c
WD
4474+ file_acl->acl_len = ACL_SIZ;
4475+ file_acl->acl_mode = S_IXACL;
4476+
0f6733d8 4477+ for(acl_entry_link=theacl; acl_entry_link != NULL; acl_entry_link = acl_entry_link->nextp) {
fa26e11c
WD
4478+ acl_entry_link->entryp->ace_access >>= 6;
4479+ id_type = acl_entry_link->entryp->ace_id->id_type;
4480+ DEBUG(10,("The id_type is %d\n",id_type));
4481+
0f6733d8 4482+ switch(id_type) {
fa26e11c
WD
4483+ case SMB_ACL_USER_OBJ:
4484+ file_acl->u_access = acl_entry_link->entryp->ace_access;
4485+ continue;
4486+ case SMB_ACL_GROUP_OBJ:
4487+ file_acl->g_access = acl_entry_link->entryp->ace_access;
4488+ continue;
4489+ case SMB_ACL_OTHER:
4490+ file_acl->o_access = acl_entry_link->entryp->ace_access;
4491+ continue;
4492+ case SMB_ACL_MASK:
4493+ continue;
4494+ }
4495+
0f6733d8
WD
4496+ if((file_acl->acl_len + sizeof(struct acl_entry)) > acl_length) {
4497+ acl_length += sizeof(struct acl_entry);
252945ef 4498+ file_acl_temp = (struct acl *)SMB_MALLOC(acl_length);
0f6733d8
WD
4499+ if(file_acl_temp == NULL) {
4500+ SAFE_FREE(file_acl);
fa26e11c
WD
4501+ errno = ENOMEM;
4502+ DEBUG(0,("Error in sys_acl_set_fd is %d\n",errno));
0f6733d8 4503+ return(-1);
fa26e11c
WD
4504+ }
4505+
4506+ memcpy(file_acl_temp,file_acl,file_acl->acl_len);
0f6733d8 4507+ SAFE_FREE(file_acl);
fa26e11c
WD
4508+ file_acl = file_acl_temp;
4509+ }
4510+
4511+ acl_entry = (struct acl_entry *)((char *)file_acl + file_acl->acl_len);
0f6733d8 4512+ file_acl->acl_len += sizeof(struct acl_entry);
fa26e11c
WD
4513+ acl_entry->ace_len = acl_entry_link->entryp->ace_len;
4514+ acl_entry->ace_access = acl_entry_link->entryp->ace_access;
0f6733d8 4515+
fa26e11c 4516+ /* In order to use this, we'll need to wait until we can get denies */
0f6733d8 4517+ /* if(!acl_entry->ace_access && acl_entry->ace_type == ACC_PERMIT)
fa26e11c 4518+ acl_entry->ace_type = ACC_SPECIFY; */
0f6733d8 4519+
fa26e11c 4520+ acl_entry->ace_type = ACC_SPECIFY;
0f6733d8 4521+
fa26e11c 4522+ ace_id = acl_entry->ace_id;
0f6733d8 4523+
fa26e11c
WD
4524+ ace_id->id_type = acl_entry_link->entryp->ace_id->id_type;
4525+ DEBUG(10,("The id type is %d\n",ace_id->id_type));
4526+ ace_id->id_len = acl_entry_link->entryp->ace_id->id_len;
0f6733d8
WD
4527+ memcpy(&user_id, acl_entry_link->entryp->ace_id->id_data, sizeof(uid_t));
4528+ memcpy(ace_id->id_data, &user_id, sizeof(uid_t));
fa26e11c 4529+ }
0f6733d8 4530+
fa26e11c
WD
4531+ rc = fchacl(fd,file_acl,file_acl->acl_len);
4532+ DEBUG(10,("errno is %d\n",errno));
4533+ DEBUG(10,("return code is %d\n",rc));
0f6733d8 4534+ SAFE_FREE(file_acl);
fa26e11c 4535+ DEBUG(10,("Exiting sys_acl_set_fd\n"));
0f6733d8 4536+ return(rc);
fa26e11c
WD
4537+}
4538+
0f6733d8 4539+int sys_acl_delete_def_file(const char *name)
fa26e11c
WD
4540+{
4541+ /* AIX has no default ACL */
4542+ return 0;
4543+}
4544+
0f6733d8 4545+int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
fa26e11c 4546+{
0f6733d8 4547+ return(*permset & perm);
fa26e11c
WD
4548+}
4549+
0f6733d8 4550+int sys_acl_free_text(char *text)
fa26e11c 4551+{
0f6733d8 4552+ return(0);
fa26e11c
WD
4553+}
4554+
0f6733d8 4555+int sys_acl_free_acl(SMB_ACL_T posix_acl)
fa26e11c
WD
4556+{
4557+ struct acl_entry_link *acl_entry_link;
4558+
0f6733d8
WD
4559+ for(acl_entry_link = posix_acl->nextp; acl_entry_link->nextp != NULL; acl_entry_link = acl_entry_link->nextp) {
4560+ SAFE_FREE(acl_entry_link->prevp->entryp);
4561+ SAFE_FREE(acl_entry_link->prevp);
fa26e11c
WD
4562+ }
4563+
0f6733d8
WD
4564+ SAFE_FREE(acl_entry_link->prevp->entryp);
4565+ SAFE_FREE(acl_entry_link->prevp);
4566+ SAFE_FREE(acl_entry_link->entryp);
4567+ SAFE_FREE(acl_entry_link);
4568+
4569+ return(0);
fa26e11c
WD
4570+}
4571+
0f6733d8 4572+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype)
fa26e11c 4573+{
0f6733d8 4574+ return(0);
fa26e11c
WD
4575+}
4576+
4577+#else /* No ACLs. */
4578+
4df546eb 4579+int sys_acl_get_entry(UNUSED(SMB_ACL_T the_acl), UNUSED(int entry_id), UNUSED(SMB_ACL_ENTRY_T *entry_p))
fa26e11c
WD
4580+{
4581+ errno = ENOSYS;
4582+ return -1;
4583+}
4584+
4df546eb 4585+int sys_acl_get_tag_type(UNUSED(SMB_ACL_ENTRY_T entry_d), UNUSED(SMB_ACL_TAG_T *tag_type_p))
fa26e11c
WD
4586+{
4587+ errno = ENOSYS;
4588+ return -1;
4589+}
4590+
4df546eb 4591+int sys_acl_get_permset(UNUSED(SMB_ACL_ENTRY_T entry_d), UNUSED(SMB_ACL_PERMSET_T *permset_p))
fa26e11c
WD
4592+{
4593+ errno = ENOSYS;
4594+ return -1;
4595+}
4596+
4df546eb 4597+void *sys_acl_get_qualifier(UNUSED(SMB_ACL_ENTRY_T entry_d))
fa26e11c
WD
4598+{
4599+ errno = ENOSYS;
4600+ return NULL;
4601+}
4602+
4df546eb 4603+SMB_ACL_T sys_acl_get_file(UNUSED(const char *path_p), UNUSED(SMB_ACL_TYPE_T type))
fa26e11c
WD
4604+{
4605+ errno = ENOSYS;
5ca9317d 4606+ return (SMB_ACL_T)NULL;
fa26e11c
WD
4607+}
4608+
4df546eb 4609+SMB_ACL_T sys_acl_get_fd(UNUSED(int fd))
fa26e11c
WD
4610+{
4611+ errno = ENOSYS;
5ca9317d 4612+ return (SMB_ACL_T)NULL;
fa26e11c
WD
4613+}
4614+
4df546eb 4615+int sys_acl_clear_perms(UNUSED(SMB_ACL_PERMSET_T permset))
fa26e11c
WD
4616+{
4617+ errno = ENOSYS;
4618+ return -1;
4619+}
4620+
4df546eb 4621+int sys_acl_add_perm( UNUSED(SMB_ACL_PERMSET_T permset), UNUSED(SMB_ACL_PERM_T perm))
fa26e11c
WD
4622+{
4623+ errno = ENOSYS;
4624+ return -1;
4625+}
4626+
0f6733d8 4627+int sys_acl_get_perm( SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm)
fa26e11c
WD
4628+{
4629+ errno = ENOSYS;
0f6733d8 4630+ return (permset & perm) ? 1 : 0;
fa26e11c
WD
4631+}
4632+
4df546eb 4633+char *sys_acl_to_text(UNUSED(SMB_ACL_T the_acl), UNUSED(ssize_t *plen))
fa26e11c
WD
4634+{
4635+ errno = ENOSYS;
4636+ return NULL;
4637+}
4638+
4df546eb 4639+int sys_acl_free_text(UNUSED(char *text))
fa26e11c
WD
4640+{
4641+ errno = ENOSYS;
4642+ return -1;
4643+}
4644+
4df546eb 4645+SMB_ACL_T sys_acl_init(UNUSED(int count))
fa26e11c
WD
4646+{
4647+ errno = ENOSYS;
4648+ return NULL;
4649+}
4650+
4df546eb 4651+int sys_acl_create_entry(UNUSED(SMB_ACL_T *pacl), UNUSED(SMB_ACL_ENTRY_T *pentry))
fa26e11c
WD
4652+{
4653+ errno = ENOSYS;
4654+ return -1;
4655+}
4656+
4df546eb 4657+int sys_acl_set_tag_type(UNUSED(SMB_ACL_ENTRY_T entry), UNUSED(SMB_ACL_TAG_T tagtype))
fa26e11c
WD
4658+{
4659+ errno = ENOSYS;
4660+ return -1;
4661+}
4662+
4df546eb 4663+int sys_acl_set_qualifier(UNUSED(SMB_ACL_ENTRY_T entry), UNUSED(void *qual))
fa26e11c
WD
4664+{
4665+ errno = ENOSYS;
4666+ return -1;
4667+}
4668+
4df546eb 4669+int sys_acl_set_permset(UNUSED(SMB_ACL_ENTRY_T entry), UNUSED(SMB_ACL_PERMSET_T permset))
fa26e11c
WD
4670+{
4671+ errno = ENOSYS;
4672+ return -1;
4673+}
4674+
4df546eb 4675+int sys_acl_valid(UNUSED(SMB_ACL_T theacl))
fa26e11c
WD
4676+{
4677+ errno = ENOSYS;
4678+ return -1;
4679+}
4680+
4df546eb 4681+int sys_acl_set_file(UNUSED(const char *name), UNUSED(SMB_ACL_TYPE_T acltype), UNUSED(SMB_ACL_T theacl))
fa26e11c
WD
4682+{
4683+ errno = ENOSYS;
4684+ return -1;
4685+}
4686+
4df546eb 4687+int sys_acl_set_fd(UNUSED(int fd), UNUSED(SMB_ACL_T theacl))
fa26e11c
WD
4688+{
4689+ errno = ENOSYS;
4690+ return -1;
4691+}
4692+
4df546eb 4693+int sys_acl_delete_def_file(UNUSED(const char *name))
fa26e11c
WD
4694+{
4695+ errno = ENOSYS;
4696+ return -1;
4697+}
4698+
4df546eb 4699+int sys_acl_free_acl(UNUSED(SMB_ACL_T the_acl))
fa26e11c
WD
4700+{
4701+ errno = ENOSYS;
4702+ return -1;
4703+}
4704+
4df546eb 4705+int sys_acl_free_qualifier(UNUSED(void *qual), UNUSED(SMB_ACL_TAG_T tagtype))
fa26e11c
WD
4706+{
4707+ errno = ENOSYS;
4708+ return -1;
4709+}
4710+
4711+#endif /* No ACLs. */
252945ef
WD
4712+
4713+/************************************************************************
4714+ Deliberately outside the ACL defines. Return 1 if this is a "no acls"
4715+ errno, 0 if not.
4716+************************************************************************/
4717+
4718+int no_acl_syscall_error(int err)
4719+{
4720+#if defined(ENOSYS)
4721+ if (err == ENOSYS) {
4722+ return 1;
4723+ }
4724+#endif
4725+#if defined(ENOTSUP)
4726+ if (err == ENOTSUP) {
4727+ return 1;
4728+ }
4729+#endif
4730+ return 0;
4731+}
9a7eef96
WD
4732--- old/lib/sysacls.h
4733+++ new/lib/sysacls.h
252945ef
WD
4734@@ -0,0 +1,28 @@
4735+#define SMB_MALLOC(cnt) new_array(char, cnt)
4736+#define SMB_MALLOC_P(obj) new_array(obj, 1)
4737+#define SMB_MALLOC_ARRAY(obj, cnt) new_array(obj, cnt)
4738+#define SMB_REALLOC(mem, cnt) realloc_array(mem, char, cnt)
5ca9317d 4739+#define slprintf snprintf
0f6733d8
WD
4740+
4741+int sys_acl_get_entry(SMB_ACL_T the_acl, int entry_id, SMB_ACL_ENTRY_T *entry_p);
4742+int sys_acl_get_tag_type(SMB_ACL_ENTRY_T entry_d, SMB_ACL_TAG_T *tag_type_p);
4743+int sys_acl_get_permset(SMB_ACL_ENTRY_T entry_d, SMB_ACL_PERMSET_T *permset_p);
4744+void *sys_acl_get_qualifier(SMB_ACL_ENTRY_T entry_d);
4745+SMB_ACL_T sys_acl_get_file(const char *path_p, SMB_ACL_TYPE_T type);
4746+SMB_ACL_T sys_acl_get_fd(int fd);
4747+int sys_acl_clear_perms(SMB_ACL_PERMSET_T permset);
4748+int sys_acl_add_perm(SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm);
4749+int sys_acl_get_perm(SMB_ACL_PERMSET_T permset, SMB_ACL_PERM_T perm);
4750+char *sys_acl_to_text(SMB_ACL_T the_acl, ssize_t *plen);
4751+SMB_ACL_T sys_acl_init(int count);
4752+int sys_acl_create_entry(SMB_ACL_T *pacl, SMB_ACL_ENTRY_T *pentry);
4753+int sys_acl_set_tag_type(SMB_ACL_ENTRY_T entry, SMB_ACL_TAG_T tagtype);
4754+int sys_acl_set_qualifier(SMB_ACL_ENTRY_T entry, void *qual);
4755+int sys_acl_set_permset(SMB_ACL_ENTRY_T entry, SMB_ACL_PERMSET_T permset);
4756+int sys_acl_valid(SMB_ACL_T theacl);
4757+int sys_acl_set_file(const char *name, SMB_ACL_TYPE_T acltype, SMB_ACL_T theacl);
4758+int sys_acl_set_fd(int fd, SMB_ACL_T theacl);
4759+int sys_acl_delete_def_file(const char *name);
4760+int sys_acl_free_text(char *text);
4761+int sys_acl_free_acl(SMB_ACL_T the_acl);
4762+int sys_acl_free_qualifier(void *qual, SMB_ACL_TAG_T tagtype);
9a7eef96
WD
4763--- old/mkproto.awk
4764+++ new/mkproto.awk
0f6733d8
WD
4765@@ -58,7 +58,7 @@ BEGIN {
4766 next;
4767 }
4768
bc5988ec
WD
4769-!/^OFF_T|^size_t|^off_t|^pid_t|^unsigned|^mode_t|^DIR|^user|^int|^char|^uint|^uchar|^short|^struct|^BOOL|^void|^time|^const|^RETSIGTYPE/ {
4770+!/^OFF_T|^size_t|^off_t|^pid_t|^id_t|^unsigned|^mode_t|^DIR|^user|^int|^char|^uint|^uchar|^short|^struct|^BOOL|^void|^time|^const|^RETSIGTYPE/ {
0f6733d8
WD
4771 next;
4772 }
4773
9a7eef96
WD
4774--- old/options.c
4775+++ new/options.c
2578e2b6 4776@@ -45,6 +45,7 @@ int copy_dirlinks = 0;
0f6733d8
WD
4777 int copy_links = 0;
4778 int preserve_links = 0;
4779 int preserve_hard_links = 0;
4780+int preserve_acls = 0;
4781 int preserve_perms = 0;
90fa6d68 4782 int preserve_executability = 0;
0f6733d8 4783 int preserve_devices = 0;
2578e2b6 4784@@ -194,6 +195,7 @@ static void print_rsync_version(enum log
0f6733d8
WD
4785 char const *got_socketpair = "no ";
4786 char const *have_inplace = "no ";
4787 char const *hardlinks = "no ";
4788+ char const *acls = "no ";
4789 char const *links = "no ";
4790 char const *ipv6 = "no ";
4791 STRUCT_STAT *dumstat;
2578e2b6 4792@@ -210,6 +212,10 @@ static void print_rsync_version(enum log
0f6733d8
WD
4793 hardlinks = "";
4794 #endif
4795
09fb8f03 4796+#ifdef SUPPORT_ACLS
0f6733d8
WD
4797+ acls = "";
4798+#endif
4799+
09fb8f03 4800 #ifdef SUPPORT_LINKS
0f6733d8
WD
4801 links = "";
4802 #endif
2578e2b6 4803@@ -223,9 +229,9 @@ static void print_rsync_version(enum log
3b05e91f 4804 rprintf(f, "Copyright (C) 1996-2006 by Andrew Tridgell, Wayne Davison, and others.\n");
0f6733d8
WD
4805 rprintf(f, "<http://rsync.samba.org/>\n");
4806 rprintf(f, "Capabilities: %d-bit files, %ssocketpairs, "
bc5988ec
WD
4807- "%shard links, %ssymlinks, batchfiles,\n",
4808+ "%shard links, %sACLs, %ssymlinks, batchfiles,\n",
0f6733d8
WD
4809 (int) (sizeof (OFF_T) * 8),
4810- got_socketpair, hardlinks, links);
4811+ got_socketpair, hardlinks, acls, links);
4812
4813 /* Note that this field may not have type ino_t. It depends
4814 * on the complicated interaction between largefile feature
2578e2b6
WD
4815@@ -295,6 +301,9 @@ void usage(enum logcode F)
4816 rprintf(F," -H, --hard-links preserve hard links\n");
0f6733d8 4817 rprintf(F," -p, --perms preserve permissions\n");
90fa6d68 4818 rprintf(F," -E, --executability preserve the file's executability\n");
25d385b9 4819+#ifdef SUPPORT_ACLS
0f6733d8 4820+ rprintf(F," -A, --acls preserve ACLs (implies --perms)\n");
25d385b9 4821+#endif
90fa6d68
WD
4822 rprintf(F," --chmod=CHMOD change destination permissions\n");
4823 rprintf(F," -o, --owner preserve owner (super-user only)\n");
0f6733d8 4824 rprintf(F," -g, --group preserve group\n");
2578e2b6 4825@@ -410,6 +419,9 @@ static struct poptOption long_options[]
489b0a72
WD
4826 {"no-perms", 0, POPT_ARG_VAL, &preserve_perms, 0, 0, 0 },
4827 {"no-p", 0, POPT_ARG_VAL, &preserve_perms, 0, 0, 0 },
90fa6d68 4828 {"executability", 'E', POPT_ARG_NONE, &preserve_executability, 0, 0, 0 },
489b0a72
WD
4829+ {"acls", 'A', POPT_ARG_NONE, 0, 'A', 0, 0 },
4830+ {"no-acls", 0, POPT_ARG_VAL, &preserve_acls, 0, 0, 0 },
4831+ {"no-A", 0, POPT_ARG_VAL, &preserve_acls, 0, 0, 0 },
4832 {"times", 't', POPT_ARG_VAL, &preserve_times, 1, 0, 0 },
4833 {"no-times", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 },
4834 {"no-t", 0, POPT_ARG_VAL, &preserve_times, 0, 0, 0 },
2578e2b6 4835@@ -1068,6 +1080,23 @@ int parse_arguments(int *argc, const cha
3b05e91f
WD
4836 usage(FINFO);
4837 exit_cleanup(0);
0f6733d8
WD
4838
4839+ case 'A':
4df546eb 4840+#ifdef SUPPORT_ACLS
25d385b9 4841+ preserve_acls = preserve_perms = 1;
489b0a72 4842+ break;
0f6733d8
WD
4843+#else
4844+ /* FIXME: this should probably be ignored with a
4845+ * warning and then countermeasures taken to
4846+ * restrict group and other access in the presence
4847+ * of any more restrictive ACLs, but this is safe
4848+ * for now */
4849+ snprintf(err_buf,sizeof(err_buf),
4850+ "ACLs are not supported on this %s\n",
4851+ am_server ? "server" : "client");
4852+ return 0;
25d385b9 4853+#endif
0f6733d8
WD
4854+
4855+
4856 default:
4857 /* A large opt value means that set_refuse_options()
27a7053c 4858 * turned this option off. */
2578e2b6 4859@@ -1511,6 +1540,10 @@ void server_options(char **args,int *arg
c7bc7375 4860
0f6733d8
WD
4861 if (preserve_hard_links)
4862 argstr[x++] = 'H';
25d385b9 4863+#ifdef SUPPORT_ACLS
0f6733d8
WD
4864+ if (preserve_acls)
4865+ argstr[x++] = 'A';
25d385b9 4866+#endif
0f6733d8
WD
4867 if (preserve_uid)
4868 argstr[x++] = 'o';
4869 if (preserve_gid)
9a7eef96
WD
4870--- old/receiver.c
4871+++ new/receiver.c
2578e2b6 4872@@ -46,6 +46,7 @@ extern int keep_partial;
1a2fa68f
WD
4873 extern int checksum_seed;
4874 extern int inplace;
4875 extern int delay_updates;
4876+extern mode_t orig_umask;
4877 extern struct stats stats;
4878 extern char *log_format;
4879 extern char *tmpdir;
2578e2b6 4880@@ -344,6 +345,10 @@ int recv_files(int f_in, struct file_lis
26c810d8
WD
4881 int itemizing = am_daemon ? daemon_log_format_has_i
4882 : !am_server && log_format_has_i;
4883 int max_phase = protocol_version >= 29 ? 2 : 1;
4884+ int dflt_perms = (ACCESSPERMS & ~orig_umask);
5c8b4e6e 4885+#ifdef SUPPORT_ACLS
26c810d8 4886+ char *parent_dirname = "";
5c8b4e6e 4887+#endif
26c810d8
WD
4888 int i, recv_ok;
4889
4890 if (verbose > 2)
2578e2b6 4891@@ -541,7 +546,16 @@ int recv_files(int f_in, struct file_lis
90fa6d68
WD
4892 * mode based on the local permissions and some heuristics. */
4893 if (!preserve_perms) {
4894 int exists = fd1 != -1;
4895- file->mode = dest_mode(file->mode, st.st_mode, exists);
26c810d8 4896+#ifdef SUPPORT_ACLS
5c8b4e6e
WD
4897+ char *dn = file->dirname ? file->dirname : ".";
4898+ if (parent_dirname != dn
4899+ && strcmp(parent_dirname, dn) != 0) {
4900+ dflt_perms = default_perms_for_dir(dn);
4901+ parent_dirname = dn;
26c810d8
WD
4902+ }
4903+#endif
4904+ file->mode = dest_mode(file->mode, st.st_mode,
4905+ dflt_perms, exists);
90fa6d68
WD
4906 }
4907
4908 /* We now check to see if we are writing file "inplace" */
9a7eef96
WD
4909--- old/rsync.c
4910+++ new/rsync.c
c769ea2c 4911@@ -101,7 +101,8 @@ void free_sums(struct sum_struct *s)
90fa6d68
WD
4912
4913 /* This is only called when we aren't preserving permissions. Figure out what
4914 * the permissions should be and return them merged back into the mode. */
02929d4c
WD
4915-mode_t dest_mode(mode_t flist_mode, mode_t cur_mode, int exists)
4916+mode_t dest_mode(mode_t flist_mode, mode_t cur_mode, int dflt_perms,
26c810d8 4917+ int exists)
90fa6d68 4918 {
25d385b9 4919 /* If the file already exists, we'll return the local permissions,
90fa6d68 4920 * possibly tweaked by the --executability option. */
c769ea2c 4921@@ -116,7 +117,7 @@ mode_t dest_mode(mode_t flist_mode, mode
02929d4c 4922 cur_mode |= (cur_mode & 0444) >> 2;
90fa6d68 4923 }
26c810d8 4924 } else
02929d4c 4925- cur_mode = flist_mode & ACCESSPERMS & ~orig_umask;
81ddc4dc 4926+ cur_mode = flist_mode & ACCESSPERMS & dflt_perms;
c769ea2c
WD
4927 if (daemon_chmod_modes && !S_ISLNK(flist_mode))
4928 cur_mode = tweak_mode(cur_mode, daemon_chmod_modes);
02929d4c 4929 return (flist_mode & ~CHMOD_BITS) | (cur_mode & CHMOD_BITS);
36aa3171
WD
4930@@ -203,6 +204,13 @@ int set_file_attrs(char *fname, struct f
4931 updated = 1;
0f6733d8 4932 }
0f6733d8 4933
e6a7303b 4934+#ifdef SUPPORT_ACLS
36aa3171
WD
4935+ /* It's OK to call set_acl() now, even for a dir, as the generator
4936+ * will enable owner-writability using chmod, if necessary. */
e6a7303b 4937+ if (set_acl(fname, file) == 0)
81ddc4dc 4938+ updated = 1;
e6a7303b 4939+#endif
0f6733d8 4940+
36aa3171
WD
4941 #ifdef HAVE_CHMOD
4942 if ((st->st_mode & CHMOD_BITS) != (file->mode & CHMOD_BITS)) {
4943 int ret = do_chmod(fname, file->mode);
9a7eef96
WD
4944--- old/rsync.h
4945+++ new/rsync.h
e6a7303b 4946@@ -658,6 +658,20 @@ struct chmod_mode_struct;
bc5988ec
WD
4947
4948 #define UNUSED(x) x __attribute__((__unused__))
0f6733d8 4949
4df546eb
WD
4950+#if HAVE_POSIX_ACLS|HAVE_UNIXWARE_ACLS|HAVE_SOLARIS_ACLS|\
4951+ HAVE_HPUX_ACLS|HAVE_IRIX_ACLS|HAVE_AIX_ACLS|HAVE_TRU64_ACLS
4952+#define SUPPORT_ACLS 1
4953+#endif
0f6733d8 4954+
4df546eb
WD
4955+#if HAVE_UNIXWARE_ACLS|HAVE_SOLARIS_ACLS|HAVE_HPUX_ACLS
4956+#define ACLS_NEED_MASK 1
4957+#endif
0f6733d8 4958+
e6a7303b 4959+#if defined SUPPORT_ACLS && defined HAVE_SYS_ACL_H
0f6733d8
WD
4960+#include <sys/acl.h>
4961+#endif
0f6733d8
WD
4962+#include "smb_acls.h"
4963+
4964 #include "proto.h"
4965
4966 /* We have replacement versions of these if they're missing. */
9a7eef96
WD
4967--- old/rsync.yo
4968+++ new/rsync.yo
2578e2b6
WD
4969@@ -321,6 +321,7 @@ to the detailed description below for a
4970 -H, --hard-links preserve hard links
0f6733d8 4971 -p, --perms preserve permissions
90fa6d68
WD
4972 -E, --executability preserve executability
4973+ -A, --acls preserve ACLs (implies -p) [non-standard]
4974 --chmod=CHMOD change destination permissions
4975 -o, --owner preserve owner (super-user only)
0f6733d8 4976 -g, --group preserve group
2578e2b6 4977@@ -742,7 +743,9 @@ quote(itemize(
90fa6d68
WD
4978 permissions, though the bf(--executability) option might change just
4979 the execute permission for the file.
03baf100
WD
4980 it() New files get their "normal" permission bits set to the source
4981- file's permissions masked with the receiving end's umask setting, and
4982+ file's permissions masked with the receiving directory's default
4983+ permissions (either the receiving process's umask, or the permissions
4984+ specified via the destination directory's default ACL), and
4985 their special permission bits disabled except in the case where a new
4986 directory inherits a setgid bit from its parent directory.
90fa6d68 4987 ))
2578e2b6 4988@@ -773,9 +776,11 @@ The preservation of the destination's se
03baf100
WD
4989 directories when bf(--perms) is off was added in rsync 2.6.7. Older rsync
4990 versions erroneously preserved the three special permission bits for
4991 newly-created files when bf(--perms) was off, while overriding the
4992-destination's setgid bit setting on a newly-created directory. (Keep in
4993-mind that it is the version of the receiving rsync that affects this
4994-behavior.)
4995+destination's setgid bit setting on a newly-created directory. Default ACL
4996+observance was added to the ACL patch for rsync 2.6.7, so older (or
4997+non-ACL-enabled) rsyncs use the umask even if default ACLs are present.
4998+(Keep in mind that it is the version of the receiving rsync that affects
4999+these behaviors.)
90fa6d68 5000
90fa6d68
WD
5001 dit(bf(-E, --executability)) This option causes rsync to preserve the
5002 executability (or non-executability) of regular files when bf(--perms) is
2578e2b6 5003@@ -793,6 +798,10 @@ quote(itemize(
90fa6d68
WD
5004
5005 If bf(--perms) is enabled, this option is ignored.
5006
5007+dit(bf(-A, --acls)) This option causes rsync to update the destination
5008+ACLs to be the same as the source ACLs. This nonstandard option only
5009+works if the remote rsync also supports it. bf(--acls) implies bf(--perms).
5010+
5011 dit(bf(--chmod)) This option tells rsync to apply one or more
5012 comma-separated "chmod" strings to the permission of the files in the
5013 transfer. The resulting value is treated as though it was the permissions
9a7eef96
WD
5014--- old/smb_acls.h
5015+++ new/smb_acls.h
0f6733d8
WD
5016@@ -0,0 +1,277 @@
5017+/*
5018+ Unix SMB/Netbios implementation.
5019+ Version 2.2.x
5020+ Portable SMB ACL interface
5021+ Copyright (C) Jeremy Allison 2000
5022+
5023+ This program is free software; you can redistribute it and/or modify
5024+ it under the terms of the GNU General Public License as published by
5025+ the Free Software Foundation; either version 2 of the License, or
5026+ (at your option) any later version.
5027+
5028+ This program is distributed in the hope that it will be useful,
5029+ but WITHOUT ANY WARRANTY; without even the implied warranty of
5030+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
5031+ GNU General Public License for more details.
5032+
5033+ You should have received a copy of the GNU General Public License
5034+ along with this program; if not, write to the Free Software
5035+ Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
5036+*/
5037+
5038+#ifndef _SMB_ACLS_H
5039+#define _SMB_ACLS_H
5040+
e6a7303b 5041+#if defined HAVE_POSIX_ACLS
0f6733d8
WD
5042+
5043+/* This is an identity mapping (just remove the SMB_). */
5044+
5045+#define SMB_ACL_TAG_T acl_tag_t
5046+#define SMB_ACL_TYPE_T acl_type_t
5047+#define SMB_ACL_PERMSET_T acl_permset_t
5048+#define SMB_ACL_PERM_T acl_perm_t
5049+#define SMB_ACL_READ ACL_READ
5050+#define SMB_ACL_WRITE ACL_WRITE
5051+#define SMB_ACL_EXECUTE ACL_EXECUTE
5052+
5053+/* Types of ACLs. */
5054+#define SMB_ACL_USER ACL_USER
5055+#define SMB_ACL_USER_OBJ ACL_USER_OBJ
5056+#define SMB_ACL_GROUP ACL_GROUP
5057+#define SMB_ACL_GROUP_OBJ ACL_GROUP_OBJ
5058+#define SMB_ACL_OTHER ACL_OTHER
5059+#define SMB_ACL_MASK ACL_MASK
5060+
5061+#define SMB_ACL_T acl_t
5062+
5063+#define SMB_ACL_ENTRY_T acl_entry_t
5064+
5065+#define SMB_ACL_FIRST_ENTRY ACL_FIRST_ENTRY
5066+#define SMB_ACL_NEXT_ENTRY ACL_NEXT_ENTRY
5067+
5068+#define SMB_ACL_TYPE_ACCESS ACL_TYPE_ACCESS
5069+#define SMB_ACL_TYPE_DEFAULT ACL_TYPE_DEFAULT
5070+
e6a7303b 5071+#elif defined HAVE_TRU64_ACLS
0f6733d8
WD
5072+
5073+/* This is for DEC/Compaq Tru64 UNIX */
5074+
5075+#define SMB_ACL_TAG_T acl_tag_t
5076+#define SMB_ACL_TYPE_T acl_type_t
5077+#define SMB_ACL_PERMSET_T acl_permset_t
5078+#define SMB_ACL_PERM_T acl_perm_t
5079+#define SMB_ACL_READ ACL_READ
5080+#define SMB_ACL_WRITE ACL_WRITE
5081+#define SMB_ACL_EXECUTE ACL_EXECUTE
5082+
5083+/* Types of ACLs. */
5084+#define SMB_ACL_USER ACL_USER
5085+#define SMB_ACL_USER_OBJ ACL_USER_OBJ
5086+#define SMB_ACL_GROUP ACL_GROUP
5087+#define SMB_ACL_GROUP_OBJ ACL_GROUP_OBJ
5088+#define SMB_ACL_OTHER ACL_OTHER
5089+#define SMB_ACL_MASK ACL_MASK
5090+
5091+#define SMB_ACL_T acl_t
5092+
5093+#define SMB_ACL_ENTRY_T acl_entry_t
5094+
5095+#define SMB_ACL_FIRST_ENTRY 0
5096+#define SMB_ACL_NEXT_ENTRY 1
5097+
5098+#define SMB_ACL_TYPE_ACCESS ACL_TYPE_ACCESS
5099+#define SMB_ACL_TYPE_DEFAULT ACL_TYPE_DEFAULT
5100+
e6a7303b 5101+#elif defined HAVE_UNIXWARE_ACLS || defined HAVE_SOLARIS_ACLS
0f6733d8
WD
5102+/*
5103+ * Donated by Michael Davidson <md@sco.COM> for UnixWare / OpenUNIX.
5104+ * Modified by Toomas Soome <tsoome@ut.ee> for Solaris.
5105+ */
5106+
5107+/* SVR4.2 ES/MP ACLs */
5108+typedef int SMB_ACL_TAG_T;
5109+typedef int SMB_ACL_TYPE_T;
5110+typedef ushort *SMB_ACL_PERMSET_T;
5111+typedef ushort SMB_ACL_PERM_T;
5112+#define SMB_ACL_READ 4
5113+#define SMB_ACL_WRITE 2
5114+#define SMB_ACL_EXECUTE 1
5115+
5116+/* Types of ACLs. */
5117+#define SMB_ACL_USER USER
5118+#define SMB_ACL_USER_OBJ USER_OBJ
5119+#define SMB_ACL_GROUP GROUP
5120+#define SMB_ACL_GROUP_OBJ GROUP_OBJ
5121+#define SMB_ACL_OTHER OTHER_OBJ
5122+#define SMB_ACL_MASK CLASS_OBJ
5123+
5124+typedef struct SMB_ACL_T {
5125+ int size;
5126+ int count;
5127+ int next;
5128+ struct acl acl[1];
5129+} *SMB_ACL_T;
5130+
5131+typedef struct acl *SMB_ACL_ENTRY_T;
5132+
5133+#define SMB_ACL_FIRST_ENTRY 0
5134+#define SMB_ACL_NEXT_ENTRY 1
5135+
5136+#define SMB_ACL_TYPE_ACCESS 0
5137+#define SMB_ACL_TYPE_DEFAULT 1
5138+
e6a7303b 5139+#elif defined HAVE_HPUX_ACLS
0f6733d8
WD
5140+
5141+/*
5142+ * Based on the Solaris & UnixWare code.
5143+ */
5144+
5145+#undef GROUP
5146+#include <sys/aclv.h>
5147+
5148+/* SVR4.2 ES/MP ACLs */
5149+typedef int SMB_ACL_TAG_T;
5150+typedef int SMB_ACL_TYPE_T;
5151+typedef ushort *SMB_ACL_PERMSET_T;
5152+typedef ushort SMB_ACL_PERM_T;
5153+#define SMB_ACL_READ 4
5154+#define SMB_ACL_WRITE 2
5155+#define SMB_ACL_EXECUTE 1
5156+
5157+/* Types of ACLs. */
5158+#define SMB_ACL_USER USER
5159+#define SMB_ACL_USER_OBJ USER_OBJ
5160+#define SMB_ACL_GROUP GROUP
5161+#define SMB_ACL_GROUP_OBJ GROUP_OBJ
5162+#define SMB_ACL_OTHER OTHER_OBJ
5163+#define SMB_ACL_MASK CLASS_OBJ
5164+
5165+typedef struct SMB_ACL_T {
5166+ int size;
5167+ int count;
5168+ int next;
5169+ struct acl acl[1];
5170+} *SMB_ACL_T;
5171+
5172+typedef struct acl *SMB_ACL_ENTRY_T;
5173+
5174+#define SMB_ACL_FIRST_ENTRY 0
5175+#define SMB_ACL_NEXT_ENTRY 1
5176+
5177+#define SMB_ACL_TYPE_ACCESS 0
5178+#define SMB_ACL_TYPE_DEFAULT 1
5179+
e6a7303b 5180+#elif defined HAVE_IRIX_ACLS
0f6733d8
WD
5181+
5182+#define SMB_ACL_TAG_T acl_tag_t
5183+#define SMB_ACL_TYPE_T acl_type_t
5184+#define SMB_ACL_PERMSET_T acl_permset_t
5185+#define SMB_ACL_PERM_T acl_perm_t
5186+#define SMB_ACL_READ ACL_READ
5187+#define SMB_ACL_WRITE ACL_WRITE
5188+#define SMB_ACL_EXECUTE ACL_EXECUTE
5189+
5190+/* Types of ACLs. */
5191+#define SMB_ACL_USER ACL_USER
5192+#define SMB_ACL_USER_OBJ ACL_USER_OBJ
5193+#define SMB_ACL_GROUP ACL_GROUP
5194+#define SMB_ACL_GROUP_OBJ ACL_GROUP_OBJ
5195+#define SMB_ACL_OTHER ACL_OTHER_OBJ
5196+#define SMB_ACL_MASK ACL_MASK
5197+
5198+typedef struct SMB_ACL_T {
5199+ int next;
5200+ BOOL freeaclp;
5201+ struct acl *aclp;
5202+} *SMB_ACL_T;
5203+
5204+#define SMB_ACL_ENTRY_T acl_entry_t
5205+
5206+#define SMB_ACL_FIRST_ENTRY 0
5207+#define SMB_ACL_NEXT_ENTRY 1
5208+
5209+#define SMB_ACL_TYPE_ACCESS ACL_TYPE_ACCESS
5210+#define SMB_ACL_TYPE_DEFAULT ACL_TYPE_DEFAULT
5211+
e6a7303b 5212+#elif defined HAVE_AIX_ACLS
0f6733d8
WD
5213+
5214+/* Donated by Medha Date, mdate@austin.ibm.com, for IBM */
5215+
5216+#include "/usr/include/acl.h"
5217+
5218+typedef uint *SMB_ACL_PERMSET_T;
5219+
5220+struct acl_entry_link{
5221+ struct acl_entry_link *prevp;
5222+ struct new_acl_entry *entryp;
5223+ struct acl_entry_link *nextp;
5224+ int count;
5225+};
5226+
5227+struct new_acl_entry{
5228+ unsigned short ace_len;
5229+ unsigned short ace_type;
5230+ unsigned int ace_access;
5231+ struct ace_id ace_id[1];
5232+};
5233+
5234+#define SMB_ACL_ENTRY_T struct new_acl_entry*
5235+#define SMB_ACL_T struct acl_entry_link*
5236+
5237+#define SMB_ACL_TAG_T unsigned short
5238+#define SMB_ACL_TYPE_T int
5239+#define SMB_ACL_PERM_T uint
5240+#define SMB_ACL_READ S_IRUSR
5241+#define SMB_ACL_WRITE S_IWUSR
5242+#define SMB_ACL_EXECUTE S_IXUSR
5243+
5244+/* Types of ACLs. */
5245+#define SMB_ACL_USER ACEID_USER
5246+#define SMB_ACL_USER_OBJ 3
5247+#define SMB_ACL_GROUP ACEID_GROUP
5248+#define SMB_ACL_GROUP_OBJ 4
5249+#define SMB_ACL_OTHER 5
5250+#define SMB_ACL_MASK 6
5251+
5252+
5253+#define SMB_ACL_FIRST_ENTRY 1
5254+#define SMB_ACL_NEXT_ENTRY 2
5255+
5256+#define SMB_ACL_TYPE_ACCESS 0
5257+#define SMB_ACL_TYPE_DEFAULT 1
5258+
5259+#else /* No ACLs. */
5260+
5261+/* No ACLS - fake it. */
5262+#define SMB_ACL_TAG_T int
5263+#define SMB_ACL_TYPE_T int
5264+#define SMB_ACL_PERMSET_T mode_t
5265+#define SMB_ACL_PERM_T mode_t
5266+#define SMB_ACL_READ S_IRUSR
5267+#define SMB_ACL_WRITE S_IWUSR
5268+#define SMB_ACL_EXECUTE S_IXUSR
5269+
5270+/* Types of ACLs. */
5271+#define SMB_ACL_USER 0
5272+#define SMB_ACL_USER_OBJ 1
5273+#define SMB_ACL_GROUP 2
5274+#define SMB_ACL_GROUP_OBJ 3
5275+#define SMB_ACL_OTHER 4
5276+#define SMB_ACL_MASK 5
5277+
5278+typedef struct SMB_ACL_T {
5279+ int dummy;
5280+} *SMB_ACL_T;
5281+
5282+typedef struct SMB_ACL_ENTRY_T {
5283+ int dummy;
5284+} *SMB_ACL_ENTRY_T;
5285+
5286+#define SMB_ACL_FIRST_ENTRY 0
5287+#define SMB_ACL_NEXT_ENTRY 1
5288+
5289+#define SMB_ACL_TYPE_ACCESS 0
5290+#define SMB_ACL_TYPE_DEFAULT 1
5291+
5292+#endif /* No ACLs. */
5293+#endif /* _SMB_ACLS_H */
9a7eef96
WD
5294--- old/testsuite/default-acls.test
5295+++ new/testsuite/default-acls.test
bb81ee98 5296@@ -0,0 +1,55 @@
90fa6d68
WD
5297+#! /bin/sh
5298+
5299+# This program is distributable under the terms of the GNU GPL see
5300+# COPYING).
5301+
5302+# Test that rsync obeys default ACLs. -- Matt McCutchen
5303+
5304+. $srcdir/testsuite/rsync.fns
5305+
25d385b9 5306+$RSYNC --version | grep ", ACLs" >/dev/null || test_skipped "Rsync is configured without ACL support"
90fa6d68
WD
5307+setfacl -dm u::rwx,g::---,o::--- "$scratchdir" || test_skipped "Your filesystem has ACLs disabled"
5308+
90fa6d68 5309+# Call as: testit <dirname> <default-acl> <file-expected> <program-expected>
25d385b9 5310+testit() {
90fa6d68
WD
5311+ todir="$scratchdir/$1"
5312+ mkdir "$todir"
25d385b9 5313+ # FIXME This doesn't work on solaris...
90fa6d68 5314+ setfacl -k "$todir"
90fa6d68
WD
5315+ [ "$2" ] && setfacl -dm "$2" "$todir"
5316+ # Make sure we obey ACLs when creating a directory to hold multiple transferred files,
5317+ # even though the directory itself is outside the transfer
25d385b9 5318+ $RSYNC -rvv "$scratchdir/dir" "$scratchdir/file" "$scratchdir/program" "$todir/to/"
0251480d 5319+ check_perms "$todir/to" $4 "Target $1"
25d385b9 5320+ check_perms "$todir/to/dir" $4 "Target $1"
0251480d
WD
5321+ check_perms "$todir/to/file" $3 "Target $1"
5322+ check_perms "$todir/to/program" $4 "Target $1"
90fa6d68
WD
5323+ # Make sure get_local_name doesn't mess us up when transferring only one file
5324+ $RSYNC -rvv "$scratchdir/file" "$todir/to/anotherfile"
0251480d 5325+ check_perms "$todir/to/anotherfile" $3 "Target $1"
bb81ee98 5326+ # Make sure we obey default ACLs when not transferring a regular file
2578e2b6 5327+ $RSYNC -rvv "$scratchdir/dir/" "$todir/to/anotherdir/"
bb81ee98 5328+ check_perms "$todir/to/anotherdir" $4 "Target $1"
90fa6d68
WD
5329+}
5330+
25d385b9 5331+mkdir "$scratchdir/dir"
0251480d 5332+echo "File!" >"$scratchdir/file"
25d385b9
WD
5333+echo "#!/bin/sh" >"$scratchdir/program"
5334+chmod 777 "$scratchdir/dir"
0251480d
WD
5335+chmod 666 "$scratchdir/file"
5336+chmod 777 "$scratchdir/program"
5337+
90fa6d68
WD
5338+# Test some target directories
5339+umask 0077
0251480d
WD
5340+testit da777 u::rwx,g::rwx,o::rwx rw-rw-rw- rwxrwxrwx
5341+testit da775 u::rwx,g::rwx,o::r-x rw-rw-r-- rwxrwxr-x
5342+testit da750 u::rwx,g::r-x,o::--- rw-r----- rwxr-x---
5343+testit da770mask u::rwx,g::---,m::rwx,o::--- rw-rw---- rwxrwx---
5344+testit noda1 '' rw------- rwx------
90fa6d68 5345+umask 0000
0251480d 5346+testit noda2 '' rw-rw-rw- rwxrwxrwx
90fa6d68 5347+umask 0022
0251480d 5348+testit noda3 '' rw-r--r-- rwxr-xr-x
90fa6d68
WD
5349+
5350+# Hooray
5351+exit 0
9a7eef96
WD
5352--- old/uidlist.c
5353+++ new/uidlist.c
fa26e11c
WD
5354@@ -34,6 +34,7 @@
5355 extern int verbose;
5356 extern int preserve_uid;
5357 extern int preserve_gid;
5358+extern int preserve_acls;
5359 extern int numeric_ids;
5360 extern int am_root;
5361
5362@@ -274,7 +275,7 @@ void send_uid_list(int f)
5363 if (numeric_ids)
5364 return;
5365
5366- if (preserve_uid) {
5367+ if (preserve_uid || preserve_acls) {
5368 int len;
5369 /* we send sequences of uid/byte-length/name */
5370 for (list = uidlist; list; list = list->next) {
5371@@ -291,7 +292,7 @@ void send_uid_list(int f)
5372 write_int(f, 0);
5373 }
5374
5375- if (preserve_gid) {
5376+ if (preserve_gid || preserve_acls) {
5377 int len;
5378 for (list = gidlist; list; list = list->next) {
5379 if (!list->name)
5380@@ -312,7 +313,7 @@ void recv_uid_list(int f, struct file_li
5381 int id, i;
5382 char *name;
5383
5384- if (preserve_uid && !numeric_ids) {
5385+ if ((preserve_uid || preserve_acls) && !numeric_ids) {
5386 /* read the uid list */
5387 while ((id = read_int(f)) != 0) {
5388 int len = read_byte(f);
6849cd84
WD
5389@@ -324,7 +325,7 @@ void recv_uid_list(int f, struct file_li
5390 }
fa26e11c
WD
5391 }
5392
fa26e11c
WD
5393- if (preserve_gid && !numeric_ids) {
5394+ if ((preserve_gid || preserve_acls) && !numeric_ids) {
5395 /* read the gid list */
5396 while ((id = read_int(f)) != 0) {
5397 int len = read_byte(f);
6849cd84 5398@@ -336,6 +337,18 @@ void recv_uid_list(int f, struct file_li
fa26e11c
WD
5399 }
5400 }
125d7fca 5401
4edb99c8 5402+#ifdef SUPPORT_ACLS
fa26e11c
WD
5403+ if (preserve_acls && !numeric_ids) {
5404+ id_t id;
4edb99c8
WD
5405+ /* The enumerations don't return 0 except to flag the last
5406+ * entry, since uidlist doesn't munge 0 anyway. */
5407+ while ((id = next_acl_uid(flist)) != 0)
fa26e11c 5408+ acl_uid_map(match_uid(id));
4edb99c8 5409+ while ((id = next_acl_gid(flist)) != 0)
fa26e11c
WD
5410+ acl_gid_map(match_gid(id));
5411+ }
5412+#endif /* SUPPORT_ACLS */
125d7fca 5413+
90fa6d68 5414 /* Now convert all the uids/gids from sender values to our values. */
125d7fca 5415 if (am_root && preserve_uid && !numeric_ids) {
90fa6d68 5416 for (i = 0; i < flist->count; i++)