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