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