r4016: Fix for bug found by Steve French client code (cifsfs) on
[obnox/samba/samba-obnox.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 = file_ace_list; ace_list; ace_list = ace_list->next) {
184                 if (ace_list->inherited) {
185                         uint8 type_val = (unsigned char)ace_list->owner_type;
186                         uint32 entry_val = get_entry_val(ace_list);
187
188                         SCVAL(entry_offset,0,type_val);
189                         SIVAL(entry_offset,1,entry_val);
190                         entry_offset += PAI_ENTRY_LENGTH;
191                 }
192         }
193
194         for (ace_list = dir_ace_list; ace_list; ace_list = ace_list->next) {
195                 if (ace_list->inherited) {
196                         uint8 type_val = (unsigned char)ace_list->owner_type;
197                         uint32 entry_val = get_entry_val(ace_list);
198
199                         SCVAL(entry_offset,0,type_val);
200                         SIVAL(entry_offset,1,entry_val);
201                         entry_offset += PAI_ENTRY_LENGTH;
202                 }
203         }
204
205         return pai_buf;
206 }
207
208 /************************************************************************
209  Store the user.SAMBA_PAI attribute on disk.
210 ************************************************************************/
211
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 && !no_acl_syscall_error(errno))
249                 DEBUG(1,("store_inheritance_attribute: Error %s\n", strerror(errno) ));
250 }
251
252 /************************************************************************
253  Delete the in memory inheritance info.
254 ************************************************************************/
255
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, False) : 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 (!no_acl_syscall_error(errno)) {
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 (no_acl_syscall_error(errno)) {
2412                                 *pacl_set_support = False;
2413                         }
2414
2415                         DEBUG(2,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n",
2416                                         the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
2417                                         fsp->fsp_name, strerror(errno) ));
2418                         goto done;
2419                 }
2420         } else {
2421                 if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fd, the_acl) == -1) {
2422                         /*
2423                          * Some systems allow all the above calls and only fail with no ACL support
2424                          * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
2425                          */
2426                         if (no_acl_syscall_error(errno)) {
2427                                 *pacl_set_support = False;
2428                         }
2429
2430                         DEBUG(2,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n",
2431                                         fsp->fsp_name, strerror(errno) ));
2432                         goto done;
2433                 }
2434         }
2435
2436         ret = True;
2437
2438   done:
2439
2440         if (the_acl != NULL)
2441             SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
2442
2443         return ret;
2444 }
2445
2446 /****************************************************************************
2447  Find a particular canon_ace entry.
2448 ****************************************************************************/
2449
2450 static struct canon_ace *canon_ace_entry_for(struct canon_ace *list, SMB_ACL_TAG_T type, posix_id *id)
2451 {
2452         while (list) {
2453                 if (list->type == type && ((type != SMB_ACL_USER && type != SMB_ACL_GROUP) ||
2454                                 (type == SMB_ACL_USER  && id && id->uid == list->unix_ug.uid) ||
2455                                 (type == SMB_ACL_GROUP && id && id->gid == list->unix_ug.gid)))
2456                         break;
2457                 list = list->next;
2458         }
2459         return list;
2460 }
2461
2462 /****************************************************************************
2463  
2464 ****************************************************************************/
2465
2466 SMB_ACL_T free_empty_sys_acl(connection_struct *conn, SMB_ACL_T the_acl)
2467 {
2468         SMB_ACL_ENTRY_T entry;
2469
2470         if (!the_acl)
2471                 return NULL;
2472         if (SMB_VFS_SYS_ACL_GET_ENTRY(conn, the_acl, SMB_ACL_FIRST_ENTRY, &entry) != 1) {
2473                 SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
2474                 return NULL;
2475         }
2476         return the_acl;
2477 }
2478
2479 /****************************************************************************
2480  Convert a canon_ace to a generic 3 element permission - if possible.
2481 ****************************************************************************/
2482
2483 #define MAP_PERM(p,mask,result) (((p) & (mask)) ? (result) : 0 )
2484
2485 static BOOL convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file_ace_list, mode_t *posix_perms)
2486 {
2487         int snum = SNUM(fsp->conn);
2488         size_t ace_count = count_canon_ace_list(file_ace_list);
2489         canon_ace *ace_p;
2490         canon_ace *owner_ace = NULL;
2491         canon_ace *group_ace = NULL;
2492         canon_ace *other_ace = NULL;
2493         mode_t and_bits;
2494         mode_t or_bits;
2495
2496         if (ace_count != 3) {
2497                 DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE entries for file %s to convert to \
2498 posix perms.\n", fsp->fsp_name ));
2499                 return False;
2500         }
2501
2502         for (ace_p = file_ace_list; ace_p; ace_p = ace_p->next) {
2503                 if (ace_p->owner_type == UID_ACE)
2504                         owner_ace = ace_p;
2505                 else if (ace_p->owner_type == GID_ACE)
2506                         group_ace = ace_p;
2507                 else if (ace_p->owner_type == WORLD_ACE)
2508                         other_ace = ace_p;
2509         }
2510
2511         if (!owner_ace || !group_ace || !other_ace) {
2512                 DEBUG(3,("convert_canon_ace_to_posix_perms: Can't get standard entries for file %s.\n",
2513                                 fsp->fsp_name ));
2514                 return False;
2515         }
2516
2517         *posix_perms = (mode_t)0;
2518
2519         *posix_perms |= owner_ace->perms;
2520         *posix_perms |= MAP_PERM(group_ace->perms, S_IRUSR, S_IRGRP);
2521         *posix_perms |= MAP_PERM(group_ace->perms, S_IWUSR, S_IWGRP);
2522         *posix_perms |= MAP_PERM(group_ace->perms, S_IXUSR, S_IXGRP);
2523         *posix_perms |= MAP_PERM(other_ace->perms, S_IRUSR, S_IROTH);
2524         *posix_perms |= MAP_PERM(other_ace->perms, S_IWUSR, S_IWOTH);
2525         *posix_perms |= MAP_PERM(other_ace->perms, S_IXUSR, S_IXOTH);
2526
2527         /* The owner must have at least read access. */
2528
2529         *posix_perms |= S_IRUSR;
2530         if (fsp->is_directory)
2531                 *posix_perms |= (S_IWUSR|S_IXUSR);
2532
2533         /* If requested apply the masks. */
2534
2535         /* Get the initial bits to apply. */
2536
2537         if (fsp->is_directory) {
2538                 and_bits = lp_dir_security_mask(snum);
2539                 or_bits = lp_force_dir_security_mode(snum);
2540         } else {
2541                 and_bits = lp_security_mask(snum);
2542                 or_bits = lp_force_security_mode(snum);
2543         }
2544
2545         *posix_perms = (((*posix_perms) & and_bits)|or_bits);
2546
2547         DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o to perm=0%o for file %s.\n",
2548                 (int)owner_ace->perms, (int)group_ace->perms, (int)other_ace->perms, (int)*posix_perms,
2549                 fsp->fsp_name ));
2550
2551         return True;
2552 }
2553
2554 /****************************************************************************
2555   Incoming NT ACLs on a directory can be split into a default POSIX acl (CI|OI|IO) and
2556   a normal POSIX acl. Win2k needs these split acls re-merging into one ACL
2557   with CI|OI set so it is inherited and also applies to the directory.
2558   Based on code from "Jim McDonough" <jmcd@us.ibm.com>.
2559 ****************************************************************************/
2560
2561 static size_t merge_default_aces( SEC_ACE *nt_ace_list, size_t num_aces)
2562 {
2563         size_t i, j;
2564
2565         for (i = 0; i < num_aces; i++) {
2566                 for (j = i+1; j < num_aces; j++) {
2567                         uint32 i_flags_ni = (nt_ace_list[i].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
2568                         uint32 j_flags_ni = (nt_ace_list[j].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
2569                         BOOL i_inh = (nt_ace_list[i].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
2570                         BOOL j_inh = (nt_ace_list[j].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
2571
2572                         /* We know the lower number ACE's are file entries. */
2573                         if ((nt_ace_list[i].type == nt_ace_list[j].type) &&
2574                                 (nt_ace_list[i].size == nt_ace_list[j].size) &&
2575                                 (nt_ace_list[i].info.mask == nt_ace_list[j].info.mask) &&
2576                                 sid_equal(&nt_ace_list[i].trustee, &nt_ace_list[j].trustee) &&
2577                                 (i_inh == j_inh) &&
2578                                 (i_flags_ni == 0) &&
2579                                 (j_flags_ni == (SEC_ACE_FLAG_OBJECT_INHERIT|
2580                                                   SEC_ACE_FLAG_CONTAINER_INHERIT|
2581                                                   SEC_ACE_FLAG_INHERIT_ONLY))) {
2582                                 /*
2583                                  * W2K wants to have access allowed zero access ACE's
2584                                  * at the end of the list. If the mask is zero, merge
2585                                  * the non-inherited ACE onto the inherited ACE.
2586                                  */
2587
2588                                 if (nt_ace_list[i].info.mask == 0) {
2589                                         nt_ace_list[j].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2590                                                                 (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2591                                         if (num_aces - i - 1 > 0)
2592                                                 memmove(&nt_ace_list[i], &nt_ace_list[i+1], (num_aces-i-1) *
2593                                                                 sizeof(SEC_ACE));
2594
2595                                         DEBUG(10,("merge_default_aces: Merging zero access ACE %u onto ACE %u.\n",
2596                                                 (unsigned int)i, (unsigned int)j ));
2597                                 } else {
2598                                         /*
2599                                          * These are identical except for the flags.
2600                                          * Merge the inherited ACE onto the non-inherited ACE.
2601                                          */
2602
2603                                         nt_ace_list[i].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2604                                                                 (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2605                                         if (num_aces - j - 1 > 0)
2606                                                 memmove(&nt_ace_list[j], &nt_ace_list[j+1], (num_aces-j-1) *
2607                                                                 sizeof(SEC_ACE));
2608
2609                                         DEBUG(10,("merge_default_aces: Merging ACE %u onto ACE %u.\n",
2610                                                 (unsigned int)j, (unsigned int)i ));
2611                                 }
2612                                 num_aces--;
2613                                 break;
2614                         }
2615                 }
2616         }
2617
2618         return num_aces;
2619 }
2620 /****************************************************************************
2621  Reply to query a security descriptor from an fsp. If it succeeds it allocates
2622  the space for the return elements and returns the size needed to return the
2623  security descriptor. This should be the only external function needed for
2624  the UNIX style get ACL.
2625 ****************************************************************************/
2626
2627 size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc)
2628 {
2629         extern DOM_SID global_sid_Builtin_Administrators;
2630         extern DOM_SID global_sid_Builtin_Users;
2631         extern DOM_SID global_sid_Creator_Owner;
2632         extern DOM_SID global_sid_Creator_Group;
2633         connection_struct *conn = fsp->conn;
2634         SMB_STRUCT_STAT sbuf;
2635         SEC_ACE *nt_ace_list = NULL;
2636         DOM_SID owner_sid;
2637         DOM_SID group_sid;
2638         size_t sd_size = 0;
2639         SEC_ACL *psa = NULL;
2640         size_t num_acls = 0;
2641         size_t num_def_acls = 0;
2642         size_t num_aces = 0;
2643         SMB_ACL_T posix_acl = NULL;
2644         SMB_ACL_T def_acl = NULL;
2645         canon_ace *file_ace = NULL;
2646         canon_ace *dir_ace = NULL;
2647         size_t num_profile_acls = 0;
2648         struct pai_val *pal = NULL;
2649         SEC_DESC *psd = NULL;
2650
2651         *ppdesc = NULL;
2652
2653         DEBUG(10,("get_nt_acl: called for file %s\n", fsp->fsp_name ));
2654
2655         if(fsp->is_directory || fsp->fd == -1) {
2656
2657                 /* Get the stat struct for the owner info. */
2658                 if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) {
2659                         return 0;
2660                 }
2661                 /*
2662                  * Get the ACL from the path.
2663                  */
2664
2665                 posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_ACCESS);
2666
2667                 /*
2668                  * If it's a directory get the default POSIX ACL.
2669                  */
2670
2671                 if(fsp->is_directory) {
2672                         def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_DEFAULT);
2673                         def_acl = free_empty_sys_acl(conn, def_acl);
2674                 }
2675
2676         } else {
2677
2678                 /* Get the stat struct for the owner info. */
2679                 if(SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0) {
2680                         return 0;
2681                 }
2682                 /*
2683                  * Get the ACL from the fd.
2684                  */
2685                 posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fd);
2686         }
2687
2688         DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n",
2689                         posix_acl ? "present" :  "absent",
2690                         def_acl ? "present" :  "absent" ));
2691
2692         pal = load_inherited_info(fsp);
2693
2694         /*
2695          * Get the owner, group and world SIDs.
2696          */
2697
2698         if (lp_profile_acls(SNUM(fsp->conn))) {
2699                 /* For WXP SP1 the owner must be administrators. */
2700                 sid_copy(&owner_sid, &global_sid_Builtin_Administrators);
2701                 sid_copy(&group_sid, &global_sid_Builtin_Users);
2702                 num_profile_acls = 2;
2703         } else {
2704                 create_file_sids(&sbuf, &owner_sid, &group_sid);
2705         }
2706
2707         if ((security_info & DACL_SECURITY_INFORMATION) && !(security_info & PROTECTED_DACL_SECURITY_INFORMATION)) {
2708
2709                 /*
2710                  * In the optimum case Creator Owner and Creator Group would be used for
2711                  * the ACL_USER_OBJ and ACL_GROUP_OBJ entries, respectively, but this
2712                  * would lead to usability problems under Windows: The Creator entries
2713                  * are only available in browse lists of directories and not for files;
2714                  * additionally the identity of the owning group couldn't be determined.
2715                  * We therefore use those identities only for Default ACLs. 
2716                  */
2717
2718                 /* Create the canon_ace lists. */
2719                 file_ace = canonicalise_acl( fsp, posix_acl, &sbuf, &owner_sid, &group_sid, pal, SMB_ACL_TYPE_ACCESS );
2720
2721                 /* We must have *some* ACLS. */
2722         
2723                 if (count_canon_ace_list(file_ace) == 0) {
2724                         DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", fsp->fsp_name ));
2725                         return 0;
2726                 }
2727
2728                 if (fsp->is_directory && def_acl) {
2729                         dir_ace = canonicalise_acl(fsp, def_acl, &sbuf,
2730                                         &global_sid_Creator_Owner,
2731                                         &global_sid_Creator_Group, pal, SMB_ACL_TYPE_DEFAULT );
2732                 }
2733
2734                 /*
2735                  * Create the NT ACE list from the canonical ace lists.
2736                  */
2737
2738                 {
2739                         canon_ace *ace;
2740                         int nt_acl_type;
2741                         int i;
2742
2743                         if (nt4_compatible_acls() && dir_ace) {
2744                                 /*
2745                                  * NT 4 chokes if an ACL contains an INHERIT_ONLY entry
2746                                  * but no non-INHERIT_ONLY entry for one SID. So we only
2747                                  * remove entries from the Access ACL if the
2748                                  * corresponding Default ACL entries have also been
2749                                  * removed. ACEs for CREATOR-OWNER and CREATOR-GROUP
2750                                  * are exceptions. We can do nothing
2751                                  * intelligent if the Default ACL contains entries that
2752                                  * are not also contained in the Access ACL, so this
2753                                  * case will still fail under NT 4.
2754                                  */
2755
2756                                 ace = canon_ace_entry_for(dir_ace, SMB_ACL_OTHER, NULL);
2757                                 if (ace && !ace->perms) {
2758                                         DLIST_REMOVE(dir_ace, ace);
2759                                         SAFE_FREE(ace);
2760
2761                                         ace = canon_ace_entry_for(file_ace, SMB_ACL_OTHER, NULL);
2762                                         if (ace && !ace->perms) {
2763                                                 DLIST_REMOVE(file_ace, ace);
2764                                                 SAFE_FREE(ace);
2765                                         }
2766                                 }
2767
2768                                 /*
2769                                  * WinNT doesn't usually have Creator Group
2770                                  * in browse lists, so we send this entry to
2771                                  * WinNT even if it contains no relevant
2772                                  * permissions. Once we can add
2773                                  * Creator Group to browse lists we can
2774                                  * re-enable this.
2775                                  */
2776
2777 #if 0
2778                                 ace = canon_ace_entry_for(dir_ace, SMB_ACL_GROUP_OBJ, NULL);
2779                                 if (ace && !ace->perms) {
2780                                         DLIST_REMOVE(dir_ace, ace);
2781                                         SAFE_FREE(ace);
2782                                 }
2783 #endif
2784
2785                                 ace = canon_ace_entry_for(file_ace, SMB_ACL_GROUP_OBJ, NULL);
2786                                 if (ace && !ace->perms) {
2787                                         DLIST_REMOVE(file_ace, ace);
2788                                         SAFE_FREE(ace);
2789                                 }
2790                         }
2791
2792                         num_acls = count_canon_ace_list(file_ace);
2793                         num_def_acls = count_canon_ace_list(dir_ace);
2794
2795                         /* Allocate the ace list. */
2796                         if ((nt_ace_list = (SEC_ACE *)malloc((num_acls + num_profile_acls + num_def_acls)* sizeof(SEC_ACE))) == NULL) {
2797                                 DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
2798                                 goto done;
2799                         }
2800
2801                         memset(nt_ace_list, '\0', (num_acls + num_def_acls) * sizeof(SEC_ACE) );
2802                                                                                                         
2803                         /*
2804                          * Create the NT ACE list from the canonical ace lists.
2805                          */
2806         
2807                         ace = file_ace;
2808
2809                         for (i = 0; i < num_acls; i++, ace = ace->next) {
2810                                 SEC_ACCESS acc;
2811
2812                                 acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
2813                                 init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc, ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2814                         }
2815
2816                         /* The User must have access to a profile share - even if we can't map the SID. */
2817                         if (lp_profile_acls(SNUM(fsp->conn))) {
2818                                 SEC_ACCESS acc;
2819
2820                                 init_sec_access(&acc,FILE_GENERIC_ALL);
2821                                 init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED,
2822                                                 acc, 0);
2823                         }
2824
2825                         ace = dir_ace;
2826
2827                         for (i = 0; i < num_def_acls; i++, ace = ace->next) {
2828                                 SEC_ACCESS acc;
2829         
2830                                 acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
2831                                 init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc,
2832                                                 SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2833                                                 SEC_ACE_FLAG_INHERIT_ONLY|
2834                                                 (ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 0));
2835                         }
2836
2837                         /* The User must have access to a profile share - even if we can't map the SID. */
2838                         if (lp_profile_acls(SNUM(fsp->conn))) {
2839                                 SEC_ACCESS acc;
2840                         
2841                                 init_sec_access(&acc,FILE_GENERIC_ALL);
2842                                 init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, acc,
2843                                                 SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2844                                                 SEC_ACE_FLAG_INHERIT_ONLY|0);
2845                         }
2846
2847                         /*
2848                          * Merge POSIX default ACLs and normal ACLs into one NT ACE.
2849                          * Win2K needs this to get the inheritance correct when replacing ACLs
2850                          * on a directory tree. Based on work by Jim @ IBM.
2851                          */
2852
2853                         num_aces = merge_default_aces(nt_ace_list, num_aces);
2854
2855                 }
2856
2857                 if (num_aces) {
2858                         if((psa = make_sec_acl( main_loop_talloc_get(), NT4_ACL_REVISION, num_aces, nt_ace_list)) == NULL) {
2859                                 DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
2860                                 goto done;
2861                         }
2862                 }
2863         } /* security_info & DACL_SECURITY_INFORMATION */
2864
2865         psd = make_standard_sec_desc( main_loop_talloc_get(),
2866                         (security_info & OWNER_SECURITY_INFORMATION) ? &owner_sid : NULL,
2867                         (security_info & GROUP_SECURITY_INFORMATION) ? &group_sid : NULL,
2868                         psa,
2869                         &sd_size);
2870
2871         if(!psd) {
2872                 DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
2873                 sd_size = 0;
2874         } else {
2875                 /*
2876                  * Windows 2000: The DACL_PROTECTED flag in the security
2877                  * descriptor marks the ACL as non-inheriting, i.e., no
2878                  * ACEs from higher level directories propagate to this
2879                  * ACL. In the POSIX ACL model permissions are only
2880                  * inherited at file create time, so ACLs never contain
2881                  * any ACEs that are inherited dynamically. The DACL_PROTECTED
2882                  * flag doesn't seem to bother Windows NT.
2883                  * Always set this if map acl inherit is turned off.
2884                  */
2885                 if (get_protected_flag(pal) || !lp_map_acl_inherit(SNUM(conn))) {
2886                         psd->type |= SE_DESC_DACL_PROTECTED;
2887                 }
2888         }
2889
2890         if (psd->dacl)
2891                 dacl_sort_into_canonical_order(psd->dacl->ace, (unsigned int)psd->dacl->num_aces);
2892
2893         *ppdesc = psd;
2894
2895  done:
2896
2897         if (posix_acl)
2898                 SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
2899         if (def_acl)
2900                 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
2901         free_canon_ace_list(file_ace);
2902         free_canon_ace_list(dir_ace);
2903         free_inherited_info(pal);
2904         SAFE_FREE(nt_ace_list);
2905
2906         return sd_size;
2907 }
2908
2909 /****************************************************************************
2910  Try to chown a file. We will be able to chown it under the following conditions.
2911
2912   1) If we have root privileges, then it will just work.
2913   2) If we have write permission to the file and dos_filemodes is set
2914      then allow chown to the currently authenticated user.
2915 ****************************************************************************/
2916
2917 static int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid)
2918 {
2919         int ret;
2920         extern struct current_user current_user;
2921         files_struct *fsp;
2922         SMB_STRUCT_STAT st;
2923
2924         /* try the direct way first */
2925         ret = SMB_VFS_CHOWN(conn, fname, uid, gid);
2926         if (ret == 0)
2927                 return 0;
2928
2929         if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
2930                 return -1;
2931
2932         if (SMB_VFS_STAT(conn,fname,&st))
2933                 return -1;
2934
2935         fsp = open_file_fchmod(conn,fname,&st);
2936         if (!fsp)
2937                 return -1;
2938
2939         /* only allow chown to the current user. This is more secure,
2940            and also copes with the case where the SID in a take ownership ACL is
2941            a local SID on the users workstation 
2942         */
2943         uid = current_user.uid;
2944
2945         become_root();
2946         /* Keep the current file gid the same. */
2947         ret = SMB_VFS_FCHOWN(fsp, fsp->fd, uid, (gid_t)-1);
2948         unbecome_root();
2949
2950         close_file_fchmod(fsp);
2951
2952         return ret;
2953 }
2954
2955 /****************************************************************************
2956  Reply to set a security descriptor on an fsp. security_info_sent is the
2957  description of the following NT ACL.
2958  This should be the only external function needed for the UNIX style set ACL.
2959 ****************************************************************************/
2960
2961 BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
2962 {
2963         connection_struct *conn = fsp->conn;
2964         uid_t user = (uid_t)-1;
2965         gid_t grp = (gid_t)-1;
2966         SMB_STRUCT_STAT sbuf;  
2967         DOM_SID file_owner_sid;
2968         DOM_SID file_grp_sid;
2969         canon_ace *file_ace_list = NULL;
2970         canon_ace *dir_ace_list = NULL;
2971         BOOL acl_perms = False;
2972         mode_t orig_mode = (mode_t)0;
2973         uid_t orig_uid;
2974         gid_t orig_gid;
2975         BOOL need_chown = False;
2976         extern struct current_user current_user;
2977
2978         DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name ));
2979
2980         if (!CAN_WRITE(conn)) {
2981                 DEBUG(10,("set acl rejected on read-only share\n"));
2982                 return False;
2983         }
2984
2985         /*
2986          * Get the current state of the file.
2987          */
2988
2989         if(fsp->is_directory || fsp->fd == -1) {
2990                 if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0)
2991                         return False;
2992         } else {
2993                 if(SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0)
2994                         return False;
2995         }
2996
2997         /* Save the original elements we check against. */
2998         orig_mode = sbuf.st_mode;
2999         orig_uid = sbuf.st_uid;
3000         orig_gid = sbuf.st_gid;
3001
3002         /*
3003          * Unpack the user/group/world id's.
3004          */
3005
3006         if (!unpack_nt_owners( SNUM(conn), &sbuf, &user, &grp, security_info_sent, psd))
3007                 return False;
3008
3009         /*
3010          * Do we need to chown ?
3011          */
3012
3013         if (((user != (uid_t)-1) && (orig_uid != user)) || (( grp != (gid_t)-1) && (orig_gid != grp)))
3014                 need_chown = True;
3015
3016         /*
3017          * Chown before setting ACL only if we don't change the user, or
3018          * if we change to the current user, but not if we want to give away
3019          * the file.
3020          */
3021
3022         if (need_chown && (user == (uid_t)-1 || user == current_user.uid)) {
3023
3024                 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
3025                                 fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
3026
3027                 if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
3028                         DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
3029                                 fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
3030                         return False;
3031                 }
3032
3033                 /*
3034                  * Recheck the current state of the file, which may have changed.
3035                  * (suid/sgid bits, for instance)
3036                  */
3037
3038                 if(fsp->is_directory) {
3039                         if(SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf) != 0) {
3040                                 return False;
3041                         }
3042                 } else {
3043
3044                         int ret;
3045     
3046                         if(fsp->fd == -1)
3047                                 ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf);
3048                         else
3049                                 ret = SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf);
3050   
3051                         if(ret != 0)
3052                                 return False;
3053                 }
3054
3055                 /* Save the original elements we check against. */
3056                 orig_mode = sbuf.st_mode;
3057                 orig_uid = sbuf.st_uid;
3058                 orig_gid = sbuf.st_gid;
3059
3060                 /* We did it, don't try again */
3061                 need_chown = False;
3062         }
3063
3064         create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid);
3065
3066         acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid,
3067                                                                         &file_ace_list, &dir_ace_list, security_info_sent, psd);
3068
3069         /* Ignore W2K traverse DACL set. */
3070         if (file_ace_list || dir_ace_list) {
3071
3072                 if (!acl_perms) {
3073                         DEBUG(3,("set_nt_acl: cannot set permissions\n"));
3074                         free_canon_ace_list(file_ace_list);
3075                         free_canon_ace_list(dir_ace_list); 
3076                         return False;
3077                 }
3078
3079                 /*
3080                  * Only change security if we got a DACL.
3081                  */
3082
3083                 if((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl != NULL)) {
3084
3085                         BOOL acl_set_support = False;
3086                         BOOL ret = False;
3087
3088                         /*
3089                          * Try using the POSIX ACL set first. Fall back to chmod if
3090                          * we have no ACL support on this filesystem.
3091                          */
3092
3093                         if (acl_perms && file_ace_list) {
3094                                 ret = set_canon_ace_list(fsp, file_ace_list, False, &acl_set_support);
3095                                 if (acl_set_support && ret == False) {
3096                                         DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) ));
3097                                         free_canon_ace_list(file_ace_list);
3098                                         free_canon_ace_list(dir_ace_list); 
3099                                         return False;
3100                                 }
3101                         }
3102
3103                         if (acl_perms && acl_set_support && fsp->is_directory) {
3104                                 if (dir_ace_list) {
3105                                         if (!set_canon_ace_list(fsp, dir_ace_list, True, &acl_set_support)) {
3106                                                 DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) ));
3107                                                 free_canon_ace_list(file_ace_list);
3108                                                 free_canon_ace_list(dir_ace_list); 
3109                                                 return False;
3110                                         }
3111                                 } else {
3112
3113                                         /*
3114                                          * No default ACL - delete one if it exists.
3115                                          */
3116
3117                                         if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name) == -1) {
3118                                                 DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno)));
3119                                                 free_canon_ace_list(file_ace_list);
3120                                                 free_canon_ace_list(dir_ace_list);
3121                                                 return False;
3122                                         }
3123                                 }
3124                         }
3125
3126                         if (acl_set_support)
3127                                 store_inheritance_attributes(fsp, file_ace_list, dir_ace_list,
3128                                                 (psd->type & SE_DESC_DACL_PROTECTED) ? True : False);
3129
3130                         /*
3131                          * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
3132                          */
3133
3134                         if(!acl_set_support && acl_perms) {
3135                                 mode_t posix_perms;
3136
3137                                 if (!convert_canon_ace_to_posix_perms( fsp, file_ace_list, &posix_perms)) {
3138                                         free_canon_ace_list(file_ace_list);
3139                                         free_canon_ace_list(dir_ace_list);
3140                                         DEBUG(3,("set_nt_acl: failed to convert file acl to posix permissions for file %s.\n",
3141                                                 fsp->fsp_name ));
3142                                         return False;
3143                                 }
3144
3145                                 if (orig_mode != posix_perms) {
3146
3147                                         DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
3148                                                 fsp->fsp_name, (unsigned int)posix_perms ));
3149
3150                                         if(SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms) == -1) {
3151                                                 DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n",
3152                                                                 fsp->fsp_name, (unsigned int)posix_perms, strerror(errno) ));
3153                                                 free_canon_ace_list(file_ace_list);
3154                                                 free_canon_ace_list(dir_ace_list);
3155                                                 return False;
3156                                         }
3157                                 }
3158                         }
3159                 }
3160
3161                 free_canon_ace_list(file_ace_list);
3162                 free_canon_ace_list(dir_ace_list); 
3163         }
3164
3165         /* Any chown pending? */
3166         if (need_chown) {
3167
3168                 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
3169                         fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
3170
3171                 if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
3172                         DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
3173                                 fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
3174                         return False;
3175                 }
3176         }
3177
3178         return True;
3179 }
3180
3181 /****************************************************************************
3182  Get the actual group bits stored on a file with an ACL. Has no effect if
3183  the file has no ACL. Needed in dosmode code where the stat() will return
3184  the mask bits, not the real group bits, for a file with an ACL.
3185 ****************************************************************************/
3186
3187 int get_acl_group_bits( connection_struct *conn, const char *fname, mode_t *mode )
3188 {
3189         int entry_id = SMB_ACL_FIRST_ENTRY;
3190         SMB_ACL_ENTRY_T entry;
3191         SMB_ACL_T posix_acl;
3192         int result = -1;
3193
3194         posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS);
3195         if (posix_acl == (SMB_ACL_T)NULL)
3196                 return -1;
3197
3198         while (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
3199                 SMB_ACL_TAG_T tagtype;
3200                 SMB_ACL_PERMSET_T permset;
3201
3202                 /* get_next... */
3203                 if (entry_id == SMB_ACL_FIRST_ENTRY)
3204                         entry_id = SMB_ACL_NEXT_ENTRY;
3205
3206                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) ==-1)
3207                         break;
3208
3209                 if (tagtype == SMB_ACL_GROUP_OBJ) {
3210                         if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
3211                                 break;
3212                         } else {
3213                                 *mode &= ~(S_IRGRP|S_IWGRP|S_IXGRP);
3214                                 *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRGRP : 0);
3215                                 *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWGRP : 0);
3216                                 *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXGRP : 0);
3217                                 result = 0;
3218                                 break;
3219                         }
3220                 }
3221         }
3222         SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
3223         return result;
3224 }
3225
3226 /****************************************************************************
3227  Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3228  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3229 ****************************************************************************/
3230
3231 static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mode_t mode)
3232 {
3233         int entry_id = SMB_ACL_FIRST_ENTRY;
3234         SMB_ACL_ENTRY_T entry;
3235         int num_entries = 0;
3236
3237         while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
3238                 SMB_ACL_TAG_T tagtype;
3239                 SMB_ACL_PERMSET_T permset;
3240                 mode_t perms;
3241
3242                 /* get_next... */
3243                 if (entry_id == SMB_ACL_FIRST_ENTRY)
3244                         entry_id = SMB_ACL_NEXT_ENTRY;
3245
3246                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
3247                         return -1;
3248
3249                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
3250                         return -1;
3251
3252                 num_entries++;
3253
3254                 switch(tagtype) {
3255                         case SMB_ACL_USER_OBJ:
3256                                 perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
3257                                 break;
3258                         case SMB_ACL_GROUP_OBJ:
3259                                 perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
3260                                 break;
3261                         case SMB_ACL_MASK:
3262                                 /*
3263                                  * FIXME: The ACL_MASK entry permissions should really be set to
3264                                  * the union of the permissions of all ACL_USER,
3265                                  * ACL_GROUP_OBJ, and ACL_GROUP entries. That's what
3266                                  * acl_calc_mask() does, but Samba ACLs doesn't provide it.
3267                                  */
3268                                 perms = S_IRUSR|S_IWUSR|S_IXUSR;
3269                                 break;
3270                         case SMB_ACL_OTHER:
3271                                 perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
3272                                 break;
3273                         default:
3274                                 continue;
3275                 }
3276
3277                 if (map_acl_perms_to_permset(conn, perms, &permset) == -1)
3278                         return -1;
3279
3280                 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, entry, permset) == -1)
3281                         return -1;
3282         }
3283
3284         /*
3285          * If this is a simple 3 element ACL or no elements then it's a standard
3286          * UNIX permission set. Just use chmod...       
3287          */
3288
3289         if ((num_entries == 3) || (num_entries == 0))
3290                 return -1;
3291
3292         return 0;
3293 }
3294
3295 /****************************************************************************
3296  Get the access ACL of FROM, do a chmod by setting the ACL USER_OBJ,
3297  GROUP_OBJ and OTHER bits in an ACL and set the mask to rwx. Set the
3298  resulting ACL on TO.  Note that name is in UNIX character set.
3299 ****************************************************************************/
3300
3301 static int copy_access_acl(connection_struct *conn, const char *from, const char *to, mode_t mode)
3302 {
3303         SMB_ACL_T posix_acl = NULL;
3304         int ret = -1;
3305
3306         if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, from, SMB_ACL_TYPE_ACCESS)) == NULL)
3307                 return -1;
3308
3309         if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
3310                 goto done;
3311
3312         ret = SMB_VFS_SYS_ACL_SET_FILE(conn, to, SMB_ACL_TYPE_ACCESS, posix_acl);
3313
3314  done:
3315
3316         SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
3317         return ret;
3318 }
3319
3320 /****************************************************************************
3321  Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3322  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3323  Note that name is in UNIX character set.
3324 ****************************************************************************/
3325
3326 int chmod_acl(connection_struct *conn, const char *name, mode_t mode)
3327 {
3328         return copy_access_acl(conn, name, name, mode);
3329 }
3330
3331 /****************************************************************************
3332  If "inherit permissions" is set and the parent directory has no default
3333  ACL but it does have an Access ACL, inherit this Access ACL to file name.
3334 ****************************************************************************/
3335
3336 int inherit_access_acl(connection_struct *conn, const char *name, mode_t mode)
3337 {
3338         pstring dirname;
3339         pstrcpy(dirname, parent_dirname(name));
3340
3341         if (!lp_inherit_perms(SNUM(conn)) || directory_has_default_acl(conn, dirname))
3342                 return 0;
3343
3344         return copy_access_acl(conn, dirname, name, mode);
3345 }
3346
3347 /****************************************************************************
3348  Do an fchmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3349  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3350 ****************************************************************************/
3351
3352 int fchmod_acl(files_struct *fsp, int fd, mode_t mode)
3353 {
3354         connection_struct *conn = fsp->conn;
3355         SMB_ACL_T posix_acl = NULL;
3356         int ret = -1;
3357
3358         if ((posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fd)) == NULL)
3359                 return -1;
3360
3361         if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
3362                 goto done;
3363
3364         ret = SMB_VFS_SYS_ACL_SET_FD(fsp, fd, posix_acl);
3365
3366   done:
3367
3368         SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
3369         return ret;
3370 }
3371
3372 /****************************************************************************
3373  Check for an existing default POSIX ACL on a directory.
3374 ****************************************************************************/
3375
3376 BOOL directory_has_default_acl(connection_struct *conn, const char *fname)
3377 {
3378         SMB_ACL_T def_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_DEFAULT);
3379         BOOL has_acl = False;
3380         SMB_ACL_ENTRY_T entry;
3381
3382         if (def_acl != NULL && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, def_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1)) {
3383                 has_acl = True;
3384         }
3385
3386         if (def_acl) {
3387                 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
3388         }
3389         return has_acl;
3390 }
3391
3392 /****************************************************************************
3393  Map from wire type to permset.
3394 ****************************************************************************/
3395
3396 static BOOL unix_ex_wire_to_permset(connection_struct *conn, unsigned char wire_perm, SMB_ACL_PERMSET_T *p_permset)
3397 {
3398         if (wire_perm & ~(SMB_POSIX_ACL_READ|SMB_POSIX_ACL_WRITE|SMB_POSIX_ACL_EXECUTE)) {
3399                 return False;
3400         }
3401
3402         if (SMB_VFS_SYS_ACL_CLEAR_PERMS(conn, *p_permset) ==  -1) {
3403                 return False;
3404         }
3405
3406         if (wire_perm & SMB_POSIX_ACL_READ) {
3407                 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_READ) == -1) {
3408                         return False;
3409                 }
3410         }
3411         if (wire_perm & SMB_POSIX_ACL_WRITE) {
3412                 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_WRITE) == -1) {
3413                         return False;
3414                 }
3415         }
3416         if (wire_perm & SMB_POSIX_ACL_EXECUTE) {
3417                 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_EXECUTE) == -1) {
3418                         return False;
3419                 }
3420         }
3421         return True;
3422 }
3423
3424 /****************************************************************************
3425  Map from wire type to tagtype.
3426 ****************************************************************************/
3427
3428 static BOOL unix_ex_wire_to_tagtype(unsigned char wire_tt, SMB_ACL_TAG_T *p_tt)
3429 {
3430         switch (wire_tt) {
3431                 case SMB_POSIX_ACL_USER_OBJ:
3432                         *p_tt = SMB_ACL_USER_OBJ;
3433                         break;
3434                 case SMB_POSIX_ACL_USER:
3435                         *p_tt = SMB_ACL_USER;
3436                         break;
3437                 case SMB_POSIX_ACL_GROUP_OBJ:
3438                         *p_tt = SMB_ACL_GROUP_OBJ;
3439                         break;
3440                 case SMB_POSIX_ACL_GROUP:
3441                         *p_tt = SMB_ACL_GROUP;
3442                         break;
3443                 case SMB_POSIX_ACL_MASK:
3444                         *p_tt = SMB_ACL_MASK;
3445                         break;
3446                 case SMB_POSIX_ACL_OTHER:
3447                         *p_tt = SMB_ACL_OTHER;
3448                         break;
3449                 default:
3450                         return False;
3451         }
3452         return True;
3453 }
3454
3455 /****************************************************************************
3456  Create a new POSIX acl from wire permissions.
3457  FIXME ! How does the share mask/mode fit into this.... ?
3458 ****************************************************************************/
3459
3460 static SMB_ACL_T create_posix_acl_from_wire(connection_struct *conn, uint16 num_acls, const char *pdata)
3461 {
3462         unsigned int i;
3463         SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, num_acls);
3464
3465         if (the_acl == NULL) {
3466                 return NULL;
3467         }
3468
3469         for (i = 0; i < num_acls; i++) {
3470                 SMB_ACL_ENTRY_T the_entry;
3471                 SMB_ACL_PERMSET_T the_permset;
3472                 SMB_ACL_TAG_T tag_type;
3473
3474                 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) {
3475                         DEBUG(0,("create_posix_acl_from_wire: Failed to create entry %u. (%s)\n",
3476                                 i, strerror(errno) ));
3477                         goto fail;
3478                 }
3479
3480                 if (!unix_ex_wire_to_tagtype(CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)), &tag_type)) {
3481                         DEBUG(0,("create_posix_acl_from_wire: invalid wire tagtype %u on entry %u.\n",
3482                                 CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)), i ));
3483                         goto fail;
3484                 }
3485
3486                 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, tag_type) == -1) {
3487                         DEBUG(0,("create_posix_acl_from_wire: Failed to set tagtype on entry %u. (%s)\n",
3488                                 i, strerror(errno) ));
3489                         goto fail;
3490                 }
3491
3492                 /* Get the permset pointer from the new ACL entry. */
3493                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) {
3494                         DEBUG(0,("create_posix_acl_from_wire: Failed to get permset on entry %u. (%s)\n",
3495                                 i, strerror(errno) ));
3496                         goto fail;
3497                 }
3498
3499                 /* Map from wire to permissions. */
3500                 if (!unix_ex_wire_to_permset(conn, CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+1), &the_permset)) {
3501                         DEBUG(0,("create_posix_acl_from_wire: invalid permset %u on entry %u.\n",
3502                                 CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE) + 1), i ));
3503                         goto fail;
3504                 }
3505
3506                 /* Now apply to the new ACL entry. */
3507                 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) {
3508                         DEBUG(0,("create_posix_acl_from_wire: Failed to add permset on entry %u. (%s)\n",
3509                                 i, strerror(errno) ));
3510                         goto fail;
3511                 }
3512
3513                 if (tag_type == SMB_ACL_USER) {
3514                         uint32 uidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3515                         uid_t uid = (uid_t)uidval;
3516                         if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&uid) == -1) {
3517                                 DEBUG(0,("create_posix_acl_from_wire: Failed to set uid %u on entry %u. (%s)\n",
3518                                         (unsigned int)uid, i, strerror(errno) ));
3519                                 goto fail;
3520                         }
3521                 }
3522
3523                 if (tag_type == SMB_ACL_GROUP) {
3524                         uint32 gidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3525                         gid_t gid = (uid_t)gidval;
3526                         if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&gid) == -1) {
3527                                 DEBUG(0,("create_posix_acl_from_wire: Failed to set gid %u on entry %u. (%s)\n",
3528                                         (unsigned int)gid, i, strerror(errno) ));
3529                                 goto fail;
3530                         }
3531                 }
3532         }
3533
3534         return the_acl;
3535
3536  fail:
3537
3538         if (the_acl != NULL) {
3539                 SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
3540         }
3541         return NULL;
3542 }
3543
3544 /****************************************************************************
3545  Calls from UNIX extensions - Default POSIX ACL set.
3546  If num_def_acls == 0 and not a directory just return. If it is a directory
3547  and num_def_acls == 0 then remove the default acl. Else set the default acl
3548  on the directory.
3549 ****************************************************************************/
3550
3551 BOOL set_unix_posix_default_acl(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf,
3552                                 uint16 num_def_acls, const char *pdata)
3553 {
3554         SMB_ACL_T def_acl = NULL;
3555
3556         if (num_def_acls && !S_ISDIR(psbuf->st_mode)) {
3557                 DEBUG(5,("set_unix_posix_default_acl: Can't set default ACL on non-directory file %s\n", fname ));
3558                 errno = EISDIR;
3559                 return False;
3560         }
3561
3562         if (!num_def_acls) {
3563                 /* Remove the default ACL. */
3564                 if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fname) == -1) {
3565                         DEBUG(5,("set_unix_posix_default_acl: acl_delete_def_file failed on directory %s (%s)\n",
3566                                 fname, strerror(errno) ));
3567                         return False;
3568                 }
3569                 return True;
3570         }
3571
3572         if ((def_acl = create_posix_acl_from_wire(conn, num_def_acls, pdata)) == NULL) {
3573                 return False;
3574         }
3575
3576         if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_DEFAULT, def_acl) == -1) {
3577                 DEBUG(5,("set_unix_posix_default_acl: acl_set_file failed on directory %s (%s)\n",
3578                         fname, strerror(errno) ));
3579                 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
3580                 return False;
3581         }
3582
3583         DEBUG(10,("set_unix_posix_default_acl: set default acl for file %s\n", fname ));
3584         SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
3585         return True;
3586 }
3587
3588 /****************************************************************************
3589  Remove an ACL from a file. As we don't have acl_delete_entry() available
3590  we must read the current acl and copy all entries except MASK, USER and GROUP
3591  to a new acl, then set that. This (at least on Linux) causes any ACL to be
3592  removed.
3593  FIXME ! How does the share mask/mode fit into this.... ?
3594 ****************************************************************************/
3595
3596 static BOOL remove_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname)
3597 {
3598         SMB_ACL_T file_acl = NULL;
3599         int entry_id = SMB_ACL_FIRST_ENTRY;
3600         SMB_ACL_ENTRY_T entry;
3601         BOOL ret = False;
3602         /* Create a new ACL with only 3 entries, u/g/w. */
3603         SMB_ACL_T new_file_acl = SMB_VFS_SYS_ACL_INIT(conn, 3);
3604         SMB_ACL_ENTRY_T user_ent = NULL;
3605         SMB_ACL_ENTRY_T group_ent = NULL;
3606         SMB_ACL_ENTRY_T other_ent = NULL;
3607
3608         if (new_file_acl == NULL) {
3609                 DEBUG(5,("remove_posix_acl: failed to init new ACL with 3 entries for file %s.\n", fname));
3610                 return False;
3611         }
3612
3613         /* Now create the u/g/w entries. */
3614         if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &user_ent) == -1) {
3615                 DEBUG(5,("remove_posix_acl: Failed to create user entry for file %s. (%s)\n",
3616                         fname, strerror(errno) ));
3617                 goto done;
3618         }
3619         if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, user_ent, SMB_ACL_USER_OBJ) == -1) {
3620                 DEBUG(5,("remove_posix_acl: Failed to set user entry for file %s. (%s)\n",
3621                         fname, strerror(errno) ));
3622                 goto done;
3623         }
3624
3625         if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &group_ent) == -1) {
3626                 DEBUG(5,("remove_posix_acl: Failed to create group entry for file %s. (%s)\n",
3627                         fname, strerror(errno) ));
3628                 goto done;
3629         }
3630         if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, group_ent, SMB_ACL_GROUP_OBJ) == -1) {
3631                 DEBUG(5,("remove_posix_acl: Failed to set group entry for file %s. (%s)\n",
3632                         fname, strerror(errno) ));
3633                 goto done;
3634         }
3635
3636         if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &other_ent) == -1) {
3637                 DEBUG(5,("remove_posix_acl: Failed to create other entry for file %s. (%s)\n",
3638                         fname, strerror(errno) ));
3639                 goto done;
3640         }
3641         if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, other_ent, SMB_ACL_OTHER) == -1) {
3642                 DEBUG(5,("remove_posix_acl: Failed to set other entry for file %s. (%s)\n",
3643                         fname, strerror(errno) ));
3644                 goto done;
3645         }
3646
3647         /* Get the current file ACL. */
3648         if (fsp && fsp->fd != -1) {
3649                 file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fd);
3650         } else {
3651                 file_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_ACCESS);
3652         }
3653
3654         if (file_acl == NULL) {
3655                 /* This is only returned if an error occurred. Even for a file with
3656                    no acl a u/g/w acl should be returned. */
3657                 DEBUG(5,("remove_posix_acl: failed to get ACL from file %s (%s).\n",
3658                         fname, strerror(errno) ));
3659                 goto done;
3660         }
3661
3662         while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, file_acl, entry_id, &entry) == 1) {
3663                 SMB_ACL_TAG_T tagtype;
3664                 SMB_ACL_PERMSET_T permset;
3665
3666                 /* get_next... */
3667                 if (entry_id == SMB_ACL_FIRST_ENTRY)
3668                         entry_id = SMB_ACL_NEXT_ENTRY;
3669
3670                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
3671                         DEBUG(5,("remove_posix_acl: failed to get tagtype from ACL on file %s (%s).\n",
3672                                 fname, strerror(errno) ));
3673                         goto done;
3674                 }
3675
3676                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
3677                         DEBUG(5,("remove_posix_acl: failed to get permset from ACL on file %s (%s).\n",
3678                                 fname, strerror(errno) ));
3679                         goto done;
3680                 }
3681
3682                 if (tagtype == SMB_ACL_USER_OBJ) {
3683                         if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, user_ent, permset) == -1) {
3684                                 DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
3685                                         fname, strerror(errno) ));
3686                         }
3687                 } else if (tagtype == SMB_ACL_GROUP_OBJ) {
3688                         if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, group_ent, permset) == -1) {
3689                                 DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
3690                                         fname, strerror(errno) ));
3691                         }
3692                 } else if (tagtype == SMB_ACL_OTHER) {
3693                         if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, other_ent, permset) == -1) {
3694                                 DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
3695                                         fname, strerror(errno) ));
3696                         }
3697                 }
3698         }
3699
3700         ret = True;
3701
3702  done:
3703
3704         if (file_acl) {
3705                 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
3706         }
3707         if (new_file_acl) {
3708                 SMB_VFS_SYS_ACL_FREE_ACL(conn, new_file_acl);
3709         }
3710         return ret;
3711 }
3712
3713 /****************************************************************************
3714  Calls from UNIX extensions - POSIX ACL set.
3715  If num_def_acls == 0 then read/modify/write acl after removing all entries
3716  except SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER.
3717 ****************************************************************************/
3718
3719 BOOL set_unix_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname, uint16 num_acls, const char *pdata)
3720 {
3721         SMB_ACL_T file_acl = NULL;
3722
3723         if (!num_acls) {
3724                 /* Remove the ACL from the file. */
3725                 return remove_posix_acl(conn, fsp, fname);
3726         }
3727
3728         if ((file_acl = create_posix_acl_from_wire(conn, num_acls, pdata)) == NULL) {
3729                 return False;
3730         }
3731
3732         if (fsp && fsp->fd != -1) {
3733                 /* The preferred way - use an open fd. */
3734                 if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fd, file_acl) == -1) {
3735                         DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n",
3736                                 fname, strerror(errno) ));
3737                         SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
3738                         return False;
3739                 }
3740         } else {
3741                 if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS, file_acl) == -1) {
3742                         DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n",
3743                                 fname, strerror(errno) ));
3744                         SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
3745                         return False;
3746                 }
3747         }
3748
3749         DEBUG(10,("set_unix_posix_acl: set acl for file %s\n", fname ));
3750         SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
3751         return True;
3752 }