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