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