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