1/*
2   Unix SMB/CIFS implementation.
3   SMB NT Security Descriptor / Unix permission conversion.
4   Copyright (C) Jeremy Allison 1994-2000.
5   Copyright (C) Andreas Gruenbacher 2002.
6
7   This program is free software; you can redistribute it and/or modify
8   it under the terms of the GNU General Public License as published by
9   the Free Software Foundation; either version 2 of the License, or
10   (at your option) any later version.
11
12   This program is distributed in the hope that it will be useful,
13   but WITHOUT ANY WARRANTY; without even the implied warranty of
14   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15   GNU General Public License for more details.
16
17   You should have received a copy of the GNU General Public License
18   along with this program; if not, write to the Free Software
19   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20*/
21
22#include "includes.h"
23
24#undef  DBGC_CLASS
25#define DBGC_CLASS DBGC_ACLS
26
27/****************************************************************************
28 Data structures representing the internal ACE format.
29****************************************************************************/
30
31enum ace_owner {UID_ACE, GID_ACE, WORLD_ACE};
32enum ace_attribute {ALLOW_ACE, DENY_ACE}; /* Used for incoming NT ACLS. */
33
34typedef union posix_id {
35		uid_t uid;
36		gid_t gid;
37		int world;
38} posix_id;
39
40typedef struct canon_ace {
41	struct canon_ace *next, *prev;
42	SMB_ACL_TAG_T type;
43	mode_t perms; /* Only use S_I(R|W|X)USR mode bits here. */
44	DOM_SID trustee;
45	enum ace_owner owner_type;
46	enum ace_attribute attr;
47	posix_id unix_ug;
48	BOOL inherited;
49} canon_ace;
50
51#define ALL_ACE_PERMS (S_IRUSR|S_IWUSR|S_IXUSR)
52
53/*
54 * EA format of user.SAMBA_PAI (Samba_Posix_Acl_Interitance)
55 * attribute on disk.
56 *
57 * |  1   |  1   |   2         |         2           |  ....
58 * +------+------+-------------+---------------------+-------------+--------------------+
59 * | vers | flag | num_entries | num_default_entries | ..entries.. | default_entries... |
60 * +------+------+-------------+---------------------+-------------+--------------------+
61 */
62
63#define PAI_VERSION_OFFSET	0
64#define PAI_FLAG_OFFSET		1
65#define PAI_NUM_ENTRIES_OFFSET	2
66#define PAI_NUM_DEFAULT_ENTRIES_OFFSET	4
67#define PAI_ENTRIES_BASE	6
68
69#define PAI_VERSION		1
70#define PAI_ACL_FLAG_PROTECTED	0x1
71#define PAI_ENTRY_LENGTH	5
72
73/*
74 * In memory format of user.SAMBA_PAI attribute.
75 */
76
77struct pai_entry {
78	struct pai_entry *next, *prev;
79	enum ace_owner owner_type;
80	posix_id unix_ug;
81};
82
83struct pai_val {
84	BOOL protected;
85	unsigned int num_entries;
86	struct pai_entry *entry_list;
87	unsigned int num_def_entries;
88	struct pai_entry *def_entry_list;
89};
90
91/************************************************************************
92 Return a uint32 of the pai_entry principal.
93************************************************************************/
94
95static uint32 get_pai_entry_val(struct pai_entry *paie)
96{
97	switch (paie->owner_type) {
98		case UID_ACE:
99			DEBUG(10,("get_pai_entry_val: uid = %u\n", (unsigned int)paie->unix_ug.uid ));
100			return (uint32)paie->unix_ug.uid;
101		case GID_ACE:
102			DEBUG(10,("get_pai_entry_val: gid = %u\n", (unsigned int)paie->unix_ug.gid ));
103			return (uint32)paie->unix_ug.gid;
104		case WORLD_ACE:
105		default:
106			DEBUG(10,("get_pai_entry_val: world ace\n"));
107			return (uint32)-1;
108	}
109}
110
111/************************************************************************
112 Return a uint32 of the entry principal.
113************************************************************************/
114
115static uint32 get_entry_val(canon_ace *ace_entry)
116{
117	switch (ace_entry->owner_type) {
118		case UID_ACE:
119			DEBUG(10,("get_entry_val: uid = %u\n", (unsigned int)ace_entry->unix_ug.uid ));
120			return (uint32)ace_entry->unix_ug.uid;
121		case GID_ACE:
122			DEBUG(10,("get_entry_val: gid = %u\n", (unsigned int)ace_entry->unix_ug.gid ));
123			return (uint32)ace_entry->unix_ug.gid;
124		case WORLD_ACE:
125		default:
126			DEBUG(10,("get_entry_val: world ace\n"));
127			return (uint32)-1;
128	}
129}
130
131/************************************************************************
132 Count the inherited entries.
133************************************************************************/
134
135static unsigned int num_inherited_entries(canon_ace *ace_list)
136{
137	unsigned int num_entries = 0;
138
139	for (; ace_list; ace_list = ace_list->next)
140		if (ace_list->inherited)
141			num_entries++;
142	return num_entries;
143}
144
145/************************************************************************
146 Create the on-disk format. Caller must free.
147************************************************************************/
148
149static char *create_pai_buf(canon_ace *file_ace_list, canon_ace *dir_ace_list, BOOL protected, size_t *store_size)
150{
151	char *pai_buf = NULL;
152	canon_ace *ace_list = NULL;
153	char *entry_offset = NULL;
154	unsigned int num_entries = 0;
155	unsigned int num_def_entries = 0;
156
157	for (ace_list = file_ace_list; ace_list; ace_list = ace_list->next)
158		if (ace_list->inherited)
159			num_entries++;
160
161	for (ace_list = dir_ace_list; ace_list; ace_list = ace_list->next)
162		if (ace_list->inherited)
163			num_def_entries++;
164
165	DEBUG(10,("create_pai_buf: num_entries = %u, num_def_entries = %u\n", num_entries, num_def_entries ));
166
167	*store_size = PAI_ENTRIES_BASE + ((num_entries + num_def_entries)*PAI_ENTRY_LENGTH);
168
169	pai_buf = SMB_MALLOC(*store_size);
170	if (!pai_buf) {
171		return NULL;
172	}
173
174	/* Set up the header. */
175	memset(pai_buf, '\0', PAI_ENTRIES_BASE);
176	SCVAL(pai_buf,PAI_VERSION_OFFSET,PAI_VERSION);
177	SCVAL(pai_buf,PAI_FLAG_OFFSET,(protected ? PAI_ACL_FLAG_PROTECTED : 0));
178	SSVAL(pai_buf,PAI_NUM_ENTRIES_OFFSET,num_entries);
179	SSVAL(pai_buf,PAI_NUM_DEFAULT_ENTRIES_OFFSET,num_def_entries);
180
181	entry_offset = pai_buf + PAI_ENTRIES_BASE;
182
183	for (ace_list = file_ace_list; ace_list; ace_list = ace_list->next) {
184		if (ace_list->inherited) {
185			uint8 type_val = (unsigned char)ace_list->owner_type;
186			uint32 entry_val = get_entry_val(ace_list);
187
188			SCVAL(entry_offset,0,type_val);
189			SIVAL(entry_offset,1,entry_val);
190			entry_offset += PAI_ENTRY_LENGTH;
191		}
192	}
193
194	for (ace_list = dir_ace_list; ace_list; ace_list = ace_list->next) {
195		if (ace_list->inherited) {
196			uint8 type_val = (unsigned char)ace_list->owner_type;
197			uint32 entry_val = get_entry_val(ace_list);
198
199			SCVAL(entry_offset,0,type_val);
200			SIVAL(entry_offset,1,entry_val);
201			entry_offset += PAI_ENTRY_LENGTH;
202		}
203	}
204
205	return pai_buf;
206}
207
208/************************************************************************
209 Store the user.SAMBA_PAI attribute on disk.
210************************************************************************/
211
212static void store_inheritance_attributes(files_struct *fsp, canon_ace *file_ace_list,
213					canon_ace *dir_ace_list, BOOL protected)
214{
215	int ret;
216	size_t store_size;
217	char *pai_buf;
218
219	if (!lp_map_acl_inherit(SNUM(fsp->conn)))
220		return;
221
222	/*
223	 * Don't store if this ACL isn't protected and
224	 * none of the entries in it are marked as inherited.
225	 */
226
227	if (!protected && num_inherited_entries(file_ace_list) == 0 && num_inherited_entries(dir_ace_list) == 0) {
228		/* Instead just remove the attribute if it exists. */
229		if (fsp->fd != -1)
230			SMB_VFS_FREMOVEXATTR(fsp, fsp->fd, SAMBA_POSIX_INHERITANCE_EA_NAME);
231		else
232			SMB_VFS_REMOVEXATTR(fsp->conn, fsp->fsp_name, SAMBA_POSIX_INHERITANCE_EA_NAME);
233		return;
234	}
235
236	pai_buf = create_pai_buf(file_ace_list, dir_ace_list, protected, &store_size);
237
238	if (fsp->fd != -1)
239		ret = SMB_VFS_FSETXATTR(fsp, fsp->fd, SAMBA_POSIX_INHERITANCE_EA_NAME,
240				pai_buf, store_size, 0);
241	else
242		ret = SMB_VFS_SETXATTR(fsp->conn,fsp->fsp_name, SAMBA_POSIX_INHERITANCE_EA_NAME,
243				pai_buf, store_size, 0);
244
245	SAFE_FREE(pai_buf);
246
247	DEBUG(10,("store_inheritance_attribute:%s for file %s\n", protected ? " (protected)" : "", fsp->fsp_name));
248	if (ret == -1 && !no_acl_syscall_error(errno))
249		DEBUG(1,("store_inheritance_attribute: Error %s\n", strerror(errno) ));
250}
251
252/************************************************************************
253 Delete the in memory inheritance info.
254************************************************************************/
255
256static void free_inherited_info(struct pai_val *pal)
257{
258	if (pal) {
259		struct pai_entry *paie, *paie_next;
260		for (paie = pal->entry_list; paie; paie = paie_next) {
261			paie_next = paie->next;
262			SAFE_FREE(paie);
263		}
264		for (paie = pal->def_entry_list; paie; paie = paie_next) {
265			paie_next = paie->next;
266			SAFE_FREE(paie);
267		}
268		SAFE_FREE(pal);
269	}
270}
271
272/************************************************************************
273 Was this ACL protected ?
274************************************************************************/
275
276static BOOL get_protected_flag(struct pai_val *pal)
277{
278	if (!pal)
279		return False;
280	return pal->protected;
281}
282
283/************************************************************************
284 Was this ACE inherited ?
285************************************************************************/
286
287static BOOL get_inherited_flag(struct pai_val *pal, canon_ace *ace_entry, BOOL default_ace)
288{
289	struct pai_entry *paie;
290
291	if (!pal)
292		return False;
293
294	/* If the entry exists it is inherited. */
295	for (paie = (default_ace ? pal->def_entry_list : pal->entry_list); paie; paie = paie->next) {
296		if (ace_entry->owner_type == paie->owner_type &&
297				get_entry_val(ace_entry) == get_pai_entry_val(paie))
298			return True;
299	}
300	return False;
301}
302
303/************************************************************************
304 Ensure an attribute just read is valid.
305************************************************************************/
306
307static BOOL check_pai_ok(char *pai_buf, size_t pai_buf_data_size)
308{
309	uint16 num_entries;
310	uint16 num_def_entries;
311
312	if (pai_buf_data_size < PAI_ENTRIES_BASE) {
313		/* Corrupted - too small. */
314		return False;
315	}
316
317	if (CVAL(pai_buf,PAI_VERSION_OFFSET) != PAI_VERSION)
318		return False;
319
320	num_entries = SVAL(pai_buf,PAI_NUM_ENTRIES_OFFSET);
321	num_def_entries = SVAL(pai_buf,PAI_NUM_DEFAULT_ENTRIES_OFFSET);
322
323	/* Check the entry lists match. */
324	/* Each entry is 5 bytes (type plus 4 bytes of uid or gid). */
325
326	if (((num_entries + num_def_entries)*PAI_ENTRY_LENGTH) + PAI_ENTRIES_BASE != pai_buf_data_size)
327		return False;
328
329	return True;
330}
331
332
333/************************************************************************
334 Convert to in-memory format.
335************************************************************************/
336
337static struct pai_val *create_pai_val(char *buf, size_t size)
338{
339	char *entry_offset;
340	struct pai_val *paiv = NULL;
341	int i;
342
343	if (!check_pai_ok(buf, size))
344		return NULL;
345
346	paiv = SMB_MALLOC_P(struct pai_val);
347	if (!paiv)
348		return NULL;
349
350	memset(paiv, '\0', sizeof(struct pai_val));
351
352	paiv->protected = (CVAL(buf,PAI_FLAG_OFFSET) == PAI_ACL_FLAG_PROTECTED);
353
354	paiv->num_entries = SVAL(buf,PAI_NUM_ENTRIES_OFFSET);
355	paiv->num_def_entries = SVAL(buf,PAI_NUM_DEFAULT_ENTRIES_OFFSET);
356
357	entry_offset = buf + PAI_ENTRIES_BASE;
358
359	DEBUG(10,("create_pai_val:%s num_entries = %u, num_def_entries = %u\n",
360			paiv->protected ? " (protected)" : "", paiv->num_entries, paiv->num_def_entries ));
361
362	for (i = 0; i < paiv->num_entries; i++) {
363		struct pai_entry *paie;
364
365		paie = SMB_MALLOC_P(struct pai_entry);
366		if (!paie) {
367			free_inherited_info(paiv);
368			return NULL;
369		}
370
371		paie->owner_type = (enum ace_owner)CVAL(entry_offset,0);
372		switch( paie->owner_type) {
373			case UID_ACE:
374				paie->unix_ug.uid = (uid_t)IVAL(entry_offset,1);
375				DEBUG(10,("create_pai_val: uid = %u\n", (unsigned int)paie->unix_ug.uid ));
376				break;
377			case GID_ACE:
378				paie->unix_ug.gid = (gid_t)IVAL(entry_offset,1);
379				DEBUG(10,("create_pai_val: gid = %u\n", (unsigned int)paie->unix_ug.gid ));
380				break;
381			case WORLD_ACE:
382				paie->unix_ug.world = -1;
383				DEBUG(10,("create_pai_val: world ace\n"));
384				break;
385			default:
386				free_inherited_info(paiv);
387				return NULL;
388		}
389		entry_offset += PAI_ENTRY_LENGTH;
390		DLIST_ADD(paiv->entry_list, paie);
391	}
392
393	for (i = 0; i < paiv->num_def_entries; i++) {
394		struct pai_entry *paie;
395
396		paie = SMB_MALLOC_P(struct pai_entry);
397		if (!paie) {
398			free_inherited_info(paiv);
399			return NULL;
400		}
401
402		paie->owner_type = (enum ace_owner)CVAL(entry_offset,0);
403		switch( paie->owner_type) {
404			case UID_ACE:
405				paie->unix_ug.uid = (uid_t)IVAL(entry_offset,1);
406				DEBUG(10,("create_pai_val: (def) uid = %u\n", (unsigned int)paie->unix_ug.uid ));
407				break;
408			case GID_ACE:
409				paie->unix_ug.gid = (gid_t)IVAL(entry_offset,1);
410				DEBUG(10,("create_pai_val: (def) gid = %u\n", (unsigned int)paie->unix_ug.gid ));
411				break;
412			case WORLD_ACE:
413				paie->unix_ug.world = -1;
414				DEBUG(10,("create_pai_val: (def) world ace\n"));
415				break;
416			default:
417				free_inherited_info(paiv);
418				return NULL;
419		}
420		entry_offset += PAI_ENTRY_LENGTH;
421		DLIST_ADD(paiv->def_entry_list, paie);
422	}
423
424	return paiv;
425}
426
427/************************************************************************
428 Load the user.SAMBA_PAI attribute.
429************************************************************************/
430
431static struct pai_val *load_inherited_info(files_struct *fsp)
432{
433	char *pai_buf;
434	size_t pai_buf_size = 1024;
435	struct pai_val *paiv = NULL;
436	ssize_t ret;
437
438	if (!lp_map_acl_inherit(SNUM(fsp->conn)))
439		return NULL;
440
441	if ((pai_buf = SMB_MALLOC(pai_buf_size)) == NULL)
442		return NULL;
443
444	do {
445		if (fsp->fd != -1)
446			ret = SMB_VFS_FGETXATTR(fsp, fsp->fd, SAMBA_POSIX_INHERITANCE_EA_NAME,
447					pai_buf, pai_buf_size);
448		else
449			ret = SMB_VFS_GETXATTR(fsp->conn,fsp->fsp_name,SAMBA_POSIX_INHERITANCE_EA_NAME,
450					pai_buf, pai_buf_size);
451
452		if (ret == -1) {
453			if (errno != ERANGE) {
454				break;
455			}
456			/* Buffer too small - enlarge it. */
457			pai_buf_size *= 2;
458			SAFE_FREE(pai_buf);
459			if (pai_buf_size > 1024*1024) {
460				return NULL; /* Limit malloc to 1mb. */
461			}
462			if ((pai_buf = SMB_MALLOC(pai_buf_size)) == NULL)
463				return NULL;
464		}
465	} while (ret == -1);
466
467	DEBUG(10,("load_inherited_info: ret = %lu for file %s\n", (unsigned long)ret, fsp->fsp_name));
468
469	if (ret == -1) {
470		/* No attribute or not supported. */
471#if defined(ENOATTR)
472		if (errno != ENOATTR)
473			DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) ));
474#else
475		if (errno != ENOSYS)
476			DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) ));
477#endif
478		SAFE_FREE(pai_buf);
479		return NULL;
480	}
481
482	paiv = create_pai_val(pai_buf, ret);
483
484	if (paiv && paiv->protected)
485		DEBUG(10,("load_inherited_info: ACL is protected for file %s\n", fsp->fsp_name));
486
487	SAFE_FREE(pai_buf);
488	return paiv;
489}
490
491/****************************************************************************
492 Functions to manipulate the internal ACE format.
493****************************************************************************/
494
495/****************************************************************************
496 Count a linked list of canonical ACE entries.
497****************************************************************************/
498
499static size_t count_canon_ace_list( canon_ace *list_head )
500{
501	size_t count = 0;
502	canon_ace *ace;
503
504	for (ace = list_head; ace; ace = ace->next)
505		count++;
506
507	return count;
508}
509
510/****************************************************************************
511 Free a linked list of canonical ACE entries.
512****************************************************************************/
513
514static void free_canon_ace_list( canon_ace *list_head )
515{
516	while (list_head) {
517		canon_ace *old_head = list_head;
518		DLIST_REMOVE(list_head, list_head);
519		SAFE_FREE(old_head);
520	}
521}
522
523/****************************************************************************
524 Function to duplicate a canon_ace entry.
525****************************************************************************/
526
527static canon_ace *dup_canon_ace( canon_ace *src_ace)
528{
529	canon_ace *dst_ace = SMB_MALLOC_P(canon_ace);
530
531	if (dst_ace == NULL)
532		return NULL;
533
534	*dst_ace = *src_ace;
535	dst_ace->prev = dst_ace->next = NULL;
536	return dst_ace;
537}
538
539/****************************************************************************
540 Print out a canon ace.
541****************************************************************************/
542
543static void print_canon_ace(canon_ace *pace, int num)
544{
545	fstring str;
546
547	dbgtext( "canon_ace index %d. Type = %s ", num, pace->attr == ALLOW_ACE ? "allow" : "deny" );
548	dbgtext( "SID = %s ", sid_to_string( str, &pace->trustee));
549	if (pace->owner_type == UID_ACE) {
550		const char *u_name = uidtoname(pace->unix_ug.uid);
551		dbgtext( "uid %u (%s) ", (unsigned int)pace->unix_ug.uid, u_name );
552	} else if (pace->owner_type == GID_ACE) {
553		char *g_name = gidtoname(pace->unix_ug.gid);
554		dbgtext( "gid %u (%s) ", (unsigned int)pace->unix_ug.gid, g_name );
555	} else
556		dbgtext( "other ");
557	switch (pace->type) {
558		case SMB_ACL_USER:
559			dbgtext( "SMB_ACL_USER ");
560			break;
561		case SMB_ACL_USER_OBJ:
562			dbgtext( "SMB_ACL_USER_OBJ ");
563			break;
564		case SMB_ACL_GROUP:
565			dbgtext( "SMB_ACL_GROUP ");
566			break;
567		case SMB_ACL_GROUP_OBJ:
568			dbgtext( "SMB_ACL_GROUP_OBJ ");
569			break;
570		case SMB_ACL_OTHER:
571			dbgtext( "SMB_ACL_OTHER ");
572			break;
573	}
574	if (pace->inherited)
575		dbgtext( "(inherited) ");
576	dbgtext( "perms ");
577	dbgtext( "%c", pace->perms & S_IRUSR ? 'r' : '-');
578	dbgtext( "%c", pace->perms & S_IWUSR ? 'w' : '-');
579	dbgtext( "%c\n", pace->perms & S_IXUSR ? 'x' : '-');
580}
581
582/****************************************************************************
583 Print out a canon ace list.
584****************************************************************************/
585
586static void print_canon_ace_list(const char *name, canon_ace *ace_list)
587{
588	int count = 0;
589
590	if( DEBUGLVL( 10 )) {
591		dbgtext( "print_canon_ace_list: %s\n", name );
592		for (;ace_list; ace_list = ace_list->next, count++)
593			print_canon_ace(ace_list, count );
594	}
595}
596
597/****************************************************************************
598 Map POSIX ACL perms to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
599****************************************************************************/
600
601static mode_t convert_permset_to_mode_t(connection_struct *conn, SMB_ACL_PERMSET_T permset)
602{
603	mode_t ret = 0;
604
605	ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRUSR : 0);
606	ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWUSR : 0);
607	ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXUSR : 0);
608
609	return ret;
610}
611
612/****************************************************************************
613 Map generic UNIX permissions to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
614****************************************************************************/
615
616static mode_t unix_perms_to_acl_perms(mode_t mode, int r_mask, int w_mask, int x_mask)
617{
618	mode_t ret = 0;
619
620	if (mode & r_mask)
621		ret |= S_IRUSR;
622	if (mode & w_mask)
623		ret |= S_IWUSR;
624	if (mode & x_mask)
625		ret |= S_IXUSR;
626
627	return ret;
628}
629
630/****************************************************************************
631 Map canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits) to
632 an SMB_ACL_PERMSET_T.
633****************************************************************************/
634
635static int map_acl_perms_to_permset(connection_struct *conn, mode_t mode, SMB_ACL_PERMSET_T *p_permset)
636{
637	if (SMB_VFS_SYS_ACL_CLEAR_PERMS(conn, *p_permset) ==  -1)
638		return -1;
639	if (mode & S_IRUSR) {
640		if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_READ) == -1)
641			return -1;
642	}
643	if (mode & S_IWUSR) {
644		if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_WRITE) == -1)
645			return -1;
646	}
647	if (mode & S_IXUSR) {
648		if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_EXECUTE) == -1)
649			return -1;
650	}
651	return 0;
652}
653/****************************************************************************
654 Function to create owner and group SIDs from a SMB_STRUCT_STAT.
655****************************************************************************/
656
657static void create_file_sids(SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SID *pgroup_sid)
658{
659	uid_to_sid( powner_sid, psbuf->st_uid );
660	gid_to_sid( pgroup_sid, psbuf->st_gid );
661}
662
663/****************************************************************************
664 Merge aces with a common sid - if both are allow or deny, OR the permissions together and
665 delete the second one. If the first is deny, mask the permissions off and delete the allow
666 if the permissions become zero, delete the deny if the permissions are non zero.
667****************************************************************************/
668
669static void merge_aces( canon_ace **pp_list_head )
670{
671	canon_ace *list_head = *pp_list_head;
672	canon_ace *curr_ace_outer;
673	canon_ace *curr_ace_outer_next;
674
675	/*
676	 * First, merge allow entries with identical SIDs, and deny entries
677	 * with identical SIDs.
678	 */
679
680	for (curr_ace_outer = list_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
681		canon_ace *curr_ace;
682		canon_ace *curr_ace_next;
683
684		curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
685
686		for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
687
688			curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
689
690			if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
691				(curr_ace->attr == curr_ace_outer->attr)) {
692
693				if( DEBUGLVL( 10 )) {
694					dbgtext("merge_aces: Merging ACE's\n");
695					print_canon_ace( curr_ace_outer, 0);
696					print_canon_ace( curr_ace, 0);
697				}
698
699				/* Merge two allow or two deny ACE's. */
700
701				curr_ace_outer->perms |= curr_ace->perms;
702				DLIST_REMOVE(list_head, curr_ace);
703				SAFE_FREE(curr_ace);
704				curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
705			}
706		}
707	}
708
709	/*
710	 * Now go through and mask off allow permissions with deny permissions.
711	 * We can delete either the allow or deny here as we know that each SID
712	 * appears only once in the list.
713	 */
714
715	for (curr_ace_outer = list_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
716		canon_ace *curr_ace;
717		canon_ace *curr_ace_next;
718
719		curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
720
721		for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
722
723			curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
724
725			/*
726			 * Subtract ACE's with different entries. Due to the ordering constraints
727			 * we've put on the ACL, we know the deny must be the first one.
728			 */
729
730			if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
731				(curr_ace_outer->attr == DENY_ACE) && (curr_ace->attr == ALLOW_ACE)) {
732
733				if( DEBUGLVL( 10 )) {
734					dbgtext("merge_aces: Masking ACE's\n");
735					print_canon_ace( curr_ace_outer, 0);
736					print_canon_ace( curr_ace, 0);
737				}
738
739				curr_ace->perms &= ~curr_ace_outer->perms;
740
741				if (curr_ace->perms == 0) {
742
743					/*
744					 * The deny overrides the allow. Remove the allow.
745					 */
746
747					DLIST_REMOVE(list_head, curr_ace);
748					SAFE_FREE(curr_ace);
749					curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
750
751				} else {
752
753					/*
754					 * Even after removing permissions, there
755					 * are still allow permissions - delete the deny.
756					 * It is safe to delete the deny here,
757					 * as we are guarenteed by the deny first
758					 * ordering that all the deny entries for
759					 * this SID have already been merged into one
760					 * before we can get to an allow ace.
761					 */
762
763					DLIST_REMOVE(list_head, curr_ace_outer);
764					SAFE_FREE(curr_ace_outer);
765					break;
766				}
767			}
768
769		} /* end for curr_ace */
770	} /* end for curr_ace_outer */
771
772	/* We may have modified the list. */
773
774	*pp_list_head = list_head;
775}
776
777/****************************************************************************
778 Check if we need to return NT4.x compatible ACL entries.
779****************************************************************************/
780
781static BOOL nt4_compatible_acls(void)
782{
783	const char *compat = lp_acl_compatibility();
784
785	if (*compat == '\0') {
786		enum remote_arch_types ra_type = get_remote_arch();
787
788		/* Automatically adapt to client */
789		return (ra_type <= RA_WINNT);
790	} else
791		return (strequal(compat, "winnt"));
792}
793
794
795/****************************************************************************
796 Map canon_ace perms to permission bits NT.
797 The attr element is not used here - we only process deny entries on set,
798 not get. Deny entries are implicit on get with ace->perms = 0.
799****************************************************************************/
800
801static SEC_ACCESS map_canon_ace_perms(int *pacl_type, DOM_SID *powner_sid, canon_ace *ace)
802{
803	SEC_ACCESS sa;
804	uint32 nt_mask = 0;
805
806	*pacl_type = SEC_ACE_TYPE_ACCESS_ALLOWED;
807
808	if ((ace->perms & ALL_ACE_PERMS) == ALL_ACE_PERMS) {
809			nt_mask = UNIX_ACCESS_RWX;
810	} else if ((ace->perms & ALL_ACE_PERMS) == (mode_t)0) {
811		/*
812		 * Windows NT refuses to display ACEs with no permissions in them (but
813		 * they are perfectly legal with Windows 2000). If the ACE has empty
814		 * permissions we cannot use 0, so we use the otherwise unused
815		 * WRITE_OWNER permission, which we ignore when we set an ACL.
816		 * We abstract this into a #define of UNIX_ACCESS_NONE to allow this
817		 * to be changed in the future.
818		 */
819
820		if (nt4_compatible_acls())
821			nt_mask = UNIX_ACCESS_NONE;
822		else
823			nt_mask = 0;
824	} else {
825		nt_mask |= ((ace->perms & S_IRUSR) ? UNIX_ACCESS_R : 0 );
826		nt_mask |= ((ace->perms & S_IWUSR) ? UNIX_ACCESS_W : 0 );
827		nt_mask |= ((ace->perms & S_IXUSR) ? UNIX_ACCESS_X : 0 );
828	}
829
830	DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n",
831			(unsigned int)ace->perms, (unsigned int)nt_mask ));
832
833	init_sec_access(&sa,nt_mask);
834	return sa;
835}
836
837/****************************************************************************
838 Map NT perms to a UNIX mode_t.
839****************************************************************************/
840
841#define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES)
842#define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA|FILE_WRITE_ATTRIBUTES)
843#define FILE_SPECIFIC_EXECUTE_BITS (FILE_EXECUTE)
844
845static mode_t map_nt_perms( SEC_ACCESS sec_access, int type)
846{
847	mode_t mode = 0;
848
849	switch(type) {
850	case S_IRUSR:
851		if(sec_access.mask & GENERIC_ALL_ACCESS)
852			mode = S_IRUSR|S_IWUSR|S_IXUSR;
853		else {
854			mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRUSR : 0;
855			mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWUSR : 0;
856			mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXUSR : 0;
857		}
858		break;
859	case S_IRGRP:
860		if(sec_access.mask & GENERIC_ALL_ACCESS)
861			mode = S_IRGRP|S_IWGRP|S_IXGRP;
862		else {
863			mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRGRP : 0;
864			mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWGRP : 0;
865			mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXGRP : 0;
866		}
867		break;
868	case S_IROTH:
869		if(sec_access.mask & GENERIC_ALL_ACCESS)
870			mode = S_IROTH|S_IWOTH|S_IXOTH;
871		else {
872			mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IROTH : 0;
873			mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWOTH : 0;
874			mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXOTH : 0;
875		}
876		break;
877	}
878
879	return mode;
880}
881
882/****************************************************************************
883 Unpack a SEC_DESC into a UNIX owner and group.
884****************************************************************************/
885
886static BOOL unpack_nt_owners(int snum, SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, SEC_DESC *psd)
887{
888	DOM_SID owner_sid;
889	DOM_SID grp_sid;
890
891	*puser = (uid_t)-1;
892	*pgrp = (gid_t)-1;
893
894	if(security_info_sent == 0) {
895		DEBUG(0,("unpack_nt_owners: no security info sent !\n"));
896		return True;
897	}
898
899	/*
900	 * Validate the owner and group SID's.
901	 */
902
903	memset(&owner_sid, '\0', sizeof(owner_sid));
904	memset(&grp_sid, '\0', sizeof(grp_sid));
905
906	DEBUG(5,("unpack_nt_owners: validating owner_sids.\n"));
907
908	/*
909	 * Don't immediately fail if the owner sid cannot be validated.
910	 * This may be a group chown only set.
911	 */
912
913	if (security_info_sent & OWNER_SECURITY_INFORMATION) {
914		sid_copy(&owner_sid, psd->owner_sid);
915		if (!NT_STATUS_IS_OK(sid_to_uid(&owner_sid, puser))) {
916			if (lp_force_unknown_acl_user(snum)) {
917				/* this allows take ownership to work
918				 * reasonably */
919				extern struct current_user current_user;
920				*puser = current_user.uid;
921			} else {
922				DEBUG(3,("unpack_nt_owners: unable to validate"
923					 " owner sid for %s\n",
924					 sid_string_static(&owner_sid)));
925				return False;
926			}
927		}
928 	}
929
930	/*
931	 * Don't immediately fail if the group sid cannot be validated.
932	 * This may be an owner chown only set.
933	 */
934
935	if (security_info_sent & GROUP_SECURITY_INFORMATION) {
936		sid_copy(&grp_sid, psd->grp_sid);
937		if (!NT_STATUS_IS_OK(sid_to_gid( &grp_sid, pgrp))) {
938			if (lp_force_unknown_acl_user(snum)) {
939				/* this allows take group ownership to work
940				 * reasonably */
941				extern struct current_user current_user;
942				*pgrp = current_user.gid;
943			} else {
944				DEBUG(3,("unpack_nt_owners: unable to validate"
945					 " group sid.\n"));
946				return False;
947			}
948		}
949	}
950
951	DEBUG(5,("unpack_nt_owners: owner_sids validated.\n"));
952
953	return True;
954}
955
956/****************************************************************************
957 Ensure the enforced permissions for this share apply.
958****************************************************************************/
959
960static void apply_default_perms(files_struct *fsp, canon_ace *pace, mode_t type)
961{
962	int snum = SNUM(fsp->conn);
963	mode_t and_bits = (mode_t)0;
964	mode_t or_bits = (mode_t)0;
965
966	/* Get the initial bits to apply. */
967
968	if (fsp->is_directory) {
969		and_bits = lp_dir_security_mask(snum);
970		or_bits = lp_force_dir_security_mode(snum);
971	} else {
972		and_bits = lp_security_mask(snum);
973		or_bits = lp_force_security_mode(snum);
974	}
975
976	/* Now bounce them into the S_USR space. */
977	switch(type) {
978	case S_IRUSR:
979		/* Ensure owner has read access. */
980		pace->perms |= S_IRUSR;
981		if (fsp->is_directory)
982			pace->perms |= (S_IWUSR|S_IXUSR);
983		and_bits = unix_perms_to_acl_perms(and_bits, S_IRUSR, S_IWUSR, S_IXUSR);
984		or_bits = unix_perms_to_acl_perms(or_bits, S_IRUSR, S_IWUSR, S_IXUSR);
985		break;
986	case S_IRGRP:
987		and_bits = unix_perms_to_acl_perms(and_bits, S_IRGRP, S_IWGRP, S_IXGRP);
988		or_bits = unix_perms_to_acl_perms(or_bits, S_IRGRP, S_IWGRP, S_IXGRP);
989		break;
990	case S_IROTH:
991		and_bits = unix_perms_to_acl_perms(and_bits, S_IROTH, S_IWOTH, S_IXOTH);
992		or_bits = unix_perms_to_acl_perms(or_bits, S_IROTH, S_IWOTH, S_IXOTH);
993		break;
994	}
995
996	pace->perms = ((pace->perms & and_bits)|or_bits);
997}
998
999/****************************************************************************
1000 Check if a given uid/SID is in a group gid/SID. This is probably very
1001 expensive and will need optimisation. A *lot* of optimisation :-). JRA.
1002****************************************************************************/
1003
1004static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace )
1005{
1006	extern DOM_SID global_sid_World;
1007	fstring u_name;
1008	fstring g_name;
1009	extern struct current_user current_user;
1010
1011	/* "Everyone" always matches every uid. */
1012
1013	if (sid_equal(&group_ace->trustee, &global_sid_World))
1014		return True;
1015
1016	/* Assume that the current user is in the current group (force group) */
1017
1018	if (uid_ace->unix_ug.uid == current_user.uid && group_ace->unix_ug.gid == current_user.gid)
1019		return True;
1020
1021	fstrcpy(u_name, uidtoname(uid_ace->unix_ug.uid));
1022	fstrcpy(g_name, gidtoname(group_ace->unix_ug.gid));
1023
1024	/*
1025	 * Due to the winbind interfaces we need to do this via names,
1026	 * not uids/gids.
1027	 */
1028
1029	return user_in_group_list(u_name, g_name, NULL, 0);
1030}
1031
1032/****************************************************************************
1033 A well formed POSIX file or default ACL has at least 3 entries, a
1034 SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ.
1035 In addition, the owner must always have at least read access.
1036 When using this call on get_acl, the pst struct is valid and contains
1037 the mode of the file. When using this call on set_acl, the pst struct has
1038 been modified to have a mode containing the default for this file or directory
1039 type.
1040****************************************************************************/
1041
1042static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
1043							files_struct *fsp,
1044							DOM_SID *pfile_owner_sid,
1045							DOM_SID *pfile_grp_sid,
1046							SMB_STRUCT_STAT *pst,
1047							BOOL setting_acl)
1048{
1049	extern DOM_SID global_sid_World;
1050	canon_ace *pace;
1051	BOOL got_user = False;
1052	BOOL got_grp = False;
1053	BOOL got_other = False;
1054	canon_ace *pace_other = NULL;
1055	canon_ace *pace_group = NULL;
1056
1057	for (pace = *pp_ace; pace; pace = pace->next) {
1058		if (pace->type == SMB_ACL_USER_OBJ) {
1059
1060			if (setting_acl)
1061				apply_default_perms(fsp, pace, S_IRUSR);
1062			got_user = True;
1063
1064		} else if (pace->type == SMB_ACL_GROUP_OBJ) {
1065
1066			/*
1067			 * Ensure create mask/force create mode is respected on set.
1068			 */
1069
1070			if (setting_acl)
1071				apply_default_perms(fsp, pace, S_IRGRP);
1072			got_grp = True;
1073			pace_group = pace;
1074
1075		} else if (pace->type == SMB_ACL_OTHER) {
1076
1077			/*
1078			 * Ensure create mask/force create mode is respected on set.
1079			 */
1080
1081			if (setting_acl)
1082				apply_default_perms(fsp, pace, S_IROTH);
1083			got_other = True;
1084			pace_other = pace;
1085		}
1086	}
1087
1088	if (!got_user) {
1089		if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) {
1090			DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
1091			return False;
1092		}
1093
1094		ZERO_STRUCTP(pace);
1095		pace->type = SMB_ACL_USER_OBJ;
1096		pace->owner_type = UID_ACE;
1097		pace->unix_ug.uid = pst->st_uid;
1098		pace->trustee = *pfile_owner_sid;
1099		pace->attr = ALLOW_ACE;
1100
1101		if (setting_acl) {
1102			/* If we only got an "everyone" perm, just use that. */
1103			if (!got_grp && got_other)
1104				pace->perms = pace_other->perms;
1105			else if (got_grp && uid_entry_in_group(pace, pace_group))
1106				pace->perms = pace_group->perms;
1107			else
1108				pace->perms = 0;
1109
1110			apply_default_perms(fsp, pace, S_IRUSR);
1111		} else {
1112			pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR);
1113		}
1114
1115		DLIST_ADD(*pp_ace, pace);
1116	}
1117
1118	if (!got_grp) {
1119		if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) {
1120			DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
1121			return False;
1122		}
1123
1124		ZERO_STRUCTP(pace);
1125		pace->type = SMB_ACL_GROUP_OBJ;
1126		pace->owner_type = GID_ACE;
1127		pace->unix_ug.uid = pst->st_gid;
1128		pace->trustee = *pfile_grp_sid;
1129		pace->attr = ALLOW_ACE;
1130		if (setting_acl) {
1131			/* If we only got an "everyone" perm, just use that. */
1132			if (got_other)
1133				pace->perms = pace_other->perms;
1134			else
1135				pace->perms = 0;
1136			apply_default_perms(fsp, pace, S_IRGRP);
1137		} else {
1138			pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP);
1139		}
1140
1141		DLIST_ADD(*pp_ace, pace);
1142	}
1143
1144	if (!got_other) {
1145		if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) {
1146			DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
1147			return False;
1148		}
1149
1150		ZERO_STRUCTP(pace);
1151		pace->type = SMB_ACL_OTHER;
1152		pace->owner_type = WORLD_ACE;
1153		pace->unix_ug.world = -1;
1154		pace->trustee = global_sid_World;
1155		pace->attr = ALLOW_ACE;
1156		if (setting_acl) {
1157			pace->perms = 0;
1158			apply_default_perms(fsp, pace, S_IROTH);
1159		} else
1160			pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IROTH, S_IWOTH, S_IXOTH);
1161
1162		DLIST_ADD(*pp_ace, pace);
1163	}
1164
1165	return True;
1166}
1167
1168/****************************************************************************
1169 Check if a POSIX ACL has the required SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries.
1170 If it does not have them, check if there are any entries where the trustee is the
1171 file owner or the owning group, and map these to SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ.
1172****************************************************************************/
1173
1174static void check_owning_objs(canon_ace *ace, DOM_SID *pfile_owner_sid, DOM_SID *pfile_grp_sid)
1175{
1176	BOOL got_user_obj, got_group_obj;
1177	canon_ace *current_ace;
1178	int i, entries;
1179
1180	entries = count_canon_ace_list(ace);
1181	got_user_obj = False;
1182	got_group_obj = False;
1183
1184	for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
1185		if (current_ace->type == SMB_ACL_USER_OBJ)
1186			got_user_obj = True;
1187		else if (current_ace->type == SMB_ACL_GROUP_OBJ)
1188			got_group_obj = True;
1189	}
1190	if (got_user_obj && got_group_obj) {
1191		DEBUG(10,("check_owning_objs: ACL had owning user/group entries.\n"));
1192		return;
1193	}
1194
1195	for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
1196		if (!got_user_obj && current_ace->owner_type == UID_ACE &&
1197				sid_equal(&current_ace->trustee, pfile_owner_sid)) {
1198			current_ace->type = SMB_ACL_USER_OBJ;
1199			got_user_obj = True;
1200		}
1201		if (!got_group_obj && current_ace->owner_type == GID_ACE &&
1202				sid_equal(&current_ace->trustee, pfile_grp_sid)) {
1203			current_ace->type = SMB_ACL_GROUP_OBJ;
1204			got_group_obj = True;
1205		}
1206	}
1207	if (!got_user_obj)
1208		DEBUG(10,("check_owning_objs: ACL is missing an owner entry.\n"));
1209	if (!got_group_obj)
1210		DEBUG(10,("check_owning_objs: ACL is missing an owning group entry.\n"));
1211}
1212
1213/****************************************************************************
1214 Unpack a SEC_DESC into two canonical ace lists.
1215****************************************************************************/
1216
1217static BOOL create_canon_ace_lists(files_struct *fsp, SMB_STRUCT_STAT *pst,
1218							DOM_SID *pfile_owner_sid,
1219							DOM_SID *pfile_grp_sid,
1220							canon_ace **ppfile_ace, canon_ace **ppdir_ace,
1221							SEC_ACL *dacl)
1222{
1223	extern DOM_SID global_sid_Creator_Owner;
1224	extern DOM_SID global_sid_Creator_Group;
1225	extern DOM_SID global_sid_World;
1226	extern struct generic_mapping file_generic_mapping;
1227	BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False);
1228	canon_ace *file_ace = NULL;
1229	canon_ace *dir_ace = NULL;
1230	canon_ace *tmp_ace = NULL;
1231	canon_ace *current_ace = NULL;
1232	BOOL got_dir_allow = False;
1233	BOOL got_file_allow = False;
1234	int i, j;
1235
1236	*ppfile_ace = NULL;
1237	*ppdir_ace = NULL;
1238
1239	/*
1240	 * Convert the incoming ACL into a more regular form.
1241	 */
1242
1243	for(i = 0; i < dacl->num_aces; i++) {
1244		SEC_ACE *psa = &dacl->ace[i];
1245
1246		if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) && (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
1247			DEBUG(3,("create_canon_ace_lists: unable to set anything but an ALLOW or DENY ACE.\n"));
1248			return False;
1249		}
1250
1251		if (nt4_compatible_acls()) {
1252			/*
1253			 * The security mask may be UNIX_ACCESS_NONE which should map into
1254			 * no permissions (we overload the WRITE_OWNER bit for this) or it
1255			 * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
1256			 * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
1257			 */
1258
1259			/*
1260			 * Convert GENERIC bits to specific bits.
1261			 */
1262
1263			se_map_generic(&psa->info.mask, &file_generic_mapping);
1264
1265			psa->info.mask &= (UNIX_ACCESS_NONE|FILE_ALL_ACCESS);
1266
1267			if(psa->info.mask != UNIX_ACCESS_NONE)
1268				psa->info.mask &= ~UNIX_ACCESS_NONE;
1269		}
1270	}
1271
1272	/*
1273	 * Deal with the fact that NT 4.x re-writes the canonical format
1274	 * that we return for default ACLs. If a directory ACE is identical
1275	 * to a inherited directory ACE then NT changes the bits so that the
1276	 * first ACE is set to OI|IO and the second ACE for this SID is set
1277	 * to CI. We need to repair this. JRA.
1278	 */
1279
1280	for(i = 0; i < dacl->num_aces; i++) {
1281		SEC_ACE *psa1 = &dacl->ace[i];
1282
1283		for (j = i + 1; j < dacl->num_aces; j++) {
1284			SEC_ACE *psa2 = &dacl->ace[j];
1285
1286			if (psa1->info.mask != psa2->info.mask)
1287				continue;
1288
1289			if (!sid_equal(&psa1->trustee, &psa2->trustee))
1290				continue;
1291
1292			/*
1293			 * Ok - permission bits and SIDs are equal.
1294			 * Check if flags were re-written.
1295			 */
1296
1297			if (psa1->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
1298
1299				psa1->flags |= (psa2->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
1300				psa2->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
1301
1302			} else if (psa2->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
1303
1304				psa2->flags |= (psa1->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
1305				psa1->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
1306
1307			}
1308		}
1309	}
1310
1311	for(i = 0; i < dacl->num_aces; i++) {
1312		SEC_ACE *psa = &dacl->ace[i];
1313
1314		/*
1315		 * Ignore non-mappable SIDs (NT Authority, BUILTIN etc).
1316		 */
1317
1318		if (non_mappable_sid(&psa->trustee)) {
1319			fstring str;
1320			DEBUG(10,("create_canon_ace_lists: ignoring non-mappable SID %s\n",
1321				sid_to_string(str, &psa->trustee) ));
1322			continue;
1323		}
1324
1325		/*
1326		 * Create a cannon_ace entry representing this NT DACL ACE.
1327		 */
1328
1329		if ((current_ace = SMB_MALLOC_P(canon_ace)) == NULL) {
1330			free_canon_ace_list(file_ace);
1331			free_canon_ace_list(dir_ace);
1332			DEBUG(0,("create_canon_ace_lists: malloc fail.\n"));
1333			return False;
1334		}
1335
1336		ZERO_STRUCTP(current_ace);
1337
1338		sid_copy(&current_ace->trustee, &psa->trustee);
1339
1340		/*
1341		 * Try and work out if the SID is a user or group
1342		 * as we need to flag these differently for POSIX.
1343		 * Note what kind of a POSIX ACL this should map to.
1344		 */
1345
1346		if( sid_equal(&current_ace->trustee, &global_sid_World)) {
1347			current_ace->owner_type = WORLD_ACE;
1348			current_ace->unix_ug.world = -1;
1349			current_ace->type = SMB_ACL_OTHER;
1350		} else if (sid_equal(&current_ace->trustee, &global_sid_Creator_Owner)) {
1351			current_ace->owner_type = UID_ACE;
1352			current_ace->unix_ug.uid = pst->st_uid;
1353			current_ace->type = SMB_ACL_USER_OBJ;
1354
1355			/*
1356			 * The Creator Owner entry only specifies inheritable permissions,
1357			 * never access permissions. WinNT doesn't always set the ACE to
1358			 *INHERIT_ONLY, though.
1359			 */
1360
1361			if (nt4_compatible_acls())
1362				psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
1363		} else if (sid_equal(&current_ace->trustee, &global_sid_Creator_Group)) {
1364			current_ace->owner_type = GID_ACE;
1365			current_ace->unix_ug.gid = pst->st_gid;
1366			current_ace->type = SMB_ACL_GROUP_OBJ;
1367
1368			/*
1369			 * The Creator Group entry only specifies inheritable permissions,
1370			 * never access permissions. WinNT doesn't always set the ACE to
1371			 *INHERIT_ONLY, though.
1372			 */
1373			if (nt4_compatible_acls())
1374				psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
1375
1376		} else if (NT_STATUS_IS_OK(sid_to_uid( &current_ace->trustee, &current_ace->unix_ug.uid))) {
1377			current_ace->owner_type = UID_ACE;
1378			current_ace->type = SMB_ACL_USER;
1379		} else if (NT_STATUS_IS_OK(sid_to_gid( &current_ace->trustee, &current_ace->unix_ug.gid))) {
1380			current_ace->owner_type = GID_ACE;
1381			current_ace->type = SMB_ACL_GROUP;
1382		} else {
1383			fstring str;
1384
1385			free_canon_ace_list(file_ace);
1386			free_canon_ace_list(dir_ace);
1387			DEBUG(0,("create_canon_ace_lists: unable to map SID %s to uid or gid.\n",
1388				sid_to_string(str, &current_ace->trustee) ));
1389			SAFE_FREE(current_ace);
1390			return False;
1391		}
1392
1393		/*
1394		 * Map the given NT permissions into a UNIX mode_t containing only
1395		 * S_I(R|W|X)USR bits.
1396		 */
1397
1398		current_ace->perms |= map_nt_perms( psa->info, S_IRUSR);
1399		current_ace->attr = (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? ALLOW_ACE : DENY_ACE;
1400		current_ace->inherited = ((psa->flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False);
1401
1402		/*
1403		 * Now add the created ace to either the file list, the directory
1404		 * list, or both. We *MUST* preserve the order here (hence we use
1405		 * DLIST_ADD_END) as NT ACLs are order dependent.
1406		 */
1407
1408		if (fsp->is_directory) {
1409
1410			/*
1411			 * We can only add to the default POSIX ACE list if the ACE is
1412			 * designed to be inherited by both files and directories.
1413			 */
1414
1415			if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) ==
1416				(SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) {
1417
1418				DLIST_ADD_END(dir_ace, current_ace, tmp_ace);
1419
1420				/*
1421				 * Note if this was an allow ace. We can't process
1422				 * any further deny ace's after this.
1423				 */
1424
1425				if (current_ace->attr == ALLOW_ACE)
1426					got_dir_allow = True;
1427
1428				if ((current_ace->attr == DENY_ACE) && got_dir_allow) {
1429					DEBUG(0,("create_canon_ace_lists: malformed ACL in inheritable ACL ! \
1430Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
1431					free_canon_ace_list(file_ace);
1432					free_canon_ace_list(dir_ace);
1433					SAFE_FREE(current_ace);
1434					return False;
1435				}
1436
1437				if( DEBUGLVL( 10 )) {
1438					dbgtext("create_canon_ace_lists: adding dir ACL:\n");
1439					print_canon_ace( current_ace, 0);
1440				}
1441
1442				/*
1443				 * If this is not an inherit only ACE we need to add a duplicate
1444				 * to the file acl.
1445				 */
1446
1447				if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
1448					canon_ace *dup_ace = dup_canon_ace(current_ace);
1449
1450					if (!dup_ace) {
1451						DEBUG(0,("create_canon_ace_lists: malloc fail !\n"));
1452						free_canon_ace_list(file_ace);
1453						free_canon_ace_list(dir_ace);
1454						return False;
1455					}
1456
1457					/*
1458					 * We must not free current_ace here as its
1459					 * pointer is now owned by the dir_ace list.
1460					 */
1461					current_ace = dup_ace;
1462				} else {
1463					/*
1464					 * We must not free current_ace here as its
1465					 * pointer is now owned by the dir_ace list.
1466					 */
1467					current_ace = NULL;
1468				}
1469			}
1470		}
1471
1472		/*
1473		 * Only add to the file ACL if not inherit only.
1474		 */
1475
1476		if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
1477			DLIST_ADD_END(file_ace, current_ace, tmp_ace);
1478
1479			/*
1480			 * Note if this was an allow ace. We can't process
1481			 * any further deny ace's after this.
1482			 */
1483
1484			if (current_ace->attr == ALLOW_ACE)
1485				got_file_allow = True;
1486
1487			if ((current_ace->attr == DENY_ACE) && got_file_allow) {
1488				DEBUG(0,("create_canon_ace_lists: malformed ACL in file ACL ! \
1489Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
1490				free_canon_ace_list(file_ace);
1491				free_canon_ace_list(dir_ace);
1492				SAFE_FREE(current_ace);
1493				return False;
1494			}
1495
1496			if( DEBUGLVL( 10 )) {
1497				dbgtext("create_canon_ace_lists: adding file ACL:\n");
1498				print_canon_ace( current_ace, 0);
1499			}
1500			all_aces_are_inherit_only = False;
1501			/*
1502			 * We must not free current_ace here as its
1503			 * pointer is now owned by the file_ace list.
1504			 */
1505			current_ace = NULL;
1506		}
1507
1508		/*
1509		 * Free if ACE was not added.
1510		 */
1511
1512		SAFE_FREE(current_ace);
1513	}
1514
1515	if (fsp->is_directory && all_aces_are_inherit_only) {
1516		/*
1517		 * Windows 2000 is doing one of these weird 'inherit acl'
1518		 * traverses to conserve NTFS ACL resources. Just pretend
1519		 * there was no DACL sent. JRA.
1520		 */
1521
1522		DEBUG(10,("create_canon_ace_lists: Win2k inherit acl traverse. Ignoring DACL.\n"));
1523		free_canon_ace_list(file_ace);
1524		free_canon_ace_list(dir_ace);
1525		file_ace = NULL;
1526		dir_ace = NULL;
1527	} else {
1528		/*
1529		 * Check if we have SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries in each
1530		 * ACL. If we don't have them, check if any SMB_ACL_USER/SMB_ACL_GROUP
1531		 * entries can be converted to *_OBJ. Usually we will already have these
1532		 * entries in the Default ACL, and the Access ACL will not have them.
1533		 */
1534		check_owning_objs(file_ace, pfile_owner_sid, pfile_grp_sid);
1535		check_owning_objs(dir_ace, pfile_owner_sid, pfile_grp_sid);
1536	}
1537
1538	*ppfile_ace = file_ace;
1539	*ppdir_ace = dir_ace;
1540
1541	return True;
1542}
1543
1544/****************************************************************************
1545 ASCII art time again... JRA :-).
1546
1547 We have 4 cases to process when moving from an NT ACL to a POSIX ACL. Firstly,
1548 we insist the ACL is in canonical form (ie. all DENY entries preceede ALLOW
1549 entries). Secondly, the merge code has ensured that all duplicate SID entries for
1550 allow or deny have been merged, so the same SID can only appear once in the deny
1551 list or once in the allow list.
1552
1553 We then process as follows :
1554
1555 ---------------------------------------------------------------------------
1556 First pass - look for a Everyone DENY entry.
1557
1558 If it is deny all (rwx) trunate the list at this point.
1559 Else, walk the list from this point and use the deny permissions of this
1560 entry as a mask on all following allow entries. Finally, delete
1561 the Everyone DENY entry (we have applied it to everything possible).
1562
1563 In addition, in this pass we remove any DENY entries that have
1564 no permissions (ie. they are a DENY nothing).
1565 ---------------------------------------------------------------------------
1566 Second pass - only deal with deny user entries.
1567
1568 DENY user1 (perms XXX)
1569
1570 new_perms = 0
1571 for all following allow group entries where user1 is in group
1572	new_perms |= group_perms;
1573
1574 user1 entry perms = new_perms & ~ XXX;
1575
1576 Convert the deny entry to an allow entry with the new perms and
1577 push to the end of the list. Note if the user was in no groups
1578 this maps to a specific allow nothing entry for this user.
1579
1580 The common case from the NT ACL choser (userX deny all) is
1581 optimised so we don't do the group lookup - we just map to
1582 an allow nothing entry.
1583
1584 What we're doing here is inferring the allow permissions the
1585 person setting the ACE on user1 wanted by looking at the allow
1586 permissions on the groups the user is currently in. This will
1587 be a snapshot, depending on group membership but is the best
1588 we can do and has the advantage of failing closed rather than
1589 open.
1590 ---------------------------------------------------------------------------
1591 Third pass - only deal with deny group entries.
1592
1593 DENY group1 (perms XXX)
1594
1595 for all following allow user entries where user is in group1
1596   user entry perms = user entry perms & ~ XXX;
1597
1598 If there is a group Everyone allow entry with permissions YYY,
1599 convert the group1 entry to an allow entry and modify its
1600 permissions to be :
1601
1602 new_perms = YYY & ~ XXX
1603
1604 and push to the end of the list.
1605
1606 If there is no group Everyone allow entry then convert the
1607 group1 entry to a allow nothing entry and push to the end of the list.
1608
1609 Note that the common case from the NT ACL choser (groupX deny all)
1610 cannot be optimised here as we need to modify user entries who are
1611 in the group to change them to a deny all also.
1612
1613 What we're doing here is modifying the allow permissions of
1614 user entries (which are more specific in POSIX ACLs) to mask
1615 out the explicit deny set on the group they are in. This will
1616 be a snapshot depending on current group membership but is the
1617 best we can do and has the advantage of failing closed rather
1618 than open.
1619 ---------------------------------------------------------------------------
1620 Fourth pass - cope with cumulative permissions.
1621
1622 for all allow user entries, if there exists an allow group entry with
1623 more permissive permissions, and the user is in that group, rewrite the
1624 allow user permissions to contain both sets of permissions.
1625
1626 Currently the code for this is #ifdef'ed out as these semantics make
1627 no sense to me. JRA.
1628 ---------------------------------------------------------------------------
1629
1630 Note we *MUST* do the deny user pass first as this will convert deny user
1631 entries into allow user entries which can then be processed by the deny
1632 group pass.
1633
1634 The above algorithm took a *lot* of thinking about - hence this
1635 explaination :-). JRA.
1636****************************************************************************/
1637
1638/****************************************************************************
1639 Process a canon_ace list entries. This is very complex code. We need
1640 to go through and remove the "deny" permissions from any allow entry that matches
1641 the id of this entry. We have already refused any NT ACL that wasn't in correct
1642 order (DENY followed by ALLOW). If any allow entry ends up with zero permissions,
1643 we just remove it (to fail safe). We have already removed any duplicate ace
1644 entries. Treat an "Everyone" DENY_ACE as a special case - use it to mask all
1645 allow entries.
1646****************************************************************************/
1647
1648static void process_deny_list( canon_ace **pp_ace_list )
1649{
1650	extern DOM_SID global_sid_World;
1651	canon_ace *ace_list = *pp_ace_list;
1652	canon_ace *curr_ace = NULL;
1653	canon_ace *curr_ace_next = NULL;
1654
1655	/* Pass 1 above - look for an Everyone, deny entry. */
1656
1657	for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1658		canon_ace *allow_ace_p;
1659
1660		curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1661
1662		if (curr_ace->attr != DENY_ACE)
1663			continue;
1664
1665		if (curr_ace->perms == (mode_t)0) {
1666
1667			/* Deny nothing entry - delete. */
1668
1669			DLIST_REMOVE(ace_list, curr_ace);
1670			continue;
1671		}
1672
1673		if (!sid_equal(&curr_ace->trustee, &global_sid_World))
1674			continue;
1675
1676		/* JRATEST - assert. */
1677		SMB_ASSERT(curr_ace->owner_type == WORLD_ACE);
1678
1679		if (curr_ace->perms == ALL_ACE_PERMS) {
1680
1681			/*
1682			 * Optimisation. This is a DENY_ALL to Everyone. Truncate the
1683			 * list at this point including this entry.
1684			 */
1685
1686			canon_ace *prev_entry = curr_ace->prev;
1687
1688			free_canon_ace_list( curr_ace );
1689			if (prev_entry)
1690				prev_entry->next = NULL;
1691			else {
1692				/* We deleted the entire list. */
1693				ace_list = NULL;
1694			}
1695			break;
1696		}
1697
1698		for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1699
1700			/*
1701			 * Only mask off allow entries.
1702			 */
1703
1704			if (allow_ace_p->attr != ALLOW_ACE)
1705				continue;
1706
1707			allow_ace_p->perms &= ~curr_ace->perms;
1708		}
1709
1710		/*
1711		 * Now it's been applied, remove it.
1712		 */
1713
1714		DLIST_REMOVE(ace_list, curr_ace);
1715	}
1716
1717	/* Pass 2 above - deal with deny user entries. */
1718
1719	for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1720		mode_t new_perms = (mode_t)0;
1721		canon_ace *allow_ace_p;
1722		canon_ace *tmp_ace;
1723
1724		curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1725
1726		if (curr_ace->attr != DENY_ACE)
1727			continue;
1728
1729		if (curr_ace->owner_type != UID_ACE)
1730			continue;
1731
1732		if (curr_ace->perms == ALL_ACE_PERMS) {
1733
1734			/*
1735			 * Optimisation - this is a deny everything to this user.
1736			 * Convert to an allow nothing and push to the end of the list.
1737			 */
1738
1739			curr_ace->attr = ALLOW_ACE;
1740			curr_ace->perms = (mode_t)0;
1741			DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
1742			continue;
1743		}
1744
1745		for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1746
1747			if (allow_ace_p->attr != ALLOW_ACE)
1748				continue;
1749
1750			/* We process GID_ACE and WORLD_ACE entries only. */
1751
1752			if (allow_ace_p->owner_type == UID_ACE)
1753				continue;
1754
1755			if (uid_entry_in_group( curr_ace, allow_ace_p))
1756				new_perms |= allow_ace_p->perms;
1757		}
1758
1759		/*
1760		 * Convert to a allow entry, modify the perms and push to the end
1761		 * of the list.
1762		 */
1763
1764		curr_ace->attr = ALLOW_ACE;
1765		curr_ace->perms = (new_perms & ~curr_ace->perms);
1766		DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
1767	}
1768
1769	/* Pass 3 above - deal with deny group entries. */
1770
1771	for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1772		canon_ace *tmp_ace;
1773		canon_ace *allow_ace_p;
1774		canon_ace *allow_everyone_p = NULL;
1775
1776		curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1777
1778		if (curr_ace->attr != DENY_ACE)
1779			continue;
1780
1781		if (curr_ace->owner_type != GID_ACE)
1782			continue;
1783
1784		for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1785
1786			if (allow_ace_p->attr != ALLOW_ACE)
1787				continue;
1788
1789			/* Store a pointer to the Everyone allow, if it exists. */
1790			if (allow_ace_p->owner_type == WORLD_ACE)
1791				allow_everyone_p = allow_ace_p;
1792
1793			/* We process UID_ACE entries only. */
1794
1795			if (allow_ace_p->owner_type != UID_ACE)
1796				continue;
1797
1798			/* Mask off the deny group perms. */
1799
1800			if (uid_entry_in_group( allow_ace_p, curr_ace))
1801				allow_ace_p->perms &= ~curr_ace->perms;
1802		}
1803
1804		/*
1805		 * Convert the deny to an allow with the correct perms and
1806		 * push to the end of the list.
1807		 */
1808
1809		curr_ace->attr = ALLOW_ACE;
1810		if (allow_everyone_p)
1811			curr_ace->perms = allow_everyone_p->perms & ~curr_ace->perms;
1812		else
1813			curr_ace->perms = (mode_t)0;
1814		DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
1815
1816	}
1817
1818	/* Doing this fourth pass allows Windows semantics to be layered
1819	 * on top of POSIX semantics. I'm not sure if this is desirable.
1820	 * For example, in W2K ACLs there is no way to say, "Group X no
1821	 * access, user Y full access" if user Y is a member of group X.
1822	 * This seems completely broken semantics to me.... JRA.
1823	 */
1824
1825#if 0
1826	/* Pass 4 above - deal with allow entries. */
1827
1828	for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1829		canon_ace *allow_ace_p;
1830
1831		curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1832
1833		if (curr_ace->attr != ALLOW_ACE)
1834			continue;
1835
1836		if (curr_ace->owner_type != UID_ACE)
1837			continue;
1838
1839		for (allow_ace_p = ace_list; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1840
1841			if (allow_ace_p->attr != ALLOW_ACE)
1842				continue;
1843
1844			/* We process GID_ACE entries only. */
1845
1846			if (allow_ace_p->owner_type != GID_ACE)
1847				continue;
1848
1849			/* OR in the group perms. */
1850
1851			if (uid_entry_in_group( curr_ace, allow_ace_p))
1852				curr_ace->perms |= allow_ace_p->perms;
1853		}
1854	}
1855#endif
1856
1857	*pp_ace_list = ace_list;
1858}
1859
1860/****************************************************************************
1861 Create a default mode that will be used if a security descriptor entry has
1862 no user/group/world entries.
1863****************************************************************************/
1864
1865static mode_t create_default_mode(files_struct *fsp, BOOL interitable_mode)
1866{
1867	int snum = SNUM(fsp->conn);
1868	mode_t and_bits = (mode_t)0;
1869	mode_t or_bits = (mode_t)0;
1870	mode_t mode = interitable_mode ? unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name, False) : S_IRUSR;
1871
1872	if (fsp->is_directory)
1873		mode |= (S_IWUSR|S_IXUSR);
1874
1875	/*
1876	 * Now AND with the create mode/directory mode bits then OR with the
1877	 * force create mode/force directory mode bits.
1878	 */
1879
1880	if (fsp->is_directory) {
1881		and_bits = lp_dir_security_mask(snum);
1882		or_bits = lp_force_dir_security_mode(snum);
1883	} else {
1884		and_bits = lp_security_mask(snum);
1885		or_bits = lp_force_security_mode(snum);
1886	}
1887
1888	return ((mode & and_bits)|or_bits);
1889}
1890
1891/****************************************************************************
1892 Unpack a SEC_DESC into two canonical ace lists. We don't depend on this
1893 succeeding.
1894****************************************************************************/
1895
1896static BOOL unpack_canon_ace(files_struct *fsp,
1897							SMB_STRUCT_STAT *pst,
1898							DOM_SID *pfile_owner_sid,
1899							DOM_SID *pfile_grp_sid,
1900							canon_ace **ppfile_ace, canon_ace **ppdir_ace,
1901							uint32 security_info_sent, SEC_DESC *psd)
1902{
1903	canon_ace *file_ace = NULL;
1904	canon_ace *dir_ace = NULL;
1905
1906	*ppfile_ace = NULL;
1907	*ppdir_ace = NULL;
1908
1909	if(security_info_sent == 0) {
1910		DEBUG(0,("unpack_canon_ace: no security info sent !\n"));
1911		return False;
1912	}
1913
1914	/*
1915	 * If no DACL then this is a chown only security descriptor.
1916	 */
1917
1918	if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !psd->dacl)
1919		return True;
1920
1921	/*
1922	 * Now go through the DACL and create the canon_ace lists.
1923	 */
1924
1925	if (!create_canon_ace_lists( fsp, pst, pfile_owner_sid, pfile_grp_sid,
1926								&file_ace, &dir_ace, psd->dacl))
1927		return False;
1928
1929	if ((file_ace == NULL) && (dir_ace == NULL)) {
1930		/* W2K traverse DACL set - ignore. */
1931		return True;
1932	}
1933
1934	/*
1935	 * Go through the canon_ace list and merge entries
1936	 * belonging to identical users of identical allow or deny type.
1937	 * We can do this as all deny entries come first, followed by
1938	 * all allow entries (we have mandated this before accepting this acl).
1939	 */
1940
1941	print_canon_ace_list( "file ace - before merge", file_ace);
1942	merge_aces( &file_ace );
1943
1944	print_canon_ace_list( "dir ace - before merge", dir_ace);
1945	merge_aces( &dir_ace );
1946
1947	/*
1948	 * NT ACLs are order dependent. Go through the acl lists and
1949	 * process DENY entries by masking the allow entries.
1950	 */
1951
1952	print_canon_ace_list( "file ace - before deny", file_ace);
1953	process_deny_list( &file_ace);
1954
1955	print_canon_ace_list( "dir ace - before deny", dir_ace);
1956	process_deny_list( &dir_ace);
1957
1958	/*
1959	 * A well formed POSIX file or default ACL has at least 3 entries, a
1960	 * SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ
1961	 * and optionally a mask entry. Ensure this is the case.
1962	 */
1963
1964	print_canon_ace_list( "file ace - before valid", file_ace);
1965
1966	/*
1967	 * A default 3 element mode entry for a file should be r-- --- ---.
1968	 * A default 3 element mode entry for a directory should be rwx --- ---.
1969	 */
1970
1971	pst->st_mode = create_default_mode(fsp, False);
1972
1973	if (!ensure_canon_entry_valid(&file_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
1974		free_canon_ace_list(file_ace);
1975		free_canon_ace_list(dir_ace);
1976		return False;
1977	}
1978
1979	print_canon_ace_list( "dir ace - before valid", dir_ace);
1980
1981	/*
1982	 * A default inheritable 3 element mode entry for a directory should be the
1983	 * mode Samba will use to create a file within. Ensure user rwx bits are set if
1984	 * it's a directory.
1985	 */
1986
1987	pst->st_mode = create_default_mode(fsp, True);
1988
1989	if (dir_ace && !ensure_canon_entry_valid(&dir_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
1990		free_canon_ace_list(file_ace);
1991		free_canon_ace_list(dir_ace);
1992		return False;
1993	}
1994
1995	print_canon_ace_list( "file ace - return", file_ace);
1996	print_canon_ace_list( "dir ace - return", dir_ace);
1997
1998	*ppfile_ace = file_ace;
1999	*ppdir_ace = dir_ace;
2000	return True;
2001
2002}
2003
2004/******************************************************************************
2005 When returning permissions, try and fit NT display
2006 semantics if possible. Note the the canon_entries here must have been malloced.
2007 The list format should be - first entry = owner, followed by group and other user
2008 entries, last entry = other.
2009
2010 Note that this doesn't exactly match the NT semantics for an ACL. As POSIX entries
2011 are not ordered, and match on the most specific entry rather than walking a list,
2012 then a simple POSIX permission of rw-r--r-- should really map to 5 entries,
2013
2014 Entry 0: owner : deny all except read and write.
2015 Entry 1: group : deny all except read.
2016 Entry 2: owner : allow read and write.
2017 Entry 3: group : allow read.
2018 Entry 4: Everyone : allow read.
2019
2020 But NT cannot display this in their ACL editor !
2021********************************************************************************/
2022
2023static void arrange_posix_perms( char *filename, canon_ace **pp_list_head)
2024{
2025	canon_ace *list_head = *pp_list_head;
2026	canon_ace *owner_ace = NULL;
2027	canon_ace *other_ace = NULL;
2028	canon_ace *ace = NULL;
2029
2030	for (ace = list_head; ace; ace = ace->next) {
2031		if (ace->type == SMB_ACL_USER_OBJ)
2032			owner_ace = ace;
2033		else if (ace->type == SMB_ACL_OTHER) {
2034			/* Last ace - this is "other" */
2035			other_ace = ace;
2036		}
2037	}
2038
2039	if (!owner_ace || !other_ace) {
2040		DEBUG(0,("arrange_posix_perms: Invalid POSIX permissions for file %s, missing owner or other.\n",
2041			filename ));
2042		return;
2043	}
2044
2045	/*
2046	 * The POSIX algorithm applies to owner first, and other last,
2047	 * so ensure they are arranged in this order.
2048	 */
2049
2050	if (owner_ace) {
2051		DLIST_PROMOTE(list_head, owner_ace);
2052	}
2053
2054	if (other_ace) {
2055		DLIST_DEMOTE(list_head, other_ace, ace);
2056	}
2057
2058	/* We have probably changed the head of the list. */
2059
2060	*pp_list_head = list_head;
2061}
2062
2063/****************************************************************************
2064 Create a linked list of canonical ACE entries.
2065****************************************************************************/
2066
2067static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf,
2068					DOM_SID *powner, DOM_SID *pgroup, struct pai_val *pal, SMB_ACL_TYPE_T the_acl_type)
2069{
2070	extern DOM_SID global_sid_World;
2071	connection_struct *conn = fsp->conn;
2072	mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR);
2073	canon_ace *list_head = NULL;
2074	canon_ace *ace = NULL;
2075	canon_ace *next_ace = NULL;
2076	int entry_id = SMB_ACL_FIRST_ENTRY;
2077	SMB_ACL_ENTRY_T entry;
2078	size_t ace_count;
2079
2080	while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
2081		SMB_ACL_TAG_T tagtype;
2082		SMB_ACL_PERMSET_T permset;
2083		DOM_SID sid;
2084		posix_id unix_ug;
2085		enum ace_owner owner_type;
2086
2087		/* get_next... */
2088		if (entry_id == SMB_ACL_FIRST_ENTRY)
2089			entry_id = SMB_ACL_NEXT_ENTRY;
2090
2091		/* Is this a MASK entry ? */
2092		if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
2093			continue;
2094
2095		if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
2096			continue;
2097
2098		/* Decide which SID to use based on the ACL type. */
2099		switch(tagtype) {
2100			case SMB_ACL_USER_OBJ:
2101				/* Get the SID from the owner. */
2102				sid_copy(&sid, powner);
2103				unix_ug.uid = psbuf->st_uid;
2104				owner_type = UID_ACE;
2105				break;
2106			case SMB_ACL_USER:
2107				{
2108					uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
2109					if (puid == NULL) {
2110						DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
2111						continue;
2112					}
2113					/*
2114					 * A SMB_ACL_USER entry for the owner is shadowed by the
2115					 * SMB_ACL_USER_OBJ entry and Windows also cannot represent
2116					 * that entry, so we ignore it. We also don't create such
2117					 * entries out of the blue when setting ACLs, so a get/set
2118					 * cycle will drop them.
2119					 */
2120					if (the_acl_type == SMB_ACL_TYPE_ACCESS && *puid == psbuf->st_uid) {
2121						SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
2122						continue;
2123					}
2124					uid_to_sid( &sid, *puid);
2125					unix_ug.uid = *puid;
2126					owner_type = UID_ACE;
2127					SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
2128					break;
2129				}
2130			case SMB_ACL_GROUP_OBJ:
2131				/* Get the SID from the owning group. */
2132				sid_copy(&sid, pgroup);
2133				unix_ug.gid = psbuf->st_gid;
2134				owner_type = GID_ACE;
2135				break;
2136			case SMB_ACL_GROUP:
2137				{
2138					gid_t *pgid = (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
2139					if (pgid == NULL) {
2140						DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
2141						continue;
2142					}
2143					gid_to_sid( &sid, *pgid);
2144					unix_ug.gid = *pgid;
2145					owner_type = GID_ACE;
2146					SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)pgid,tagtype);
2147					break;
2148				}
2149			case SMB_ACL_MASK:
2150				acl_mask = convert_permset_to_mode_t(conn, permset);
2151				continue; /* Don't count the mask as an entry. */
2152			case SMB_ACL_OTHER:
2153				/* Use the Everyone SID */
2154				sid = global_sid_World;
2155				unix_ug.world = -1;
2156				owner_type = WORLD_ACE;
2157				break;
2158			default:
2159				DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype));
2160				continue;
2161		}
2162
2163		/*
2164		 * Add this entry to the list.
2165		 */
2166
2167		if ((ace = SMB_MALLOC_P(canon_ace)) == NULL)
2168			goto fail;
2169
2170		ZERO_STRUCTP(ace);
2171		ace->type = tagtype;
2172		ace->perms = convert_permset_to_mode_t(conn, permset);
2173		ace->attr = ALLOW_ACE;
2174		ace->trustee = sid;
2175		ace->unix_ug = unix_ug;
2176		ace->owner_type = owner_type;
2177		ace->inherited = get_inherited_flag(pal, ace, (the_acl_type == SMB_ACL_TYPE_DEFAULT));
2178
2179		DLIST_ADD(list_head, ace);
2180	}
2181
2182	/*
2183	 * This next call will ensure we have at least a user/group/world set.
2184	 */
2185
2186	if (!ensure_canon_entry_valid(&list_head, fsp, powner, pgroup, psbuf, False))
2187		goto fail;
2188
2189	/*
2190	 * Now go through the list, masking the permissions with the
2191	 * acl_mask. Ensure all DENY Entries are at the start of the list.
2192	 */
2193
2194	DEBUG(10,("canonicalise_acl: %s ace entries before arrange :\n", the_acl_type == SMB_ACL_TYPE_ACCESS ? "Access" : "Default" ));
2195
2196	for ( ace_count = 0, ace = list_head; ace; ace = next_ace, ace_count++) {
2197		next_ace = ace->next;
2198
2199		/* Masks are only applied to entries other than USER_OBJ and OTHER. */
2200		if (ace->type != SMB_ACL_OTHER && ace->type != SMB_ACL_USER_OBJ)
2201			ace->perms &= acl_mask;
2202
2203		if (ace->perms == 0) {
2204			DLIST_PROMOTE(list_head, ace);
2205		}
2206
2207		if( DEBUGLVL( 10 ) ) {
2208			print_canon_ace(ace, ace_count);
2209		}
2210	}
2211
2212	arrange_posix_perms(fsp->fsp_name,&list_head );
2213
2214	print_canon_ace_list( "canonicalise_acl: ace entries after arrange", list_head );
2215
2216	return list_head;
2217
2218  fail:
2219
2220	free_canon_ace_list(list_head);
2221	return NULL;
2222}
2223
2224/****************************************************************************
2225 Attempt to apply an ACL to a file or directory.
2226****************************************************************************/
2227
2228static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL default_ace, BOOL *pacl_set_support)
2229{
2230	connection_struct *conn = fsp->conn;
2231	BOOL ret = False;
2232	SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, (int)count_canon_ace_list(the_ace) + 1);
2233	canon_ace *p_ace;
2234	int i;
2235	SMB_ACL_ENTRY_T mask_entry;
2236	BOOL got_mask_entry = False;
2237	SMB_ACL_PERMSET_T mask_permset;
2238	SMB_ACL_TYPE_T the_acl_type = (default_ace ? SMB_ACL_TYPE_DEFAULT : SMB_ACL_TYPE_ACCESS);
2239	BOOL needs_mask = False;
2240	mode_t mask_perms = 0;
2241
2242#if defined(POSIX_ACL_NEEDS_MASK)
2243	/* HP-UX always wants to have a mask (called "class" there). */
2244	needs_mask = True;
2245#endif
2246
2247	if (the_acl == NULL) {
2248
2249		if (!no_acl_syscall_error(errno)) {
2250			/*
2251			 * Only print this error message if we have some kind of ACL
2252			 * support that's not working. Otherwise we would always get this.
2253			 */
2254			DEBUG(0,("set_canon_ace_list: Unable to init %s ACL. (%s)\n",
2255				default_ace ? "default" : "file", strerror(errno) ));
2256		}
2257		*pacl_set_support = False;
2258		return False;
2259	}
2260
2261	if( DEBUGLVL( 10 )) {
2262		dbgtext("set_canon_ace_list: setting ACL:\n");
2263		for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
2264			print_canon_ace( p_ace, i);
2265		}
2266	}
2267
2268	for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
2269		SMB_ACL_ENTRY_T the_entry;
2270		SMB_ACL_PERMSET_T the_permset;
2271
2272		/*
2273		 * ACLs only "need" an ACL_MASK entry if there are any named user or
2274		 * named group entries. But if there is an ACL_MASK entry, it applies
2275		 * to ACL_USER, ACL_GROUP, and ACL_GROUP_OBJ entries. Set the mask
2276		 * so that it doesn't deny (i.e., mask off) any permissions.
2277		 */
2278
2279		if (p_ace->type == SMB_ACL_USER || p_ace->type == SMB_ACL_GROUP) {
2280			needs_mask = True;
2281			mask_perms |= p_ace->perms;
2282		} else if (p_ace->type == SMB_ACL_GROUP_OBJ) {
2283			mask_perms |= p_ace->perms;
2284		}
2285
2286		/*
2287		 * Get the entry for this ACE.
2288		 */
2289
2290		if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) {
2291			DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n",
2292				i, strerror(errno) ));
2293			goto done;
2294		}
2295
2296		if (p_ace->type == SMB_ACL_MASK) {
2297			mask_entry = the_entry;
2298			got_mask_entry = True;
2299		}
2300
2301		/*
2302		 * Ok - we now know the ACL calls should be working, don't
2303		 * allow fallback to chmod.
2304		 */
2305
2306		*pacl_set_support = True;
2307
2308		/*
2309		 * Initialise the entry from the canon_ace.
2310		 */
2311
2312		/*
2313		 * First tell the entry what type of ACE this is.
2314		 */
2315
2316		if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, p_ace->type) == -1) {
2317			DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n",
2318				i, strerror(errno) ));
2319			goto done;
2320		}
2321
2322		/*
2323		 * Only set the qualifier (user or group id) if the entry is a user
2324		 * or group id ACE.
2325		 */
2326
2327		if ((p_ace->type == SMB_ACL_USER) || (p_ace->type == SMB_ACL_GROUP)) {
2328			if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&p_ace->unix_ug.uid) == -1) {
2329				DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n",
2330					i, strerror(errno) ));
2331				goto done;
2332			}
2333		}
2334
2335		/*
2336		 * Convert the mode_t perms in the canon_ace to a POSIX permset.
2337		 */
2338
2339		if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) {
2340			DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n",
2341				i, strerror(errno) ));
2342			goto done;
2343		}
2344
2345		if (map_acl_perms_to_permset(conn, p_ace->perms, &the_permset) == -1) {
2346			DEBUG(0,("set_canon_ace_list: Failed to create permset for mode (%u) on entry %d. (%s)\n",
2347				(unsigned int)p_ace->perms, i, strerror(errno) ));
2348			goto done;
2349		}
2350
2351		/*
2352		 * ..and apply them to the entry.
2353		 */
2354
2355		if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) {
2356			DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n",
2357				i, strerror(errno) ));
2358			goto done;
2359		}
2360
2361		if( DEBUGLVL( 10 ))
2362			print_canon_ace( p_ace, i);
2363
2364	}
2365
2366	if (needs_mask && !got_mask_entry) {
2367		if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &mask_entry) == -1) {
2368			DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) ));
2369			goto done;
2370		}
2371
2372		if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, mask_entry, SMB_ACL_MASK) == -1) {
2373			DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno) ));
2374			goto done;
2375		}
2376
2377		if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, mask_entry, &mask_permset) == -1) {
2378			DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) ));
2379			goto done;
2380		}
2381
2382		if (map_acl_perms_to_permset(conn, S_IRUSR|S_IWUSR|S_IXUSR, &mask_permset) == -1) {
2383			DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno) ));
2384			goto done;
2385		}
2386
2387		if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, mask_entry, mask_permset) == -1) {
2388			DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) ));
2389			goto done;
2390		}
2391	}
2392
2393	/*
2394	 * Check if the ACL is valid.
2395	 */
2396
2397	if (SMB_VFS_SYS_ACL_VALID(conn, the_acl) == -1) {
2398		DEBUG(0,("set_canon_ace_list: ACL type (%s) is invalid for set (%s).\n",
2399				the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
2400				strerror(errno) ));
2401		goto done;
2402	}
2403
2404	/*
2405	 * Finally apply it to the file or directory.
2406	 */
2407
2408	if(default_ace || fsp->is_directory || fsp->fd == -1) {
2409		if (SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name, the_acl_type, the_acl) == -1) {
2410			/*
2411			 * Some systems allow all the above calls and only fail with no ACL support
2412			 * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
2413			 */
2414			if (no_acl_syscall_error(errno)) {
2415				*pacl_set_support = False;
2416			}
2417
2418			DEBUG(2,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n",
2419					the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
2420					fsp->fsp_name, strerror(errno) ));
2421			goto done;
2422		}
2423	} else {
2424		if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fd, the_acl) == -1) {
2425			/*
2426			 * Some systems allow all the above calls and only fail with no ACL support
2427			 * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
2428			 */
2429			if (no_acl_syscall_error(errno)) {
2430				*pacl_set_support = False;
2431			}
2432
2433			DEBUG(2,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n",
2434					fsp->fsp_name, strerror(errno) ));
2435			goto done;
2436		}
2437	}
2438
2439	ret = True;
2440
2441  done:
2442
2443	if (the_acl != NULL)
2444	    SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
2445
2446	return ret;
2447}
2448
2449/****************************************************************************
2450 Find a particular canon_ace entry.
2451****************************************************************************/
2452
2453static struct canon_ace *canon_ace_entry_for(struct canon_ace *list, SMB_ACL_TAG_T type, posix_id *id)
2454{
2455	while (list) {
2456		if (list->type == type && ((type != SMB_ACL_USER && type != SMB_ACL_GROUP) ||
2457				(type == SMB_ACL_USER  && id && id->uid == list->unix_ug.uid) ||
2458				(type == SMB_ACL_GROUP && id && id->gid == list->unix_ug.gid)))
2459			break;
2460		list = list->next;
2461	}
2462	return list;
2463}
2464
2465/****************************************************************************
2466
2467****************************************************************************/
2468
2469SMB_ACL_T free_empty_sys_acl(connection_struct *conn, SMB_ACL_T the_acl)
2470{
2471	SMB_ACL_ENTRY_T entry;
2472
2473	if (!the_acl)
2474		return NULL;
2475	if (SMB_VFS_SYS_ACL_GET_ENTRY(conn, the_acl, SMB_ACL_FIRST_ENTRY, &entry) != 1) {
2476		SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
2477		return NULL;
2478	}
2479	return the_acl;
2480}
2481
2482/****************************************************************************
2483 Convert a canon_ace to a generic 3 element permission - if possible.
2484****************************************************************************/
2485
2486#define MAP_PERM(p,mask,result) (((p) & (mask)) ? (result) : 0 )
2487
2488static BOOL convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file_ace_list, mode_t *posix_perms)
2489{
2490	int snum = SNUM(fsp->conn);
2491	size_t ace_count = count_canon_ace_list(file_ace_list);
2492	canon_ace *ace_p;
2493	canon_ace *owner_ace = NULL;
2494	canon_ace *group_ace = NULL;
2495	canon_ace *other_ace = NULL;
2496	mode_t and_bits;
2497	mode_t or_bits;
2498
2499	if (ace_count != 3) {
2500		DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE entries for file %s to convert to \
2501posix perms.\n", fsp->fsp_name ));
2502		return False;
2503	}
2504
2505	for (ace_p = file_ace_list; ace_p; ace_p = ace_p->next) {
2506		if (ace_p->owner_type == UID_ACE)
2507			owner_ace = ace_p;
2508		else if (ace_p->owner_type == GID_ACE)
2509			group_ace = ace_p;
2510		else if (ace_p->owner_type == WORLD_ACE)
2511			other_ace = ace_p;
2512	}
2513
2514	if (!owner_ace || !group_ace || !other_ace) {
2515		DEBUG(3,("convert_canon_ace_to_posix_perms: Can't get standard entries for file %s.\n",
2516				fsp->fsp_name ));
2517		return False;
2518	}
2519
2520	*posix_perms = (mode_t)0;
2521
2522	*posix_perms |= owner_ace->perms;
2523	*posix_perms |= MAP_PERM(group_ace->perms, S_IRUSR, S_IRGRP);
2524	*posix_perms |= MAP_PERM(group_ace->perms, S_IWUSR, S_IWGRP);
2525	*posix_perms |= MAP_PERM(group_ace->perms, S_IXUSR, S_IXGRP);
2526	*posix_perms |= MAP_PERM(other_ace->perms, S_IRUSR, S_IROTH);
2527	*posix_perms |= MAP_PERM(other_ace->perms, S_IWUSR, S_IWOTH);
2528	*posix_perms |= MAP_PERM(other_ace->perms, S_IXUSR, S_IXOTH);
2529
2530	/* The owner must have at least read access. */
2531
2532	*posix_perms |= S_IRUSR;
2533	if (fsp->is_directory)
2534		*posix_perms |= (S_IWUSR|S_IXUSR);
2535
2536	/* If requested apply the masks. */
2537
2538	/* Get the initial bits to apply. */
2539
2540	if (fsp->is_directory) {
2541		and_bits = lp_dir_security_mask(snum);
2542		or_bits = lp_force_dir_security_mode(snum);
2543	} else {
2544		and_bits = lp_security_mask(snum);
2545		or_bits = lp_force_security_mode(snum);
2546	}
2547
2548	*posix_perms = (((*posix_perms) & and_bits)|or_bits);
2549
2550	DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o to perm=0%o for file %s.\n",
2551		(int)owner_ace->perms, (int)group_ace->perms, (int)other_ace->perms, (int)*posix_perms,
2552		fsp->fsp_name ));
2553
2554	return True;
2555}
2556
2557/****************************************************************************
2558  Incoming NT ACLs on a directory can be split into a default POSIX acl (CI|OI|IO) and
2559  a normal POSIX acl. Win2k needs these split acls re-merging into one ACL
2560  with CI|OI set so it is inherited and also applies to the directory.
2561  Based on code from "Jim McDonough" <jmcd@us.ibm.com>.
2562****************************************************************************/
2563
2564static size_t merge_default_aces( SEC_ACE *nt_ace_list, size_t num_aces)
2565{
2566	size_t i, j;
2567
2568	for (i = 0; i < num_aces; i++) {
2569		for (j = i+1; j < num_aces; j++) {
2570			uint32 i_flags_ni = (nt_ace_list[i].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
2571			uint32 j_flags_ni = (nt_ace_list[j].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
2572			BOOL i_inh = (nt_ace_list[i].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
2573			BOOL j_inh = (nt_ace_list[j].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
2574
2575			/* We know the lower number ACE's are file entries. */
2576			if ((nt_ace_list[i].type == nt_ace_list[j].type) &&
2577				(nt_ace_list[i].size == nt_ace_list[j].size) &&
2578				(nt_ace_list[i].info.mask == nt_ace_list[j].info.mask) &&
2579				sid_equal(&nt_ace_list[i].trustee, &nt_ace_list[j].trustee) &&
2580				(i_inh == j_inh) &&
2581				(i_flags_ni == 0) &&
2582				(j_flags_ni == (SEC_ACE_FLAG_OBJECT_INHERIT|
2583						  SEC_ACE_FLAG_CONTAINER_INHERIT|
2584						  SEC_ACE_FLAG_INHERIT_ONLY))) {
2585				/*
2586				 * W2K wants to have access allowed zero access ACE's
2587				 * at the end of the list. If the mask is zero, merge
2588				 * the non-inherited ACE onto the inherited ACE.
2589				 */
2590
2591				if (nt_ace_list[i].info.mask == 0) {
2592					nt_ace_list[j].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2593								(i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2594					if (num_aces - i - 1 > 0)
2595						memmove(&nt_ace_list[i], &nt_ace_list[i+1], (num_aces-i-1) *
2596								sizeof(SEC_ACE));
2597
2598					DEBUG(10,("merge_default_aces: Merging zero access ACE %u onto ACE %u.\n",
2599						(unsigned int)i, (unsigned int)j ));
2600				} else {
2601					/*
2602					 * These are identical except for the flags.
2603					 * Merge the inherited ACE onto the non-inherited ACE.
2604					 */
2605
2606					nt_ace_list[i].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2607								(i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2608					if (num_aces - j - 1 > 0)
2609						memmove(&nt_ace_list[j], &nt_ace_list[j+1], (num_aces-j-1) *
2610								sizeof(SEC_ACE));
2611
2612					DEBUG(10,("merge_default_aces: Merging ACE %u onto ACE %u.\n",
2613						(unsigned int)j, (unsigned int)i ));
2614				}
2615				num_aces--;
2616				break;
2617			}
2618		}
2619	}
2620
2621	return num_aces;
2622}
2623/****************************************************************************
2624 Reply to query a security descriptor from an fsp. If it succeeds it allocates
2625 the space for the return elements and returns the size needed to return the
2626 security descriptor. This should be the only external function needed for
2627 the UNIX style get ACL.
2628****************************************************************************/
2629
2630size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc)
2631{
2632	extern DOM_SID global_sid_Builtin_Administrators;
2633	extern DOM_SID global_sid_Builtin_Users;
2634	extern DOM_SID global_sid_Creator_Owner;
2635	extern DOM_SID global_sid_Creator_Group;
2636	connection_struct *conn = fsp->conn;
2637	SMB_STRUCT_STAT sbuf;
2638	SEC_ACE *nt_ace_list = NULL;
2639	DOM_SID owner_sid;
2640	DOM_SID group_sid;
2641	size_t sd_size = 0;
2642	SEC_ACL *psa = NULL;
2643	size_t num_acls = 0;
2644	size_t num_def_acls = 0;
2645	size_t num_aces = 0;
2646	SMB_ACL_T posix_acl = NULL;
2647	SMB_ACL_T def_acl = NULL;
2648	canon_ace *file_ace = NULL;
2649	canon_ace *dir_ace = NULL;
2650	size_t num_profile_acls = 0;
2651	struct pai_val *pal = NULL;
2652	SEC_DESC *psd = NULL;
2653
2654	*ppdesc = NULL;
2655
2656	DEBUG(10,("get_nt_acl: called for file %s\n", fsp->fsp_name ));
2657
2658	if(fsp->is_directory || fsp->fd == -1) {
2659
2660		/* Get the stat struct for the owner info. */
2661		if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) {
2662			return 0;
2663		}
2664		/*
2665		 * Get the ACL from the path.
2666		 */
2667
2668		posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_ACCESS);
2669
2670		/*
2671		 * If it's a directory get the default POSIX ACL.
2672		 */
2673
2674		if(fsp->is_directory) {
2675			def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_DEFAULT);
2676			def_acl = free_empty_sys_acl(conn, def_acl);
2677		}
2678
2679	} else {
2680
2681		/* Get the stat struct for the owner info. */
2682		if(SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0) {
2683			return 0;
2684		}
2685		/*
2686		 * Get the ACL from the fd.
2687		 */
2688		posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fd);
2689	}
2690
2691	DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n",
2692			posix_acl ? "present" :  "absent",
2693			def_acl ? "present" :  "absent" ));
2694
2695	pal = load_inherited_info(fsp);
2696
2697	/*
2698	 * Get the owner, group and world SIDs.
2699	 */
2700
2701	if (lp_profile_acls(SNUM(fsp->conn))) {
2702		/* For WXP SP1 the owner must be administrators. */
2703		sid_copy(&owner_sid, &global_sid_Builtin_Administrators);
2704		sid_copy(&group_sid, &global_sid_Builtin_Users);
2705		num_profile_acls = 2;
2706	} else {
2707		create_file_sids(&sbuf, &owner_sid, &group_sid);
2708	}
2709
2710	if ((security_info & DACL_SECURITY_INFORMATION) && !(security_info & PROTECTED_DACL_SECURITY_INFORMATION)) {
2711
2712		/*
2713		 * In the optimum case Creator Owner and Creator Group would be used for
2714		 * the ACL_USER_OBJ and ACL_GROUP_OBJ entries, respectively, but this
2715		 * would lead to usability problems under Windows: The Creator entries
2716		 * are only available in browse lists of directories and not for files;
2717		 * additionally the identity of the owning group couldn't be determined.
2718		 * We therefore use those identities only for Default ACLs.
2719		 */
2720
2721		/* Create the canon_ace lists. */
2722		file_ace = canonicalise_acl( fsp, posix_acl, &sbuf, &owner_sid, &group_sid, pal, SMB_ACL_TYPE_ACCESS );
2723
2724		/* We must have *some* ACLS. */
2725
2726		if (count_canon_ace_list(file_ace) == 0) {
2727			DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", fsp->fsp_name ));
2728			return 0;
2729		}
2730
2731		if (fsp->is_directory && def_acl) {
2732			dir_ace = canonicalise_acl(fsp, def_acl, &sbuf,
2733					&global_sid_Creator_Owner,
2734					&global_sid_Creator_Group, pal, SMB_ACL_TYPE_DEFAULT );
2735		}
2736
2737		/*
2738		 * Create the NT ACE list from the canonical ace lists.
2739		 */
2740
2741		{
2742			canon_ace *ace;
2743			int nt_acl_type;
2744			int i;
2745
2746			if (nt4_compatible_acls() && dir_ace) {
2747				/*
2748				 * NT 4 chokes if an ACL contains an INHERIT_ONLY entry
2749				 * but no non-INHERIT_ONLY entry for one SID. So we only
2750				 * remove entries from the Access ACL if the
2751				 * corresponding Default ACL entries have also been
2752				 * removed. ACEs for CREATOR-OWNER and CREATOR-GROUP
2753				 * are exceptions. We can do nothing
2754				 * intelligent if the Default ACL contains entries that
2755				 * are not also contained in the Access ACL, so this
2756				 * case will still fail under NT 4.
2757				 */
2758
2759				ace = canon_ace_entry_for(dir_ace, SMB_ACL_OTHER, NULL);
2760				if (ace && !ace->perms) {
2761					DLIST_REMOVE(dir_ace, ace);
2762					SAFE_FREE(ace);
2763
2764					ace = canon_ace_entry_for(file_ace, SMB_ACL_OTHER, NULL);
2765					if (ace && !ace->perms) {
2766						DLIST_REMOVE(file_ace, ace);
2767						SAFE_FREE(ace);
2768					}
2769				}
2770
2771				/*
2772				 * WinNT doesn't usually have Creator Group
2773				 * in browse lists, so we send this entry to
2774				 * WinNT even if it contains no relevant
2775				 * permissions. Once we can add
2776				 * Creator Group to browse lists we can
2777				 * re-enable this.
2778				 */
2779
2780#if 0
2781				ace = canon_ace_entry_for(dir_ace, SMB_ACL_GROUP_OBJ, NULL);
2782				if (ace && !ace->perms) {
2783					DLIST_REMOVE(dir_ace, ace);
2784					SAFE_FREE(ace);
2785				}
2786#endif
2787
2788				ace = canon_ace_entry_for(file_ace, SMB_ACL_GROUP_OBJ, NULL);
2789				if (ace && !ace->perms) {
2790					DLIST_REMOVE(file_ace, ace);
2791					SAFE_FREE(ace);
2792				}
2793			}
2794
2795			num_acls = count_canon_ace_list(file_ace);
2796			num_def_acls = count_canon_ace_list(dir_ace);
2797
2798			/* Allocate the ace list. */
2799			if ((nt_ace_list = SMB_MALLOC_ARRAY(SEC_ACE,num_acls + num_profile_acls + num_def_acls)) == NULL) {
2800				DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
2801				goto done;
2802			}
2803
2804			memset(nt_ace_list, '\0', (num_acls + num_def_acls) * sizeof(SEC_ACE) );
2805
2806			/*
2807			 * Create the NT ACE list from the canonical ace lists.
2808			 */
2809
2810			ace = file_ace;
2811
2812			for (i = 0; i < num_acls; i++, ace = ace->next) {
2813				SEC_ACCESS acc;
2814
2815				acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
2816				init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc, ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2817			}
2818
2819			/* The User must have access to a profile share - even if we can't map the SID. */
2820			if (lp_profile_acls(SNUM(fsp->conn))) {
2821				SEC_ACCESS acc;
2822
2823				init_sec_access(&acc,FILE_GENERIC_ALL);
2824				init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED,
2825						acc, 0);
2826			}
2827
2828			ace = dir_ace;
2829
2830			for (i = 0; i < num_def_acls; i++, ace = ace->next) {
2831				SEC_ACCESS acc;
2832
2833				acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
2834				init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc,
2835						SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2836						SEC_ACE_FLAG_INHERIT_ONLY|
2837						(ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 0));
2838			}
2839
2840			/* The User must have access to a profile share - even if we can't map the SID. */
2841			if (lp_profile_acls(SNUM(fsp->conn))) {
2842				SEC_ACCESS acc;
2843
2844				init_sec_access(&acc,FILE_GENERIC_ALL);
2845				init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, acc,
2846						SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2847						SEC_ACE_FLAG_INHERIT_ONLY|0);
2848			}
2849
2850			/*
2851			 * Merge POSIX default ACLs and normal ACLs into one NT ACE.
2852			 * Win2K needs this to get the inheritance correct when replacing ACLs
2853			 * on a directory tree. Based on work by Jim @ IBM.
2854			 */
2855
2856			num_aces = merge_default_aces(nt_ace_list, num_aces);
2857
2858		}
2859
2860		if (num_aces) {
2861			if((psa = make_sec_acl( main_loop_talloc_get(), NT4_ACL_REVISION, num_aces, nt_ace_list)) == NULL) {
2862				DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
2863				goto done;
2864			}
2865		}
2866	} /* security_info & DACL_SECURITY_INFORMATION */
2867
2868	psd = make_standard_sec_desc( main_loop_talloc_get(),
2869			(security_info & OWNER_SECURITY_INFORMATION) ? &owner_sid : NULL,
2870			(security_info & GROUP_SECURITY_INFORMATION) ? &group_sid : NULL,
2871			psa,
2872			&sd_size);
2873
2874	if(!psd) {
2875		DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
2876		sd_size = 0;
2877	} else {
2878		/*
2879		 * Windows 2000: The DACL_PROTECTED flag in the security
2880		 * descriptor marks the ACL as non-inheriting, i.e., no
2881		 * ACEs from higher level directories propagate to this
2882		 * ACL. In the POSIX ACL model permissions are only
2883		 * inherited at file create time, so ACLs never contain
2884		 * any ACEs that are inherited dynamically. The DACL_PROTECTED
2885		 * flag doesn't seem to bother Windows NT.
2886		 * Always set this if map acl inherit is turned off.
2887		 */
2888		if (get_protected_flag(pal) || !lp_map_acl_inherit(SNUM(conn))) {
2889			psd->type |= SE_DESC_DACL_PROTECTED;
2890		}
2891	}
2892
2893	if (psd->dacl)
2894		dacl_sort_into_canonical_order(psd->dacl->ace, (unsigned int)psd->dacl->num_aces);
2895
2896	*ppdesc = psd;
2897
2898 done:
2899
2900	if (posix_acl)
2901		SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
2902	if (def_acl)
2903		SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
2904	free_canon_ace_list(file_ace);
2905	free_canon_ace_list(dir_ace);
2906	free_inherited_info(pal);
2907	SAFE_FREE(nt_ace_list);
2908
2909	return sd_size;
2910}
2911
2912/****************************************************************************
2913 Try to chown a file. We will be able to chown it under the following conditions.
2914
2915  1) If we have root privileges, then it will just work.
2916  2) If we have write permission to the file and dos_filemodes is set
2917     then allow chown to the currently authenticated user.
2918****************************************************************************/
2919
2920static int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid)
2921{
2922	int ret;
2923	extern struct current_user current_user;
2924	files_struct *fsp;
2925	SMB_STRUCT_STAT st;
2926
2927	/* try the direct way first */
2928	ret = SMB_VFS_CHOWN(conn, fname, uid, gid);
2929	if (ret == 0)
2930		return 0;
2931
2932	if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
2933		return -1;
2934
2935	if (SMB_VFS_STAT(conn,fname,&st))
2936		return -1;
2937
2938	fsp = open_file_fchmod(conn,fname,&st);
2939	if (!fsp)
2940		return -1;
2941
2942	/* only allow chown to the current user. This is more secure,
2943	   and also copes with the case where the SID in a take ownership ACL is
2944	   a local SID on the users workstation
2945	*/
2946	uid = current_user.uid;
2947
2948	become_root();
2949	/* Keep the current file gid the same. */
2950	ret = SMB_VFS_FCHOWN(fsp, fsp->fd, uid, (gid_t)-1);
2951	unbecome_root();
2952
2953	close_file_fchmod(fsp);
2954
2955	return ret;
2956}
2957
2958/****************************************************************************
2959 Reply to set a security descriptor on an fsp. security_info_sent is the
2960 description of the following NT ACL.
2961 This should be the only external function needed for the UNIX style set ACL.
2962****************************************************************************/
2963
2964BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
2965{
2966	connection_struct *conn = fsp->conn;
2967	uid_t user = (uid_t)-1;
2968	gid_t grp = (gid_t)-1;
2969	SMB_STRUCT_STAT sbuf;
2970	DOM_SID file_owner_sid;
2971	DOM_SID file_grp_sid;
2972	canon_ace *file_ace_list = NULL;
2973	canon_ace *dir_ace_list = NULL;
2974	BOOL acl_perms = False;
2975	mode_t orig_mode = (mode_t)0;
2976	uid_t orig_uid;
2977	gid_t orig_gid;
2978	BOOL need_chown = False;
2979	extern struct current_user current_user;
2980
2981	DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name ));
2982
2983	if (!CAN_WRITE(conn)) {
2984		DEBUG(10,("set acl rejected on read-only share\n"));
2985		return False;
2986	}
2987
2988	/*
2989	 * Get the current state of the file.
2990	 */
2991
2992	if(fsp->is_directory || fsp->fd == -1) {
2993		if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0)
2994			return False;
2995	} else {
2996		if(SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0)
2997			return False;
2998	}
2999
3000	/* Save the original elements we check against. */
3001	orig_mode = sbuf.st_mode;
3002	orig_uid = sbuf.st_uid;
3003	orig_gid = sbuf.st_gid;
3004
3005	/*
3006	 * Unpack the user/group/world id's.
3007	 */
3008
3009	if (!unpack_nt_owners( SNUM(conn), &sbuf, &user, &grp, security_info_sent, psd))
3010		return False;
3011
3012	/*
3013	 * Do we need to chown ?
3014	 */
3015
3016	if (((user != (uid_t)-1) && (orig_uid != user)) || (( grp != (gid_t)-1) && (orig_gid != grp)))
3017		need_chown = True;
3018
3019	/*
3020	 * Chown before setting ACL only if we don't change the user, or
3021	 * if we change to the current user, but not if we want to give away
3022	 * the file.
3023	 */
3024
3025	if (need_chown && (user == (uid_t)-1 || user == current_user.uid)) {
3026
3027		DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
3028				fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
3029
3030		if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
3031			DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
3032				fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
3033			return False;
3034		}
3035
3036		/*
3037		 * Recheck the current state of the file, which may have changed.
3038		 * (suid/sgid bits, for instance)
3039		 */
3040
3041		if(fsp->is_directory) {
3042			if(SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf) != 0) {
3043				return False;
3044			}
3045		} else {
3046
3047			int ret;
3048
3049			if(fsp->fd == -1)
3050				ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf);
3051			else
3052				ret = SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf);
3053
3054			if(ret != 0)
3055				return False;
3056		}
3057
3058		/* Save the original elements we check against. */
3059		orig_mode = sbuf.st_mode;
3060		orig_uid = sbuf.st_uid;
3061		orig_gid = sbuf.st_gid;
3062
3063		/* We did it, don't try again */
3064		need_chown = False;
3065	}
3066
3067	create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid);
3068
3069	acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid,
3070									&file_ace_list, &dir_ace_list, security_info_sent, psd);
3071
3072	/* Ignore W2K traverse DACL set. */
3073	if (file_ace_list || dir_ace_list) {
3074
3075		if (!acl_perms) {
3076			DEBUG(3,("set_nt_acl: cannot set permissions\n"));
3077			free_canon_ace_list(file_ace_list);
3078			free_canon_ace_list(dir_ace_list);
3079			return False;
3080		}
3081
3082		/*
3083		 * Only change security if we got a DACL.
3084		 */
3085
3086		if((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl != NULL)) {
3087
3088			BOOL acl_set_support = False;
3089			BOOL ret = False;
3090
3091			/*
3092			 * Try using the POSIX ACL set first. Fall back to chmod if
3093			 * we have no ACL support on this filesystem.
3094			 */
3095
3096			if (acl_perms && file_ace_list) {
3097				ret = set_canon_ace_list(fsp, file_ace_list, False, &acl_set_support);
3098				if (acl_set_support && ret == False) {
3099					DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) ));
3100					free_canon_ace_list(file_ace_list);
3101					free_canon_ace_list(dir_ace_list);
3102					return False;
3103				}
3104			}
3105
3106			if (acl_perms && acl_set_support && fsp->is_directory) {
3107				if (dir_ace_list) {
3108					if (!set_canon_ace_list(fsp, dir_ace_list, True, &acl_set_support)) {
3109						DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) ));
3110						free_canon_ace_list(file_ace_list);
3111						free_canon_ace_list(dir_ace_list);
3112						return False;
3113					}
3114				} else {
3115
3116					/*
3117					 * No default ACL - delete one if it exists.
3118					 */
3119
3120					if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name) == -1) {
3121						DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno)));
3122						free_canon_ace_list(file_ace_list);
3123						free_canon_ace_list(dir_ace_list);
3124						return False;
3125					}
3126				}
3127			}
3128
3129			if (acl_set_support)
3130				store_inheritance_attributes(fsp, file_ace_list, dir_ace_list,
3131						(psd->type & SE_DESC_DACL_PROTECTED) ? True : False);
3132
3133			/*
3134			 * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
3135			 */
3136
3137			if(!acl_set_support && acl_perms) {
3138				mode_t posix_perms;
3139
3140				if (!convert_canon_ace_to_posix_perms( fsp, file_ace_list, &posix_perms)) {
3141					free_canon_ace_list(file_ace_list);
3142					free_canon_ace_list(dir_ace_list);
3143					DEBUG(3,("set_nt_acl: failed to convert file acl to posix permissions for file %s.\n",
3144						fsp->fsp_name ));
3145					return False;
3146				}
3147
3148				if (orig_mode != posix_perms) {
3149
3150					DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
3151						fsp->fsp_name, (unsigned int)posix_perms ));
3152
3153					if(SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms) == -1) {
3154						DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n",
3155								fsp->fsp_name, (unsigned int)posix_perms, strerror(errno) ));
3156						free_canon_ace_list(file_ace_list);
3157						free_canon_ace_list(dir_ace_list);
3158						return False;
3159					}
3160				}
3161			}
3162		}
3163
3164		free_canon_ace_list(file_ace_list);
3165		free_canon_ace_list(dir_ace_list);
3166	}
3167
3168	/* Any chown pending? */
3169	if (need_chown) {
3170
3171		DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
3172			fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
3173
3174		if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
3175			DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
3176				fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
3177			return False;
3178		}
3179	}
3180
3181	return True;
3182}
3183
3184/****************************************************************************
3185 Get the actual group bits stored on a file with an ACL. Has no effect if
3186 the file has no ACL. Needed in dosmode code where the stat() will return
3187 the mask bits, not the real group bits, for a file with an ACL.
3188****************************************************************************/
3189
3190int get_acl_group_bits( connection_struct *conn, const char *fname, mode_t *mode )
3191{
3192	int entry_id = SMB_ACL_FIRST_ENTRY;
3193	SMB_ACL_ENTRY_T entry;
3194	SMB_ACL_T posix_acl;
3195	int result = -1;
3196
3197	posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS);
3198	if (posix_acl == (SMB_ACL_T)NULL)
3199		return -1;
3200
3201	while (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
3202		SMB_ACL_TAG_T tagtype;
3203		SMB_ACL_PERMSET_T permset;
3204
3205		/* get_next... */
3206		if (entry_id == SMB_ACL_FIRST_ENTRY)
3207			entry_id = SMB_ACL_NEXT_ENTRY;
3208
3209		if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) ==-1)
3210			break;
3211
3212		if (tagtype == SMB_ACL_GROUP_OBJ) {
3213			if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
3214				break;
3215			} else {
3216				*mode &= ~(S_IRGRP|S_IWGRP|S_IXGRP);
3217				*mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRGRP : 0);
3218				*mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWGRP : 0);
3219				*mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXGRP : 0);
3220				result = 0;
3221				break;
3222			}
3223		}
3224	}
3225	SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
3226	return result;
3227}
3228
3229/****************************************************************************
3230 Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3231 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3232****************************************************************************/
3233
3234static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mode_t mode)
3235{
3236	int entry_id = SMB_ACL_FIRST_ENTRY;
3237	SMB_ACL_ENTRY_T entry;
3238	int num_entries = 0;
3239
3240	while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
3241		SMB_ACL_TAG_T tagtype;
3242		SMB_ACL_PERMSET_T permset;
3243		mode_t perms;
3244
3245		/* get_next... */
3246		if (entry_id == SMB_ACL_FIRST_ENTRY)
3247			entry_id = SMB_ACL_NEXT_ENTRY;
3248
3249		if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
3250			return -1;
3251
3252		if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
3253			return -1;
3254
3255		num_entries++;
3256
3257		switch(tagtype) {
3258			case SMB_ACL_USER_OBJ:
3259				perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
3260				break;
3261			case SMB_ACL_GROUP_OBJ:
3262				perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
3263				break;
3264			case SMB_ACL_MASK:
3265				/*
3266				 * FIXME: The ACL_MASK entry permissions should really be set to
3267				 * the union of the permissions of all ACL_USER,
3268				 * ACL_GROUP_OBJ, and ACL_GROUP entries. That's what
3269				 * acl_calc_mask() does, but Samba ACLs doesn't provide it.
3270				 */
3271				perms = S_IRUSR|S_IWUSR|S_IXUSR;
3272				break;
3273			case SMB_ACL_OTHER:
3274				perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
3275				break;
3276			default:
3277				continue;
3278		}
3279
3280		if (map_acl_perms_to_permset(conn, perms, &permset) == -1)
3281			return -1;
3282
3283		if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, entry, permset) == -1)
3284			return -1;
3285	}
3286
3287	/*
3288	 * If this is a simple 3 element ACL or no elements then it's a standard
3289	 * UNIX permission set. Just use chmod...
3290	 */
3291
3292	if ((num_entries == 3) || (num_entries == 0))
3293		return -1;
3294
3295	return 0;
3296}
3297
3298/****************************************************************************
3299 Get the access ACL of FROM, do a chmod by setting the ACL USER_OBJ,
3300 GROUP_OBJ and OTHER bits in an ACL and set the mask to rwx. Set the
3301 resulting ACL on TO.  Note that name is in UNIX character set.
3302****************************************************************************/
3303
3304static int copy_access_acl(connection_struct *conn, const char *from, const char *to, mode_t mode)
3305{
3306	SMB_ACL_T posix_acl = NULL;
3307	int ret = -1;
3308
3309	if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, from, SMB_ACL_TYPE_ACCESS)) == NULL)
3310		return -1;
3311
3312	if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
3313		goto done;
3314
3315	ret = SMB_VFS_SYS_ACL_SET_FILE(conn, to, SMB_ACL_TYPE_ACCESS, posix_acl);
3316
3317 done:
3318
3319	SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
3320	return ret;
3321}
3322
3323/****************************************************************************
3324 Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3325 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3326 Note that name is in UNIX character set.
3327****************************************************************************/
3328
3329int chmod_acl(connection_struct *conn, const char *name, mode_t mode)
3330{
3331	return copy_access_acl(conn, name, name, mode);
3332}
3333
3334/****************************************************************************
3335 If "inherit permissions" is set and the parent directory has no default
3336 ACL but it does have an Access ACL, inherit this Access ACL to file name.
3337****************************************************************************/
3338
3339int inherit_access_acl(connection_struct *conn, const char *name, mode_t mode)
3340{
3341	pstring dirname;
3342	pstrcpy(dirname, parent_dirname(name));
3343
3344	if (!lp_inherit_perms(SNUM(conn)) || directory_has_default_acl(conn, dirname))
3345		return 0;
3346
3347	return copy_access_acl(conn, dirname, name, mode);
3348}
3349
3350/****************************************************************************
3351 Do an fchmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3352 and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3353****************************************************************************/
3354
3355int fchmod_acl(files_struct *fsp, int fd, mode_t mode)
3356{
3357	connection_struct *conn = fsp->conn;
3358	SMB_ACL_T posix_acl = NULL;
3359	int ret = -1;
3360
3361	if ((posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fd)) == NULL)
3362		return -1;
3363
3364	if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
3365		goto done;
3366
3367	ret = SMB_VFS_SYS_ACL_SET_FD(fsp, fd, posix_acl);
3368
3369  done:
3370
3371	SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
3372	return ret;
3373}
3374
3375/****************************************************************************
3376 Check for an existing default POSIX ACL on a directory.
3377****************************************************************************/
3378
3379BOOL directory_has_default_acl(connection_struct *conn, const char *fname)
3380{
3381	SMB_ACL_T def_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_DEFAULT);
3382	BOOL has_acl = False;
3383	SMB_ACL_ENTRY_T entry;
3384
3385	if (def_acl != NULL && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, def_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1)) {
3386		has_acl = True;
3387	}
3388
3389	if (def_acl) {
3390	        SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
3391	}
3392        return has_acl;
3393}
3394
3395/****************************************************************************
3396 Map from wire type to permset.
3397****************************************************************************/
3398
3399static BOOL unix_ex_wire_to_permset(connection_struct *conn, unsigned char wire_perm, SMB_ACL_PERMSET_T *p_permset)
3400{
3401	if (wire_perm & ~(SMB_POSIX_ACL_READ|SMB_POSIX_ACL_WRITE|SMB_POSIX_ACL_EXECUTE)) {
3402		return False;
3403	}
3404
3405	if (SMB_VFS_SYS_ACL_CLEAR_PERMS(conn, *p_permset) ==  -1) {
3406		return False;
3407	}
3408
3409	if (wire_perm & SMB_POSIX_ACL_READ) {
3410		if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_READ) == -1) {
3411			return False;
3412		}
3413	}
3414	if (wire_perm & SMB_POSIX_ACL_WRITE) {
3415		if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_WRITE) == -1) {
3416			return False;
3417		}
3418	}
3419	if (wire_perm & SMB_POSIX_ACL_EXECUTE) {
3420		if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_EXECUTE) == -1) {
3421			return False;
3422		}
3423	}
3424	return True;
3425}
3426
3427/****************************************************************************
3428 Map from wire type to tagtype.
3429****************************************************************************/
3430
3431static BOOL unix_ex_wire_to_tagtype(unsigned char wire_tt, SMB_ACL_TAG_T *p_tt)
3432{
3433	switch (wire_tt) {
3434		case SMB_POSIX_ACL_USER_OBJ:
3435			*p_tt = SMB_ACL_USER_OBJ;
3436			break;
3437		case SMB_POSIX_ACL_USER:
3438			*p_tt = SMB_ACL_USER;
3439			break;
3440		case SMB_POSIX_ACL_GROUP_OBJ:
3441			*p_tt = SMB_ACL_GROUP_OBJ;
3442			break;
3443		case SMB_POSIX_ACL_GROUP:
3444			*p_tt = SMB_ACL_GROUP;
3445			break;
3446		case SMB_POSIX_ACL_MASK:
3447			*p_tt = SMB_ACL_MASK;
3448			break;
3449		case SMB_POSIX_ACL_OTHER:
3450			*p_tt = SMB_ACL_OTHER;
3451			break;
3452		default:
3453			return False;
3454	}
3455	return True;
3456}
3457
3458/****************************************************************************
3459 Create a new POSIX acl from wire permissions.
3460 FIXME ! How does the share mask/mode fit into this.... ?
3461****************************************************************************/
3462
3463static SMB_ACL_T create_posix_acl_from_wire(connection_struct *conn, uint16 num_acls, const char *pdata)
3464{
3465	unsigned int i;
3466	SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, num_acls);
3467
3468	if (the_acl == NULL) {
3469		return NULL;
3470	}
3471
3472	for (i = 0; i < num_acls; i++) {
3473		SMB_ACL_ENTRY_T the_entry;
3474		SMB_ACL_PERMSET_T the_permset;
3475		SMB_ACL_TAG_T tag_type;
3476
3477		if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) {
3478			DEBUG(0,("create_posix_acl_from_wire: Failed to create entry %u. (%s)\n",
3479				i, strerror(errno) ));
3480			goto fail;
3481		}
3482
3483		if (!unix_ex_wire_to_tagtype(CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)), &tag_type)) {
3484			DEBUG(0,("create_posix_acl_from_wire: invalid wire tagtype %u on entry %u.\n",
3485				CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)), i ));
3486			goto fail;
3487		}
3488
3489		if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, tag_type) == -1) {
3490			DEBUG(0,("create_posix_acl_from_wire: Failed to set tagtype on entry %u. (%s)\n",
3491				i, strerror(errno) ));
3492			goto fail;
3493		}
3494
3495		/* Get the permset pointer from the new ACL entry. */
3496		if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) {
3497			DEBUG(0,("create_posix_acl_from_wire: Failed to get permset on entry %u. (%s)\n",
3498                                i, strerror(errno) ));
3499                        goto fail;
3500                }
3501
3502		/* Map from wire to permissions. */
3503		if (!unix_ex_wire_to_permset(conn, CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+1), &the_permset)) {
3504			DEBUG(0,("create_posix_acl_from_wire: invalid permset %u on entry %u.\n",
3505				CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE) + 1), i ));
3506			goto fail;
3507		}
3508
3509		/* Now apply to the new ACL entry. */
3510		if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) {
3511			DEBUG(0,("create_posix_acl_from_wire: Failed to add permset on entry %u. (%s)\n",
3512				i, strerror(errno) ));
3513			goto fail;
3514		}
3515
3516		if (tag_type == SMB_ACL_USER) {
3517			uint32 uidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3518			uid_t uid = (uid_t)uidval;
3519			if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&uid) == -1) {
3520				DEBUG(0,("create_posix_acl_from_wire: Failed to set uid %u on entry %u. (%s)\n",
3521					(unsigned int)uid, i, strerror(errno) ));
3522				goto fail;
3523			}
3524		}
3525
3526		if (tag_type == SMB_ACL_GROUP) {
3527			uint32 gidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3528			gid_t gid = (uid_t)gidval;
3529			if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&gid) == -1) {
3530				DEBUG(0,("create_posix_acl_from_wire: Failed to set gid %u on entry %u. (%s)\n",
3531					(unsigned int)gid, i, strerror(errno) ));
3532				goto fail;
3533			}
3534		}
3535	}
3536
3537	return the_acl;
3538
3539 fail:
3540
3541	if (the_acl != NULL) {
3542		SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
3543	}
3544	return NULL;
3545}
3546
3547/****************************************************************************
3548 Calls from UNIX extensions - Default POSIX ACL set.
3549 If num_def_acls == 0 and not a directory just return. If it is a directory
3550 and num_def_acls == 0 then remove the default acl. Else set the default acl
3551 on the directory.
3552****************************************************************************/
3553
3554BOOL set_unix_posix_default_acl(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf,
3555				uint16 num_def_acls, const char *pdata)
3556{
3557	SMB_ACL_T def_acl = NULL;
3558
3559	if (num_def_acls && !S_ISDIR(psbuf->st_mode)) {
3560		DEBUG(5,("set_unix_posix_default_acl: Can't set default ACL on non-directory file %s\n", fname ));
3561		errno = EISDIR;
3562		return False;
3563	}
3564
3565	if (!num_def_acls) {
3566		/* Remove the default ACL. */
3567		if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fname) == -1) {
3568			DEBUG(5,("set_unix_posix_default_acl: acl_delete_def_file failed on directory %s (%s)\n",
3569				fname, strerror(errno) ));
3570			return False;
3571		}
3572		return True;
3573	}
3574
3575	if ((def_acl = create_posix_acl_from_wire(conn, num_def_acls, pdata)) == NULL) {
3576		return False;
3577	}
3578
3579	if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_DEFAULT, def_acl) == -1) {
3580		DEBUG(5,("set_unix_posix_default_acl: acl_set_file failed on directory %s (%s)\n",
3581			fname, strerror(errno) ));
3582	        SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
3583		return False;
3584	}
3585
3586	DEBUG(10,("set_unix_posix_default_acl: set default acl for file %s\n", fname ));
3587	SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
3588	return True;
3589}
3590
3591/****************************************************************************
3592 Remove an ACL from a file. As we don't have acl_delete_entry() available
3593 we must read the current acl and copy all entries except MASK, USER and GROUP
3594 to a new acl, then set that. This (at least on Linux) causes any ACL to be
3595 removed.
3596 FIXME ! How does the share mask/mode fit into this.... ?
3597****************************************************************************/
3598
3599static BOOL remove_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname)
3600{
3601	SMB_ACL_T file_acl = NULL;
3602	int entry_id = SMB_ACL_FIRST_ENTRY;
3603	SMB_ACL_ENTRY_T entry;
3604	BOOL ret = False;
3605	/* Create a new ACL with only 3 entries, u/g/w. */
3606	SMB_ACL_T new_file_acl = SMB_VFS_SYS_ACL_INIT(conn, 3);
3607	SMB_ACL_ENTRY_T user_ent = NULL;
3608	SMB_ACL_ENTRY_T group_ent = NULL;
3609	SMB_ACL_ENTRY_T other_ent = NULL;
3610
3611	if (new_file_acl == NULL) {
3612		DEBUG(5,("remove_posix_acl: failed to init new ACL with 3 entries for file %s.\n", fname));
3613		return False;
3614	}
3615
3616	/* Now create the u/g/w entries. */
3617	if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &user_ent) == -1) {
3618		DEBUG(5,("remove_posix_acl: Failed to create user entry for file %s. (%s)\n",
3619			fname, strerror(errno) ));
3620		goto done;
3621	}
3622	if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, user_ent, SMB_ACL_USER_OBJ) == -1) {
3623		DEBUG(5,("remove_posix_acl: Failed to set user entry for file %s. (%s)\n",
3624			fname, strerror(errno) ));
3625		goto done;
3626	}
3627
3628	if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &group_ent) == -1) {
3629		DEBUG(5,("remove_posix_acl: Failed to create group entry for file %s. (%s)\n",
3630			fname, strerror(errno) ));
3631		goto done;
3632	}
3633	if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, group_ent, SMB_ACL_GROUP_OBJ) == -1) {
3634		DEBUG(5,("remove_posix_acl: Failed to set group entry for file %s. (%s)\n",
3635			fname, strerror(errno) ));
3636		goto done;
3637	}
3638
3639	if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &other_ent) == -1) {
3640		DEBUG(5,("remove_posix_acl: Failed to create other entry for file %s. (%s)\n",
3641			fname, strerror(errno) ));
3642		goto done;
3643	}
3644	if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, other_ent, SMB_ACL_OTHER) == -1) {
3645		DEBUG(5,("remove_posix_acl: Failed to set other entry for file %s. (%s)\n",
3646			fname, strerror(errno) ));
3647		goto done;
3648	}
3649
3650	/* Get the current file ACL. */
3651	if (fsp && fsp->fd != -1) {
3652		file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fd);
3653	} else {
3654		file_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_ACCESS);
3655	}
3656
3657	if (file_acl == NULL) {
3658		/* This is only returned if an error occurred. Even for a file with
3659		   no acl a u/g/w acl should be returned. */
3660		DEBUG(5,("remove_posix_acl: failed to get ACL from file %s (%s).\n",
3661			fname, strerror(errno) ));
3662		goto done;
3663	}
3664
3665	while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, file_acl, entry_id, &entry) == 1) {
3666		SMB_ACL_TAG_T tagtype;
3667		SMB_ACL_PERMSET_T permset;
3668
3669		/* get_next... */
3670		if (entry_id == SMB_ACL_FIRST_ENTRY)
3671			entry_id = SMB_ACL_NEXT_ENTRY;
3672
3673		if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
3674			DEBUG(5,("remove_posix_acl: failed to get tagtype from ACL on file %s (%s).\n",
3675				fname, strerror(errno) ));
3676			goto done;
3677		}
3678
3679		if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
3680			DEBUG(5,("remove_posix_acl: failed to get permset from ACL on file %s (%s).\n",
3681				fname, strerror(errno) ));
3682			goto done;
3683		}
3684
3685		if (tagtype == SMB_ACL_USER_OBJ) {
3686			if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, user_ent, permset) == -1) {
3687				DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
3688					fname, strerror(errno) ));
3689			}
3690		} else if (tagtype == SMB_ACL_GROUP_OBJ) {
3691			if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, group_ent, permset) == -1) {
3692				DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
3693					fname, strerror(errno) ));
3694			}
3695		} else if (tagtype == SMB_ACL_OTHER) {
3696			if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, other_ent, permset) == -1) {
3697				DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
3698					fname, strerror(errno) ));
3699			}
3700		}
3701	}
3702
3703	ret = True;
3704
3705 done:
3706
3707	if (file_acl) {
3708		SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
3709	}
3710	if (new_file_acl) {
3711		SMB_VFS_SYS_ACL_FREE_ACL(conn, new_file_acl);
3712	}
3713	return ret;
3714}
3715
3716/****************************************************************************
3717 Calls from UNIX extensions - POSIX ACL set.
3718 If num_def_acls == 0 then read/modify/write acl after removing all entries
3719 except SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER.
3720****************************************************************************/
3721
3722BOOL set_unix_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname, uint16 num_acls, const char *pdata)
3723{
3724	SMB_ACL_T file_acl = NULL;
3725
3726	if (!num_acls) {
3727		/* Remove the ACL from the file. */
3728		return remove_posix_acl(conn, fsp, fname);
3729	}
3730
3731	if ((file_acl = create_posix_acl_from_wire(conn, num_acls, pdata)) == NULL) {
3732		return False;
3733	}
3734
3735	if (fsp && fsp->fd != -1) {
3736		/* The preferred way - use an open fd. */
3737		if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fd, file_acl) == -1) {
3738			DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n",
3739				fname, strerror(errno) ));
3740		        SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
3741			return False;
3742		}
3743	} else {
3744		if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS, file_acl) == -1) {
3745			DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n",
3746				fname, strerror(errno) ));
3747		        SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
3748			return False;
3749		}
3750	}
3751
3752	DEBUG(10,("set_unix_posix_acl: set acl for file %s\n", fname ));
3753	SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
3754	return True;
3755}
3756
3757/****************************************************************************
3758 Check for POSIX group ACLs. If none use stat entry.
3759****************************************************************************/
3760
3761static int check_posix_acl_group_write(connection_struct *conn, const char *dname, SMB_STRUCT_STAT *psbuf)
3762{
3763	extern struct current_user current_user;
3764	SMB_ACL_T posix_acl = NULL;
3765	int entry_id = SMB_ACL_FIRST_ENTRY;
3766	SMB_ACL_ENTRY_T entry;
3767	int i;
3768	int ret = -1;
3769
3770	if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, dname, SMB_ACL_TYPE_ACCESS)) == NULL) {
3771		goto check_stat;
3772	}
3773
3774	/* First ensure the group mask allows group read. */
3775	while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
3776		SMB_ACL_TAG_T tagtype;
3777		SMB_ACL_PERMSET_T permset;
3778
3779		/* get_next... */
3780		if (entry_id == SMB_ACL_FIRST_ENTRY)
3781			entry_id = SMB_ACL_NEXT_ENTRY;
3782
3783		if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
3784			goto check_stat;
3785		}
3786
3787		if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
3788			goto check_stat;
3789		}
3790
3791		switch(tagtype) {
3792			case SMB_ACL_MASK:
3793				if (!SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE)) {
3794					/* We don't have group write permission. */
3795					ret = -1; /* Allow caller to check "other" permissions. */
3796					goto done;
3797				}
3798				break;
3799			default:
3800				continue;
3801		}
3802	}
3803
3804	/* Now check all group entries. */
3805	entry_id = SMB_ACL_FIRST_ENTRY;
3806	while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
3807		SMB_ACL_TAG_T tagtype;
3808		SMB_ACL_PERMSET_T permset;
3809		int have_write = -1;
3810
3811		/* get_next... */
3812		if (entry_id == SMB_ACL_FIRST_ENTRY)
3813			entry_id = SMB_ACL_NEXT_ENTRY;
3814
3815		if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
3816			goto check_stat;
3817		}
3818
3819		if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
3820			goto check_stat;
3821		}
3822
3823		have_write = SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE);
3824		if (have_write == -1) {
3825			goto check_stat;
3826		}
3827
3828		switch(tagtype) {
3829			case SMB_ACL_USER:
3830				{
3831					/* Check against current_user.uid. */
3832					uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
3833					if (puid == NULL) {
3834						goto check_stat;
3835					}
3836					if (current_user.uid == *puid) {
3837						/* We're done now we have a uid match. */
3838						ret = have_write;
3839						goto done;
3840					}
3841				}
3842				break;
3843			case SMB_ACL_GROUP:
3844				{
3845					gid_t *pgid = (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
3846					if (pgid == NULL) {
3847						goto check_stat;
3848					}
3849					for (i = 0; i < current_user.ngroups; i++) {
3850						if (current_user.groups[i] == *pgid) {
3851							/* We're done now we have a gid match. */
3852							ret = have_write;
3853							goto done;
3854						}
3855					}
3856				}
3857				break;
3858			default:
3859				continue;
3860		}
3861	}
3862
3863
3864  check_stat:
3865
3866	for (i = 0; i < current_user.ngroups; i++) {
3867		if (current_user.groups[i] == psbuf->st_gid) {
3868			ret = (psbuf->st_mode & S_IWGRP) ? 1 : 0;
3869			break;
3870		}
3871	}
3872
3873  done:
3874
3875	SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
3876	return ret;
3877}
3878
3879/****************************************************************************
3880 Actually emulate the in-kernel access checking for write access. We need
3881 this to successfully return ACCESS_DENIED on a file open for delete access.
3882****************************************************************************/
3883
3884BOOL can_delete_file_in_directory(connection_struct *conn, const char *fname)
3885{
3886	extern struct current_user current_user;
3887	SMB_STRUCT_STAT sbuf;
3888	pstring dname;
3889	int ret;
3890
3891	pstrcpy(dname, parent_dirname(fname));
3892	if(SMB_VFS_STAT(conn, dname, &sbuf) != 0) {
3893		return False;
3894	}
3895	if (!S_ISDIR(sbuf.st_mode)) {
3896		return False;
3897	}
3898	if (current_user.uid == 0) {
3899		/* I'm sorry sir, I didn't know you were root... */
3900		return True;
3901	}
3902
3903	if (current_user.uid == sbuf.st_uid) {
3904		return (sbuf.st_mode & S_IWUSR) ? True : False;
3905	}
3906
3907#ifdef S_ISVTX
3908	/* sticky bit means delete only by owner or root. */
3909	if (sbuf.st_mode & S_ISVTX) {
3910		SMB_STRUCT_STAT sbuf_file;
3911		if(SMB_VFS_STAT(conn, fname, &sbuf_file) != 0) {
3912			return False;
3913		}
3914		if (current_user.uid == sbuf_file.st_uid) {
3915			return True;
3916		}
3917		return False;
3918	}
3919#endif
3920
3921	/* Check group ownership. */
3922	ret = check_posix_acl_group_write(conn, dname, &sbuf);
3923	if (ret == 0 || ret == 1) {
3924		return ret ? True : False;
3925	}
3926
3927	return (sbuf.st_mode & S_IWOTH) ? True : False;
3928}
3929