r25117: The mega-patch Jerry was waiting for. Remove all pstrings from
[tprouty/samba.git] / source / smbd / posix_acls.c
1 /*
2    Unix SMB/CIFS implementation.
3    SMB NT Security Descriptor / Unix permission conversion.
4    Copyright (C) Jeremy Allison 1994-2000.
5    Copyright (C) Andreas Gruenbacher 2002.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 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 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         fstring str;
550
551         dbgtext( "canon_ace index %d. Type = %s ", num, pace->attr == ALLOW_ACE ? "allow" : "deny" );
552         dbgtext( "SID = %s ", sid_to_string( str, &pace->trustee));
553         if (pace->owner_type == UID_ACE) {
554                 const char *u_name = uidtoname(pace->unix_ug.uid);
555                 dbgtext( "uid %u (%s) ", (unsigned int)pace->unix_ug.uid, u_name );
556         } else if (pace->owner_type == GID_ACE) {
557                 char *g_name = gidtoname(pace->unix_ug.gid);
558                 dbgtext( "gid %u (%s) ", (unsigned int)pace->unix_ug.gid, g_name );
559         } else
560                 dbgtext( "other ");
561         switch (pace->type) {
562                 case SMB_ACL_USER:
563                         dbgtext( "SMB_ACL_USER ");
564                         break;
565                 case SMB_ACL_USER_OBJ:
566                         dbgtext( "SMB_ACL_USER_OBJ ");
567                         break;
568                 case SMB_ACL_GROUP:
569                         dbgtext( "SMB_ACL_GROUP ");
570                         break;
571                 case SMB_ACL_GROUP_OBJ:
572                         dbgtext( "SMB_ACL_GROUP_OBJ ");
573                         break;
574                 case SMB_ACL_OTHER:
575                         dbgtext( "SMB_ACL_OTHER ");
576                         break;
577                 default:
578                         dbgtext( "MASK " );
579                         break;
580         }
581         if (pace->inherited)
582                 dbgtext( "(inherited) ");
583         dbgtext( "perms ");
584         dbgtext( "%c", pace->perms & S_IRUSR ? 'r' : '-');
585         dbgtext( "%c", pace->perms & S_IWUSR ? 'w' : '-');
586         dbgtext( "%c\n", pace->perms & S_IXUSR ? 'x' : '-');
587 }
588
589 /****************************************************************************
590  Print out a canon ace list.
591 ****************************************************************************/
592
593 static void print_canon_ace_list(const char *name, canon_ace *ace_list)
594 {
595         int count = 0;
596
597         if( DEBUGLVL( 10 )) {
598                 dbgtext( "print_canon_ace_list: %s\n", name );
599                 for (;ace_list; ace_list = ace_list->next, count++)
600                         print_canon_ace(ace_list, count );
601         }
602 }
603
604 /****************************************************************************
605  Map POSIX ACL perms to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
606 ****************************************************************************/
607
608 static mode_t convert_permset_to_mode_t(connection_struct *conn, SMB_ACL_PERMSET_T permset)
609 {
610         mode_t ret = 0;
611
612         ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRUSR : 0);
613         ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWUSR : 0);
614         ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXUSR : 0);
615
616         return ret;
617 }
618
619 /****************************************************************************
620  Map generic UNIX permissions to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
621 ****************************************************************************/
622
623 static mode_t unix_perms_to_acl_perms(mode_t mode, int r_mask, int w_mask, int x_mask)
624 {
625         mode_t ret = 0;
626
627         if (mode & r_mask)
628                 ret |= S_IRUSR;
629         if (mode & w_mask)
630                 ret |= S_IWUSR;
631         if (mode & x_mask)
632                 ret |= S_IXUSR;
633
634         return ret;
635 }
636
637 /****************************************************************************
638  Map canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits) to
639  an SMB_ACL_PERMSET_T.
640 ****************************************************************************/
641
642 static int map_acl_perms_to_permset(connection_struct *conn, mode_t mode, SMB_ACL_PERMSET_T *p_permset)
643 {
644         if (SMB_VFS_SYS_ACL_CLEAR_PERMS(conn, *p_permset) ==  -1)
645                 return -1;
646         if (mode & S_IRUSR) {
647                 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_READ) == -1)
648                         return -1;
649         }
650         if (mode & S_IWUSR) {
651                 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_WRITE) == -1)
652                         return -1;
653         }
654         if (mode & S_IXUSR) {
655                 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_EXECUTE) == -1)
656                         return -1;
657         }
658         return 0;
659 }
660
661 /****************************************************************************
662  Function to create owner and group SIDs from a SMB_STRUCT_STAT.
663 ****************************************************************************/
664
665 static void create_file_sids(SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SID *pgroup_sid)
666 {
667         uid_to_sid( powner_sid, psbuf->st_uid );
668         gid_to_sid( pgroup_sid, psbuf->st_gid );
669 }
670
671 /****************************************************************************
672  Is the identity in two ACEs equal ? Check both SID and uid/gid.
673 ****************************************************************************/
674
675 static BOOL identity_in_ace_equal(canon_ace *ace1, canon_ace *ace2)
676 {
677         if (sid_equal(&ace1->trustee, &ace2->trustee)) {
678                 return True;
679         }
680         if (ace1->owner_type == ace2->owner_type) {
681                 if (ace1->owner_type == UID_ACE &&
682                                 ace1->unix_ug.uid == ace2->unix_ug.uid) {
683                         return True;
684                 } else if (ace1->owner_type == GID_ACE &&
685                                 ace1->unix_ug.gid == ace2->unix_ug.gid) {
686                         return True;
687                 }
688         }
689         return False;
690 }
691
692 /****************************************************************************
693  Merge aces with a common sid - if both are allow or deny, OR the permissions together and
694  delete the second one. If the first is deny, mask the permissions off and delete the allow
695  if the permissions become zero, delete the deny if the permissions are non zero.
696 ****************************************************************************/
697
698 static void merge_aces( canon_ace **pp_list_head )
699 {
700         canon_ace *list_head = *pp_list_head;
701         canon_ace *curr_ace_outer;
702         canon_ace *curr_ace_outer_next;
703
704         /*
705          * First, merge allow entries with identical SIDs, and deny entries
706          * with identical SIDs.
707          */
708
709         for (curr_ace_outer = list_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
710                 canon_ace *curr_ace;
711                 canon_ace *curr_ace_next;
712
713                 curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
714
715                 for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
716
717                         curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
718
719                         if (identity_in_ace_equal(curr_ace, curr_ace_outer) &&
720                                 (curr_ace->attr == curr_ace_outer->attr)) {
721
722                                 if( DEBUGLVL( 10 )) {
723                                         dbgtext("merge_aces: Merging ACE's\n");
724                                         print_canon_ace( curr_ace_outer, 0);
725                                         print_canon_ace( curr_ace, 0);
726                                 }
727
728                                 /* Merge two allow or two deny ACE's. */
729
730                                 curr_ace_outer->perms |= curr_ace->perms;
731                                 DLIST_REMOVE(list_head, curr_ace);
732                                 SAFE_FREE(curr_ace);
733                                 curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
734                         }
735                 }
736         }
737
738         /*
739          * Now go through and mask off allow permissions with deny permissions.
740          * We can delete either the allow or deny here as we know that each SID
741          * appears only once in the list.
742          */
743
744         for (curr_ace_outer = list_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
745                 canon_ace *curr_ace;
746                 canon_ace *curr_ace_next;
747
748                 curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
749
750                 for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
751
752                         curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
753
754                         /*
755                          * Subtract ACE's with different entries. Due to the ordering constraints
756                          * we've put on the ACL, we know the deny must be the first one.
757                          */
758
759                         if (identity_in_ace_equal(curr_ace, curr_ace_outer) &&
760                                 (curr_ace_outer->attr == DENY_ACE) && (curr_ace->attr == ALLOW_ACE)) {
761
762                                 if( DEBUGLVL( 10 )) {
763                                         dbgtext("merge_aces: Masking ACE's\n");
764                                         print_canon_ace( curr_ace_outer, 0);
765                                         print_canon_ace( curr_ace, 0);
766                                 }
767
768                                 curr_ace->perms &= ~curr_ace_outer->perms;
769
770                                 if (curr_ace->perms == 0) {
771
772                                         /*
773                                          * The deny overrides the allow. Remove the allow.
774                                          */
775
776                                         DLIST_REMOVE(list_head, curr_ace);
777                                         SAFE_FREE(curr_ace);
778                                         curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
779
780                                 } else {
781
782                                         /*
783                                          * Even after removing permissions, there
784                                          * are still allow permissions - delete the deny.
785                                          * It is safe to delete the deny here,
786                                          * as we are guarenteed by the deny first
787                                          * ordering that all the deny entries for
788                                          * this SID have already been merged into one
789                                          * before we can get to an allow ace.
790                                          */
791
792                                         DLIST_REMOVE(list_head, curr_ace_outer);
793                                         SAFE_FREE(curr_ace_outer);
794                                         break;
795                                 }
796                         }
797
798                 } /* end for curr_ace */
799         } /* end for curr_ace_outer */
800
801         /* We may have modified the list. */
802
803         *pp_list_head = list_head;
804 }
805
806 /****************************************************************************
807  Check if we need to return NT4.x compatible ACL entries.
808 ****************************************************************************/
809
810 static BOOL nt4_compatible_acls(void)
811 {
812         int compat = lp_acl_compatibility();
813
814         if (compat == ACL_COMPAT_AUTO) {
815                 enum remote_arch_types ra_type = get_remote_arch();
816
817                 /* Automatically adapt to client */
818                 return (ra_type <= RA_WINNT);
819         } else
820                 return (compat == ACL_COMPAT_WINNT);
821 }
822
823
824 /****************************************************************************
825  Map canon_ace perms to permission bits NT.
826  The attr element is not used here - we only process deny entries on set,
827  not get. Deny entries are implicit on get with ace->perms = 0.
828 ****************************************************************************/
829
830 static SEC_ACCESS map_canon_ace_perms(int snum,
831                                 int *pacl_type,
832                                 mode_t perms,
833                                 BOOL directory_ace)
834 {
835         SEC_ACCESS sa;
836         uint32 nt_mask = 0;
837
838         *pacl_type = SEC_ACE_TYPE_ACCESS_ALLOWED;
839
840         if (lp_acl_map_full_control(snum) && ((perms & ALL_ACE_PERMS) == ALL_ACE_PERMS)) {
841                 if (directory_ace) {
842                         nt_mask = UNIX_DIRECTORY_ACCESS_RWX;
843                 } else {
844                         nt_mask = UNIX_ACCESS_RWX;
845                 }
846         } else if ((perms & ALL_ACE_PERMS) == (mode_t)0) {
847                 /*
848                  * Windows NT refuses to display ACEs with no permissions in them (but
849                  * they are perfectly legal with Windows 2000). If the ACE has empty
850                  * permissions we cannot use 0, so we use the otherwise unused
851                  * WRITE_OWNER permission, which we ignore when we set an ACL.
852                  * We abstract this into a #define of UNIX_ACCESS_NONE to allow this
853                  * to be changed in the future.
854                  */
855
856                 if (nt4_compatible_acls())
857                         nt_mask = UNIX_ACCESS_NONE;
858                 else
859                         nt_mask = 0;
860         } else {
861                 if (directory_ace) {
862                         nt_mask |= ((perms & S_IRUSR) ? UNIX_DIRECTORY_ACCESS_R : 0 );
863                         nt_mask |= ((perms & S_IWUSR) ? UNIX_DIRECTORY_ACCESS_W : 0 );
864                         nt_mask |= ((perms & S_IXUSR) ? UNIX_DIRECTORY_ACCESS_X : 0 );
865                 } else {
866                         nt_mask |= ((perms & S_IRUSR) ? UNIX_ACCESS_R : 0 );
867                         nt_mask |= ((perms & S_IWUSR) ? UNIX_ACCESS_W : 0 );
868                         nt_mask |= ((perms & S_IXUSR) ? UNIX_ACCESS_X : 0 );
869                 }
870         }
871
872         DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n",
873                         (unsigned int)perms, (unsigned int)nt_mask ));
874
875         init_sec_access(&sa,nt_mask);
876         return sa;
877 }
878
879 /****************************************************************************
880  Map NT perms to a UNIX mode_t.
881 ****************************************************************************/
882
883 #define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES)
884 #define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA|FILE_WRITE_ATTRIBUTES)
885 #define FILE_SPECIFIC_EXECUTE_BITS (FILE_EXECUTE)
886
887 static mode_t map_nt_perms( uint32 *mask, int type)
888 {
889         mode_t mode = 0;
890
891         switch(type) {
892         case S_IRUSR:
893                 if((*mask) & GENERIC_ALL_ACCESS)
894                         mode = S_IRUSR|S_IWUSR|S_IXUSR;
895                 else {
896                         mode |= ((*mask) & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRUSR : 0;
897                         mode |= ((*mask) & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWUSR : 0;
898                         mode |= ((*mask) & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXUSR : 0;
899                 }
900                 break;
901         case S_IRGRP:
902                 if((*mask) & GENERIC_ALL_ACCESS)
903                         mode = S_IRGRP|S_IWGRP|S_IXGRP;
904                 else {
905                         mode |= ((*mask) & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRGRP : 0;
906                         mode |= ((*mask) & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWGRP : 0;
907                         mode |= ((*mask) & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXGRP : 0;
908                 }
909                 break;
910         case S_IROTH:
911                 if((*mask) & GENERIC_ALL_ACCESS)
912                         mode = S_IROTH|S_IWOTH|S_IXOTH;
913                 else {
914                         mode |= ((*mask) & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IROTH : 0;
915                         mode |= ((*mask) & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWOTH : 0;
916                         mode |= ((*mask) & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXOTH : 0;
917                 }
918                 break;
919         }
920
921         return mode;
922 }
923
924 /****************************************************************************
925  Unpack a SEC_DESC into a UNIX owner and group.
926 ****************************************************************************/
927
928 NTSTATUS unpack_nt_owners(int snum, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, SEC_DESC *psd)
929 {
930         DOM_SID owner_sid;
931         DOM_SID grp_sid;
932
933         *puser = (uid_t)-1;
934         *pgrp = (gid_t)-1;
935
936         if(security_info_sent == 0) {
937                 DEBUG(0,("unpack_nt_owners: no security info sent !\n"));
938                 return NT_STATUS_OK;
939         }
940
941         /*
942          * Validate the owner and group SID's.
943          */
944
945         memset(&owner_sid, '\0', sizeof(owner_sid));
946         memset(&grp_sid, '\0', sizeof(grp_sid));
947
948         DEBUG(5,("unpack_nt_owners: validating owner_sids.\n"));
949
950         /*
951          * Don't immediately fail if the owner sid cannot be validated.
952          * This may be a group chown only set.
953          */
954
955         if (security_info_sent & OWNER_SECURITY_INFORMATION) {
956                 sid_copy(&owner_sid, psd->owner_sid);
957                 if (!sid_to_uid(&owner_sid, puser)) {
958                         if (lp_force_unknown_acl_user(snum)) {
959                                 /* this allows take ownership to work
960                                  * reasonably */
961                                 *puser = current_user.ut.uid;
962                         } else {
963                                 DEBUG(3,("unpack_nt_owners: unable to validate"
964                                          " owner sid for %s\n",
965                                          sid_string_static(&owner_sid)));
966                                 return NT_STATUS_INVALID_OWNER;
967                         }
968                 }
969                 DEBUG(3,("unpack_nt_owners: owner sid mapped to uid %u\n",
970                          (unsigned int)*puser ));
971         }
972
973         /*
974          * Don't immediately fail if the group sid cannot be validated.
975          * This may be an owner chown only set.
976          */
977
978         if (security_info_sent & GROUP_SECURITY_INFORMATION) {
979                 sid_copy(&grp_sid, psd->group_sid);
980                 if (!sid_to_gid( &grp_sid, pgrp)) {
981                         if (lp_force_unknown_acl_user(snum)) {
982                                 /* this allows take group ownership to work
983                                  * reasonably */
984                                 *pgrp = current_user.ut.gid;
985                         } else {
986                                 DEBUG(3,("unpack_nt_owners: unable to validate"
987                                          " group sid.\n"));
988                                 return NT_STATUS_INVALID_OWNER;
989                         }
990                 }
991                 DEBUG(3,("unpack_nt_owners: group sid mapped to gid %u\n",
992                          (unsigned int)*pgrp));
993         }
994
995         DEBUG(5,("unpack_nt_owners: owner_sids validated.\n"));
996
997         return NT_STATUS_OK;
998 }
999
1000 /****************************************************************************
1001  Ensure the enforced permissions for this share apply.
1002 ****************************************************************************/
1003
1004 static void apply_default_perms(const files_struct *fsp, canon_ace *pace, mode_t type)
1005 {
1006         int snum = SNUM(fsp->conn);
1007         mode_t and_bits = (mode_t)0;
1008         mode_t or_bits = (mode_t)0;
1009
1010         /* Get the initial bits to apply. */
1011
1012         if (fsp->is_directory) {
1013                 and_bits = lp_dir_security_mask(snum);
1014                 or_bits = lp_force_dir_security_mode(snum);
1015         } else {
1016                 and_bits = lp_security_mask(snum);
1017                 or_bits = lp_force_security_mode(snum);
1018         }
1019
1020         /* Now bounce them into the S_USR space. */     
1021         switch(type) {
1022         case S_IRUSR:
1023                 /* Ensure owner has read access. */
1024                 pace->perms |= S_IRUSR;
1025                 if (fsp->is_directory)
1026                         pace->perms |= (S_IWUSR|S_IXUSR);
1027                 and_bits = unix_perms_to_acl_perms(and_bits, S_IRUSR, S_IWUSR, S_IXUSR);
1028                 or_bits = unix_perms_to_acl_perms(or_bits, S_IRUSR, S_IWUSR, S_IXUSR);
1029                 break;
1030         case S_IRGRP:
1031                 and_bits = unix_perms_to_acl_perms(and_bits, S_IRGRP, S_IWGRP, S_IXGRP);
1032                 or_bits = unix_perms_to_acl_perms(or_bits, S_IRGRP, S_IWGRP, S_IXGRP);
1033                 break;
1034         case S_IROTH:
1035                 and_bits = unix_perms_to_acl_perms(and_bits, S_IROTH, S_IWOTH, S_IXOTH);
1036                 or_bits = unix_perms_to_acl_perms(or_bits, S_IROTH, S_IWOTH, S_IXOTH);
1037                 break;
1038         }
1039
1040         pace->perms = ((pace->perms & and_bits)|or_bits);
1041 }
1042
1043 /****************************************************************************
1044  Check if a given uid/SID is in a group gid/SID. This is probably very
1045  expensive and will need optimisation. A *lot* of optimisation :-). JRA.
1046 ****************************************************************************/
1047
1048 static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace )
1049 {
1050         const char *u_name = NULL;
1051
1052         /* "Everyone" always matches every uid. */
1053
1054         if (sid_equal(&group_ace->trustee, &global_sid_World))
1055                 return True;
1056
1057         /* Assume that the current user is in the current group (force group) */
1058
1059         if (uid_ace->unix_ug.uid == current_user.ut.uid && group_ace->unix_ug.gid == current_user.ut.gid)
1060                 return True;
1061
1062         /* u_name talloc'ed off tos. */
1063         u_name = uidtoname(uid_ace->unix_ug.uid);
1064         if (!u_name) {
1065                 return False;
1066         }
1067         return user_in_group_sid(u_name, &group_ace->trustee);
1068 }
1069
1070 /****************************************************************************
1071  A well formed POSIX file or default ACL has at least 3 entries, a 
1072  SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ.
1073  In addition, the owner must always have at least read access.
1074  When using this call on get_acl, the pst struct is valid and contains
1075  the mode of the file. When using this call on set_acl, the pst struct has
1076  been modified to have a mode containing the default for this file or directory
1077  type.
1078 ****************************************************************************/
1079
1080 static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
1081                                                         const files_struct *fsp,
1082                                                         const DOM_SID *pfile_owner_sid,
1083                                                         const DOM_SID *pfile_grp_sid,
1084                                                         SMB_STRUCT_STAT *pst,
1085                                                         BOOL setting_acl)
1086 {
1087         canon_ace *pace;
1088         BOOL got_user = False;
1089         BOOL got_grp = False;
1090         BOOL got_other = False;
1091         canon_ace *pace_other = NULL;
1092
1093         for (pace = *pp_ace; pace; pace = pace->next) {
1094                 if (pace->type == SMB_ACL_USER_OBJ) {
1095
1096                         if (setting_acl)
1097                                 apply_default_perms(fsp, pace, S_IRUSR);
1098                         got_user = True;
1099
1100                 } else if (pace->type == SMB_ACL_GROUP_OBJ) {
1101
1102                         /*
1103                          * Ensure create mask/force create mode is respected on set.
1104                          */
1105
1106                         if (setting_acl)
1107                                 apply_default_perms(fsp, pace, S_IRGRP);
1108                         got_grp = True;
1109
1110                 } else if (pace->type == SMB_ACL_OTHER) {
1111
1112                         /*
1113                          * Ensure create mask/force create mode is respected on set.
1114                          */
1115
1116                         if (setting_acl)
1117                                 apply_default_perms(fsp, pace, S_IROTH);
1118                         got_other = True;
1119                         pace_other = pace;
1120                 }
1121         }
1122
1123         if (!got_user) {
1124                 if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) {
1125                         DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
1126                         return False;
1127                 }
1128
1129                 ZERO_STRUCTP(pace);
1130                 pace->type = SMB_ACL_USER_OBJ;
1131                 pace->owner_type = UID_ACE;
1132                 pace->unix_ug.uid = pst->st_uid;
1133                 pace->trustee = *pfile_owner_sid;
1134                 pace->attr = ALLOW_ACE;
1135
1136                 if (setting_acl) {
1137                         /* See if the owning user is in any of the other groups in
1138                            the ACE. If so, OR in the permissions from that group. */
1139
1140                         BOOL group_matched = False;
1141                         canon_ace *pace_iter;
1142
1143                         for (pace_iter = *pp_ace; pace_iter; pace_iter = pace_iter->next) {
1144                                 if (pace_iter->type == SMB_ACL_GROUP_OBJ || pace_iter->type == SMB_ACL_GROUP) {
1145                                         if (uid_entry_in_group(pace, pace_iter)) {
1146                                                 pace->perms |= pace_iter->perms;
1147                                                 group_matched = True;
1148                                         }
1149                                 }
1150                         }
1151
1152                         /* If we only got an "everyone" perm, just use that. */
1153                         if (!group_matched) {
1154                                 if (got_other)
1155                                         pace->perms = pace_other->perms;
1156                                 else
1157                                         pace->perms = 0;
1158                         }
1159
1160                         apply_default_perms(fsp, pace, S_IRUSR);
1161                 } else {
1162                         pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR);
1163                 }
1164
1165                 DLIST_ADD(*pp_ace, pace);
1166         }
1167
1168         if (!got_grp) {
1169                 if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) {
1170                         DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
1171                         return False;
1172                 }
1173
1174                 ZERO_STRUCTP(pace);
1175                 pace->type = SMB_ACL_GROUP_OBJ;
1176                 pace->owner_type = GID_ACE;
1177                 pace->unix_ug.uid = pst->st_gid;
1178                 pace->trustee = *pfile_grp_sid;
1179                 pace->attr = ALLOW_ACE;
1180                 if (setting_acl) {
1181                         /* If we only got an "everyone" perm, just use that. */
1182                         if (got_other)
1183                                 pace->perms = pace_other->perms;
1184                         else
1185                                 pace->perms = 0;
1186                         apply_default_perms(fsp, pace, S_IRGRP);
1187                 } else {
1188                         pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP);
1189                 }
1190
1191                 DLIST_ADD(*pp_ace, pace);
1192         }
1193
1194         if (!got_other) {
1195                 if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) {
1196                         DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
1197                         return False;
1198                 }
1199
1200                 ZERO_STRUCTP(pace);
1201                 pace->type = SMB_ACL_OTHER;
1202                 pace->owner_type = WORLD_ACE;
1203                 pace->unix_ug.world = -1;
1204                 pace->trustee = global_sid_World;
1205                 pace->attr = ALLOW_ACE;
1206                 if (setting_acl) {
1207                         pace->perms = 0;
1208                         apply_default_perms(fsp, pace, S_IROTH);
1209                 } else
1210                         pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IROTH, S_IWOTH, S_IXOTH);
1211
1212                 DLIST_ADD(*pp_ace, pace);
1213         }
1214
1215         return True;
1216 }
1217
1218 /****************************************************************************
1219  Check if a POSIX ACL has the required SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries.
1220  If it does not have them, check if there are any entries where the trustee is the
1221  file owner or the owning group, and map these to SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ.
1222 ****************************************************************************/
1223
1224 static void check_owning_objs(canon_ace *ace, DOM_SID *pfile_owner_sid, DOM_SID *pfile_grp_sid)
1225 {
1226         BOOL got_user_obj, got_group_obj;
1227         canon_ace *current_ace;
1228         int i, entries;
1229
1230         entries = count_canon_ace_list(ace);
1231         got_user_obj = False;
1232         got_group_obj = False;
1233
1234         for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
1235                 if (current_ace->type == SMB_ACL_USER_OBJ)
1236                         got_user_obj = True;
1237                 else if (current_ace->type == SMB_ACL_GROUP_OBJ)
1238                         got_group_obj = True;
1239         }
1240         if (got_user_obj && got_group_obj) {
1241                 DEBUG(10,("check_owning_objs: ACL had owning user/group entries.\n"));
1242                 return;
1243         }
1244
1245         for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
1246                 if (!got_user_obj && current_ace->owner_type == UID_ACE &&
1247                                 sid_equal(&current_ace->trustee, pfile_owner_sid)) {
1248                         current_ace->type = SMB_ACL_USER_OBJ;
1249                         got_user_obj = True;
1250                 }
1251                 if (!got_group_obj && current_ace->owner_type == GID_ACE &&
1252                                 sid_equal(&current_ace->trustee, pfile_grp_sid)) {
1253                         current_ace->type = SMB_ACL_GROUP_OBJ;
1254                         got_group_obj = True;
1255                 }
1256         }
1257         if (!got_user_obj)
1258                 DEBUG(10,("check_owning_objs: ACL is missing an owner entry.\n"));
1259         if (!got_group_obj)
1260                 DEBUG(10,("check_owning_objs: ACL is missing an owning group entry.\n"));
1261 }
1262
1263 /****************************************************************************
1264  Unpack a SEC_DESC into two canonical ace lists.
1265 ****************************************************************************/
1266
1267 static BOOL create_canon_ace_lists(files_struct *fsp, SMB_STRUCT_STAT *pst,
1268                                                         DOM_SID *pfile_owner_sid,
1269                                                         DOM_SID *pfile_grp_sid,
1270                                                         canon_ace **ppfile_ace, canon_ace **ppdir_ace,
1271                                                         SEC_ACL *dacl)
1272 {
1273         BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False);
1274         canon_ace *file_ace = NULL;
1275         canon_ace *dir_ace = NULL;
1276         canon_ace *current_ace = NULL;
1277         BOOL got_dir_allow = False;
1278         BOOL got_file_allow = False;
1279         int i, j;
1280
1281         *ppfile_ace = NULL;
1282         *ppdir_ace = NULL;
1283
1284         /*
1285          * Convert the incoming ACL into a more regular form.
1286          */
1287
1288         for(i = 0; i < dacl->num_aces; i++) {
1289                 SEC_ACE *psa = &dacl->aces[i];
1290
1291                 if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) && (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
1292                         DEBUG(3,("create_canon_ace_lists: unable to set anything but an ALLOW or DENY ACE.\n"));
1293                         return False;
1294                 }
1295
1296                 if (nt4_compatible_acls()) {
1297                         /*
1298                          * The security mask may be UNIX_ACCESS_NONE which should map into
1299                          * no permissions (we overload the WRITE_OWNER bit for this) or it
1300                          * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
1301                          * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
1302                          */
1303
1304                         /*
1305                          * Convert GENERIC bits to specific bits.
1306                          */
1307  
1308                         se_map_generic(&psa->access_mask, &file_generic_mapping);
1309
1310                         psa->access_mask &= (UNIX_ACCESS_NONE|FILE_ALL_ACCESS);
1311
1312                         if(psa->access_mask != UNIX_ACCESS_NONE)
1313                                 psa->access_mask &= ~UNIX_ACCESS_NONE;
1314                 }
1315         }
1316
1317         /*
1318          * Deal with the fact that NT 4.x re-writes the canonical format
1319          * that we return for default ACLs. If a directory ACE is identical
1320          * to a inherited directory ACE then NT changes the bits so that the
1321          * first ACE is set to OI|IO and the second ACE for this SID is set
1322          * to CI. We need to repair this. JRA.
1323          */
1324
1325         for(i = 0; i < dacl->num_aces; i++) {
1326                 SEC_ACE *psa1 = &dacl->aces[i];
1327
1328                 for (j = i + 1; j < dacl->num_aces; j++) {
1329                         SEC_ACE *psa2 = &dacl->aces[j];
1330
1331                         if (psa1->access_mask != psa2->access_mask)
1332                                 continue;
1333
1334                         if (!sid_equal(&psa1->trustee, &psa2->trustee))
1335                                 continue;
1336
1337                         /*
1338                          * Ok - permission bits and SIDs are equal.
1339                          * Check if flags were re-written.
1340                          */
1341
1342                         if (psa1->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
1343
1344                                 psa1->flags |= (psa2->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
1345                                 psa2->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
1346                                 
1347                         } else if (psa2->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
1348
1349                                 psa2->flags |= (psa1->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
1350                                 psa1->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
1351                                 
1352                         }
1353                 }
1354         }
1355
1356         for(i = 0; i < dacl->num_aces; i++) {
1357                 SEC_ACE *psa = &dacl->aces[i];
1358
1359                 /*
1360                  * Create a cannon_ace entry representing this NT DACL ACE.
1361                  */
1362
1363                 if ((current_ace = SMB_MALLOC_P(canon_ace)) == NULL) {
1364                         free_canon_ace_list(file_ace);
1365                         free_canon_ace_list(dir_ace);
1366                         DEBUG(0,("create_canon_ace_lists: malloc fail.\n"));
1367                         return False;
1368                 }
1369
1370                 ZERO_STRUCTP(current_ace);
1371
1372                 sid_copy(&current_ace->trustee, &psa->trustee);
1373
1374                 /*
1375                  * Try and work out if the SID is a user or group
1376                  * as we need to flag these differently for POSIX.
1377                  * Note what kind of a POSIX ACL this should map to.
1378                  */
1379
1380                 if( sid_equal(&current_ace->trustee, &global_sid_World)) {
1381                         current_ace->owner_type = WORLD_ACE;
1382                         current_ace->unix_ug.world = -1;
1383                         current_ace->type = SMB_ACL_OTHER;
1384                 } else if (sid_equal(&current_ace->trustee, &global_sid_Creator_Owner)) {
1385                         current_ace->owner_type = UID_ACE;
1386                         current_ace->unix_ug.uid = pst->st_uid;
1387                         current_ace->type = SMB_ACL_USER_OBJ;
1388
1389                         /*
1390                          * The Creator Owner entry only specifies inheritable permissions,
1391                          * never access permissions. WinNT doesn't always set the ACE to
1392                          *INHERIT_ONLY, though.
1393                          */
1394
1395                         if (nt4_compatible_acls())
1396                                 psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
1397                 } else if (sid_equal(&current_ace->trustee, &global_sid_Creator_Group)) {
1398                         current_ace->owner_type = GID_ACE;
1399                         current_ace->unix_ug.gid = pst->st_gid;
1400                         current_ace->type = SMB_ACL_GROUP_OBJ;
1401
1402                         /*
1403                          * The Creator Group entry only specifies inheritable permissions,
1404                          * never access permissions. WinNT doesn't always set the ACE to
1405                          *INHERIT_ONLY, though.
1406                          */
1407                         if (nt4_compatible_acls())
1408                                 psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
1409
1410                 } else if (sid_to_uid( &current_ace->trustee, &current_ace->unix_ug.uid)) {
1411                         current_ace->owner_type = UID_ACE;
1412                         current_ace->type = SMB_ACL_USER;
1413                 } else if (sid_to_gid( &current_ace->trustee, &current_ace->unix_ug.gid)) {
1414                         current_ace->owner_type = GID_ACE;
1415                         current_ace->type = SMB_ACL_GROUP;
1416                 } else {
1417                         fstring str;
1418
1419                         /*
1420                          * Silently ignore map failures in non-mappable SIDs (NT Authority, BUILTIN etc).
1421                          */
1422
1423                         if (non_mappable_sid(&psa->trustee)) {
1424                                 DEBUG(10,("create_canon_ace_lists: ignoring non-mappable SID %s\n",
1425                                         sid_to_string(str, &psa->trustee) ));
1426                                 SAFE_FREE(current_ace);
1427                                 continue;
1428                         }
1429
1430                         free_canon_ace_list(file_ace);
1431                         free_canon_ace_list(dir_ace);
1432                         DEBUG(0,("create_canon_ace_lists: unable to map SID %s to uid or gid.\n",
1433                                 sid_to_string(str, &current_ace->trustee) ));
1434                         SAFE_FREE(current_ace);
1435                         return False;
1436                 }
1437
1438                 /*
1439                  * Map the given NT permissions into a UNIX mode_t containing only
1440                  * S_I(R|W|X)USR bits.
1441                  */
1442
1443                 current_ace->perms |= map_nt_perms( &psa->access_mask, S_IRUSR);
1444                 current_ace->attr = (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? ALLOW_ACE : DENY_ACE;
1445                 current_ace->inherited = ((psa->flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False);
1446
1447                 /*
1448                  * Now add the created ace to either the file list, the directory
1449                  * list, or both. We *MUST* preserve the order here (hence we use
1450                  * DLIST_ADD_END) as NT ACLs are order dependent.
1451                  */
1452
1453                 if (fsp->is_directory) {
1454
1455                         /*
1456                          * We can only add to the default POSIX ACE list if the ACE is
1457                          * designed to be inherited by both files and directories.
1458                          */
1459
1460                         if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) ==
1461                                 (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) {
1462
1463                                 DLIST_ADD_END(dir_ace, current_ace, canon_ace *);
1464
1465                                 /*
1466                                  * Note if this was an allow ace. We can't process
1467                                  * any further deny ace's after this.
1468                                  */
1469
1470                                 if (current_ace->attr == ALLOW_ACE)
1471                                         got_dir_allow = True;
1472
1473                                 if ((current_ace->attr == DENY_ACE) && got_dir_allow) {
1474                                         DEBUG(0,("create_canon_ace_lists: malformed ACL in inheritable ACL ! \
1475 Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
1476                                         free_canon_ace_list(file_ace);
1477                                         free_canon_ace_list(dir_ace);
1478                                         return False;
1479                                 }       
1480
1481                                 if( DEBUGLVL( 10 )) {
1482                                         dbgtext("create_canon_ace_lists: adding dir ACL:\n");
1483                                         print_canon_ace( current_ace, 0);
1484                                 }
1485
1486                                 /*
1487                                  * If this is not an inherit only ACE we need to add a duplicate
1488                                  * to the file acl.
1489                                  */
1490
1491                                 if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
1492                                         canon_ace *dup_ace = dup_canon_ace(current_ace);
1493
1494                                         if (!dup_ace) {
1495                                                 DEBUG(0,("create_canon_ace_lists: malloc fail !\n"));
1496                                                 free_canon_ace_list(file_ace);
1497                                                 free_canon_ace_list(dir_ace);
1498                                                 return False;
1499                                         }
1500
1501                                         /*
1502                                          * We must not free current_ace here as its
1503                                          * pointer is now owned by the dir_ace list.
1504                                          */
1505                                         current_ace = dup_ace;
1506                                 } else {
1507                                         /*
1508                                          * We must not free current_ace here as its
1509                                          * pointer is now owned by the dir_ace list.
1510                                          */
1511                                         current_ace = NULL;
1512                                 }
1513                         }
1514                 }
1515
1516                 /*
1517                  * Only add to the file ACL if not inherit only.
1518                  */
1519
1520                 if (current_ace && !(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
1521                         DLIST_ADD_END(file_ace, current_ace, canon_ace *);
1522
1523                         /*
1524                          * Note if this was an allow ace. We can't process
1525                          * any further deny ace's after this.
1526                          */
1527
1528                         if (current_ace->attr == ALLOW_ACE)
1529                                 got_file_allow = True;
1530
1531                         if ((current_ace->attr == DENY_ACE) && got_file_allow) {
1532                                 DEBUG(0,("create_canon_ace_lists: malformed ACL in file ACL ! \
1533 Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
1534                                 free_canon_ace_list(file_ace);
1535                                 free_canon_ace_list(dir_ace);
1536                                 return False;
1537                         }       
1538
1539                         if( DEBUGLVL( 10 )) {
1540                                 dbgtext("create_canon_ace_lists: adding file ACL:\n");
1541                                 print_canon_ace( current_ace, 0);
1542                         }
1543                         all_aces_are_inherit_only = False;
1544                         /*
1545                          * We must not free current_ace here as its
1546                          * pointer is now owned by the file_ace list.
1547                          */
1548                         current_ace = NULL;
1549                 }
1550
1551                 /*
1552                  * Free if ACE was not added.
1553                  */
1554
1555                 SAFE_FREE(current_ace);
1556         }
1557
1558         if (fsp->is_directory && all_aces_are_inherit_only) {
1559                 /*
1560                  * Windows 2000 is doing one of these weird 'inherit acl'
1561                  * traverses to conserve NTFS ACL resources. Just pretend
1562                  * there was no DACL sent. JRA.
1563                  */
1564
1565                 DEBUG(10,("create_canon_ace_lists: Win2k inherit acl traverse. Ignoring DACL.\n"));
1566                 free_canon_ace_list(file_ace);
1567                 free_canon_ace_list(dir_ace);
1568                 file_ace = NULL;
1569                 dir_ace = NULL;
1570         } else {
1571                 /*
1572                  * Check if we have SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries in each
1573                  * ACL. If we don't have them, check if any SMB_ACL_USER/SMB_ACL_GROUP
1574                  * entries can be converted to *_OBJ. Usually we will already have these
1575                  * entries in the Default ACL, and the Access ACL will not have them.
1576                  */
1577                 if (file_ace) {
1578                         check_owning_objs(file_ace, pfile_owner_sid, pfile_grp_sid);
1579                 }
1580                 if (dir_ace) {
1581                         check_owning_objs(dir_ace, pfile_owner_sid, pfile_grp_sid);
1582                 }
1583         }
1584
1585         *ppfile_ace = file_ace;
1586         *ppdir_ace = dir_ace;
1587
1588         return True;
1589 }
1590
1591 /****************************************************************************
1592  ASCII art time again... JRA :-).
1593
1594  We have 4 cases to process when moving from an NT ACL to a POSIX ACL. Firstly,
1595  we insist the ACL is in canonical form (ie. all DENY entries preceede ALLOW
1596  entries). Secondly, the merge code has ensured that all duplicate SID entries for
1597  allow or deny have been merged, so the same SID can only appear once in the deny
1598  list or once in the allow list.
1599
1600  We then process as follows :
1601
1602  ---------------------------------------------------------------------------
1603  First pass - look for a Everyone DENY entry.
1604
1605  If it is deny all (rwx) trunate the list at this point.
1606  Else, walk the list from this point and use the deny permissions of this
1607  entry as a mask on all following allow entries. Finally, delete
1608  the Everyone DENY entry (we have applied it to everything possible).
1609
1610  In addition, in this pass we remove any DENY entries that have 
1611  no permissions (ie. they are a DENY nothing).
1612  ---------------------------------------------------------------------------
1613  Second pass - only deal with deny user entries.
1614
1615  DENY user1 (perms XXX)
1616
1617  new_perms = 0
1618  for all following allow group entries where user1 is in group
1619         new_perms |= group_perms;
1620
1621  user1 entry perms = new_perms & ~ XXX;
1622
1623  Convert the deny entry to an allow entry with the new perms and
1624  push to the end of the list. Note if the user was in no groups
1625  this maps to a specific allow nothing entry for this user.
1626
1627  The common case from the NT ACL choser (userX deny all) is
1628  optimised so we don't do the group lookup - we just map to
1629  an allow nothing entry.
1630
1631  What we're doing here is inferring the allow permissions the
1632  person setting the ACE on user1 wanted by looking at the allow
1633  permissions on the groups the user is currently in. This will
1634  be a snapshot, depending on group membership but is the best
1635  we can do and has the advantage of failing closed rather than
1636  open.
1637  ---------------------------------------------------------------------------
1638  Third pass - only deal with deny group entries.
1639
1640  DENY group1 (perms XXX)
1641
1642  for all following allow user entries where user is in group1
1643    user entry perms = user entry perms & ~ XXX;
1644
1645  If there is a group Everyone allow entry with permissions YYY,
1646  convert the group1 entry to an allow entry and modify its
1647  permissions to be :
1648
1649  new_perms = YYY & ~ XXX
1650
1651  and push to the end of the list.
1652
1653  If there is no group Everyone allow entry then convert the
1654  group1 entry to a allow nothing entry and push to the end of the list.
1655
1656  Note that the common case from the NT ACL choser (groupX deny all)
1657  cannot be optimised here as we need to modify user entries who are
1658  in the group to change them to a deny all also.
1659
1660  What we're doing here is modifying the allow permissions of
1661  user entries (which are more specific in POSIX ACLs) to mask
1662  out the explicit deny set on the group they are in. This will
1663  be a snapshot depending on current group membership but is the
1664  best we can do and has the advantage of failing closed rather
1665  than open.
1666  ---------------------------------------------------------------------------
1667  Fourth pass - cope with cumulative permissions.
1668
1669  for all allow user entries, if there exists an allow group entry with
1670  more permissive permissions, and the user is in that group, rewrite the
1671  allow user permissions to contain both sets of permissions.
1672
1673  Currently the code for this is #ifdef'ed out as these semantics make
1674  no sense to me. JRA.
1675  ---------------------------------------------------------------------------
1676
1677  Note we *MUST* do the deny user pass first as this will convert deny user
1678  entries into allow user entries which can then be processed by the deny
1679  group pass.
1680
1681  The above algorithm took a *lot* of thinking about - hence this
1682  explaination :-). JRA.
1683 ****************************************************************************/
1684
1685 /****************************************************************************
1686  Process a canon_ace list entries. This is very complex code. We need
1687  to go through and remove the "deny" permissions from any allow entry that matches
1688  the id of this entry. We have already refused any NT ACL that wasn't in correct
1689  order (DENY followed by ALLOW). If any allow entry ends up with zero permissions,
1690  we just remove it (to fail safe). We have already removed any duplicate ace
1691  entries. Treat an "Everyone" DENY_ACE as a special case - use it to mask all
1692  allow entries.
1693 ****************************************************************************/
1694
1695 static void process_deny_list( canon_ace **pp_ace_list )
1696 {
1697         canon_ace *ace_list = *pp_ace_list;
1698         canon_ace *curr_ace = NULL;
1699         canon_ace *curr_ace_next = NULL;
1700
1701         /* Pass 1 above - look for an Everyone, deny entry. */
1702
1703         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1704                 canon_ace *allow_ace_p;
1705
1706                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1707
1708                 if (curr_ace->attr != DENY_ACE)
1709                         continue;
1710
1711                 if (curr_ace->perms == (mode_t)0) {
1712
1713                         /* Deny nothing entry - delete. */
1714
1715                         DLIST_REMOVE(ace_list, curr_ace);
1716                         continue;
1717                 }
1718
1719                 if (!sid_equal(&curr_ace->trustee, &global_sid_World))
1720                         continue;
1721
1722                 /* JRATEST - assert. */
1723                 SMB_ASSERT(curr_ace->owner_type == WORLD_ACE);
1724
1725                 if (curr_ace->perms == ALL_ACE_PERMS) {
1726
1727                         /*
1728                          * Optimisation. This is a DENY_ALL to Everyone. Truncate the
1729                          * list at this point including this entry.
1730                          */
1731
1732                         canon_ace *prev_entry = curr_ace->prev;
1733
1734                         free_canon_ace_list( curr_ace );
1735                         if (prev_entry)
1736                                 prev_entry->next = NULL;
1737                         else {
1738                                 /* We deleted the entire list. */
1739                                 ace_list = NULL;
1740                         }
1741                         break;
1742                 }
1743
1744                 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1745
1746                         /* 
1747                          * Only mask off allow entries.
1748                          */
1749
1750                         if (allow_ace_p->attr != ALLOW_ACE)
1751                                 continue;
1752
1753                         allow_ace_p->perms &= ~curr_ace->perms;
1754                 }
1755
1756                 /*
1757                  * Now it's been applied, remove it.
1758                  */
1759
1760                 DLIST_REMOVE(ace_list, curr_ace);
1761         }
1762
1763         /* Pass 2 above - deal with deny user entries. */
1764
1765         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1766                 mode_t new_perms = (mode_t)0;
1767                 canon_ace *allow_ace_p;
1768
1769                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1770
1771                 if (curr_ace->attr != DENY_ACE)
1772                         continue;
1773
1774                 if (curr_ace->owner_type != UID_ACE)
1775                         continue;
1776
1777                 if (curr_ace->perms == ALL_ACE_PERMS) {
1778
1779                         /*
1780                          * Optimisation - this is a deny everything to this user.
1781                          * Convert to an allow nothing and push to the end of the list.
1782                          */
1783
1784                         curr_ace->attr = ALLOW_ACE;
1785                         curr_ace->perms = (mode_t)0;
1786                         DLIST_DEMOTE(ace_list, curr_ace, canon_ace *);
1787                         continue;
1788                 }
1789
1790                 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1791
1792                         if (allow_ace_p->attr != ALLOW_ACE)
1793                                 continue;
1794
1795                         /* We process GID_ACE and WORLD_ACE entries only. */
1796
1797                         if (allow_ace_p->owner_type == UID_ACE)
1798                                 continue;
1799
1800                         if (uid_entry_in_group( curr_ace, allow_ace_p))
1801                                 new_perms |= allow_ace_p->perms;
1802                 }
1803
1804                 /*
1805                  * Convert to a allow entry, modify the perms and push to the end
1806                  * of the list.
1807                  */
1808
1809                 curr_ace->attr = ALLOW_ACE;
1810                 curr_ace->perms = (new_perms & ~curr_ace->perms);
1811                 DLIST_DEMOTE(ace_list, curr_ace, canon_ace *);
1812         }
1813
1814         /* Pass 3 above - deal with deny group entries. */
1815
1816         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1817                 canon_ace *allow_ace_p;
1818                 canon_ace *allow_everyone_p = NULL;
1819
1820                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1821
1822                 if (curr_ace->attr != DENY_ACE)
1823                         continue;
1824
1825                 if (curr_ace->owner_type != GID_ACE)
1826                         continue;
1827
1828                 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1829
1830                         if (allow_ace_p->attr != ALLOW_ACE)
1831                                 continue;
1832
1833                         /* Store a pointer to the Everyone allow, if it exists. */
1834                         if (allow_ace_p->owner_type == WORLD_ACE)
1835                                 allow_everyone_p = allow_ace_p;
1836
1837                         /* We process UID_ACE entries only. */
1838
1839                         if (allow_ace_p->owner_type != UID_ACE)
1840                                 continue;
1841
1842                         /* Mask off the deny group perms. */
1843
1844                         if (uid_entry_in_group( allow_ace_p, curr_ace))
1845                                 allow_ace_p->perms &= ~curr_ace->perms;
1846                 }
1847
1848                 /*
1849                  * Convert the deny to an allow with the correct perms and
1850                  * push to the end of the list.
1851                  */
1852
1853                 curr_ace->attr = ALLOW_ACE;
1854                 if (allow_everyone_p)
1855                         curr_ace->perms = allow_everyone_p->perms & ~curr_ace->perms;
1856                 else
1857                         curr_ace->perms = (mode_t)0;
1858                 DLIST_DEMOTE(ace_list, curr_ace, canon_ace *);
1859         }
1860
1861         /* Doing this fourth pass allows Windows semantics to be layered
1862          * on top of POSIX semantics. I'm not sure if this is desirable.
1863          * For example, in W2K ACLs there is no way to say, "Group X no
1864          * access, user Y full access" if user Y is a member of group X.
1865          * This seems completely broken semantics to me.... JRA.
1866          */
1867
1868 #if 0
1869         /* Pass 4 above - deal with allow entries. */
1870
1871         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1872                 canon_ace *allow_ace_p;
1873
1874                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1875
1876                 if (curr_ace->attr != ALLOW_ACE)
1877                         continue;
1878
1879                 if (curr_ace->owner_type != UID_ACE)
1880                         continue;
1881
1882                 for (allow_ace_p = ace_list; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1883
1884                         if (allow_ace_p->attr != ALLOW_ACE)
1885                                 continue;
1886
1887                         /* We process GID_ACE entries only. */
1888
1889                         if (allow_ace_p->owner_type != GID_ACE)
1890                                 continue;
1891
1892                         /* OR in the group perms. */
1893
1894                         if (uid_entry_in_group( curr_ace, allow_ace_p))
1895                                 curr_ace->perms |= allow_ace_p->perms;
1896                 }
1897         }
1898 #endif
1899
1900         *pp_ace_list = ace_list;
1901 }
1902
1903 /****************************************************************************
1904  Create a default mode that will be used if a security descriptor entry has
1905  no user/group/world entries.
1906 ****************************************************************************/
1907
1908 static mode_t create_default_mode(files_struct *fsp, BOOL interitable_mode)
1909 {
1910         int snum = SNUM(fsp->conn);
1911         mode_t and_bits = (mode_t)0;
1912         mode_t or_bits = (mode_t)0;
1913         mode_t mode = interitable_mode
1914                 ? unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name,
1915                              NULL )
1916                 : S_IRUSR;
1917
1918         if (fsp->is_directory)
1919                 mode |= (S_IWUSR|S_IXUSR);
1920
1921         /*
1922          * Now AND with the create mode/directory mode bits then OR with the
1923          * force create mode/force directory mode bits.
1924          */
1925
1926         if (fsp->is_directory) {
1927                 and_bits = lp_dir_security_mask(snum);
1928                 or_bits = lp_force_dir_security_mode(snum);
1929         } else {
1930                 and_bits = lp_security_mask(snum);
1931                 or_bits = lp_force_security_mode(snum);
1932         }
1933
1934         return ((mode & and_bits)|or_bits);
1935 }
1936
1937 /****************************************************************************
1938  Unpack a SEC_DESC into two canonical ace lists. We don't depend on this
1939  succeeding.
1940 ****************************************************************************/
1941
1942 static BOOL unpack_canon_ace(files_struct *fsp, 
1943                                                         SMB_STRUCT_STAT *pst,
1944                                                         DOM_SID *pfile_owner_sid,
1945                                                         DOM_SID *pfile_grp_sid,
1946                                                         canon_ace **ppfile_ace, canon_ace **ppdir_ace,
1947                                                         uint32 security_info_sent, SEC_DESC *psd)
1948 {
1949         canon_ace *file_ace = NULL;
1950         canon_ace *dir_ace = NULL;
1951
1952         *ppfile_ace = NULL;
1953         *ppdir_ace = NULL;
1954
1955         if(security_info_sent == 0) {
1956                 DEBUG(0,("unpack_canon_ace: no security info sent !\n"));
1957                 return False;
1958         }
1959
1960         /*
1961          * If no DACL then this is a chown only security descriptor.
1962          */
1963
1964         if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !psd->dacl)
1965                 return True;
1966
1967         /*
1968          * Now go through the DACL and create the canon_ace lists.
1969          */
1970
1971         if (!create_canon_ace_lists( fsp, pst, pfile_owner_sid, pfile_grp_sid,
1972                                                                 &file_ace, &dir_ace, psd->dacl))
1973                 return False;
1974
1975         if ((file_ace == NULL) && (dir_ace == NULL)) {
1976                 /* W2K traverse DACL set - ignore. */
1977                 return True;
1978         }
1979
1980         /*
1981          * Go through the canon_ace list and merge entries
1982          * belonging to identical users of identical allow or deny type.
1983          * We can do this as all deny entries come first, followed by
1984          * all allow entries (we have mandated this before accepting this acl).
1985          */
1986
1987         print_canon_ace_list( "file ace - before merge", file_ace);
1988         merge_aces( &file_ace );
1989
1990         print_canon_ace_list( "dir ace - before merge", dir_ace);
1991         merge_aces( &dir_ace );
1992
1993         /*
1994          * NT ACLs are order dependent. Go through the acl lists and
1995          * process DENY entries by masking the allow entries.
1996          */
1997
1998         print_canon_ace_list( "file ace - before deny", file_ace);
1999         process_deny_list( &file_ace);
2000
2001         print_canon_ace_list( "dir ace - before deny", dir_ace);
2002         process_deny_list( &dir_ace);
2003
2004         /*
2005          * A well formed POSIX file or default ACL has at least 3 entries, a 
2006          * SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ
2007          * and optionally a mask entry. Ensure this is the case.
2008          */
2009
2010         print_canon_ace_list( "file ace - before valid", file_ace);
2011
2012         /*
2013          * A default 3 element mode entry for a file should be r-- --- ---.
2014          * A default 3 element mode entry for a directory should be rwx --- ---.
2015          */
2016
2017         pst->st_mode = create_default_mode(fsp, False);
2018
2019         if (!ensure_canon_entry_valid(&file_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
2020                 free_canon_ace_list(file_ace);
2021                 free_canon_ace_list(dir_ace);
2022                 return False;
2023         }
2024
2025         print_canon_ace_list( "dir ace - before valid", dir_ace);
2026
2027         /*
2028          * A default inheritable 3 element mode entry for a directory should be the
2029          * mode Samba will use to create a file within. Ensure user rwx bits are set if
2030          * it's a directory.
2031          */
2032
2033         pst->st_mode = create_default_mode(fsp, True);
2034
2035         if (dir_ace && !ensure_canon_entry_valid(&dir_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
2036                 free_canon_ace_list(file_ace);
2037                 free_canon_ace_list(dir_ace);
2038                 return False;
2039         }
2040
2041         print_canon_ace_list( "file ace - return", file_ace);
2042         print_canon_ace_list( "dir ace - return", dir_ace);
2043
2044         *ppfile_ace = file_ace;
2045         *ppdir_ace = dir_ace;
2046         return True;
2047
2048 }
2049
2050 /******************************************************************************
2051  When returning permissions, try and fit NT display
2052  semantics if possible. Note the the canon_entries here must have been malloced.
2053  The list format should be - first entry = owner, followed by group and other user
2054  entries, last entry = other.
2055
2056  Note that this doesn't exactly match the NT semantics for an ACL. As POSIX entries
2057  are not ordered, and match on the most specific entry rather than walking a list,
2058  then a simple POSIX permission of rw-r--r-- should really map to 5 entries,
2059
2060  Entry 0: owner : deny all except read and write.
2061  Entry 1: owner : allow read and write.
2062  Entry 2: group : deny all except read.
2063  Entry 3: group : allow read.
2064  Entry 4: Everyone : allow read.
2065
2066  But NT cannot display this in their ACL editor !
2067 ********************************************************************************/
2068
2069 static void arrange_posix_perms( char *filename, canon_ace **pp_list_head)
2070 {
2071         canon_ace *list_head = *pp_list_head;
2072         canon_ace *owner_ace = NULL;
2073         canon_ace *other_ace = NULL;
2074         canon_ace *ace = NULL;
2075
2076         for (ace = list_head; ace; ace = ace->next) {
2077                 if (ace->type == SMB_ACL_USER_OBJ)
2078                         owner_ace = ace;
2079                 else if (ace->type == SMB_ACL_OTHER) {
2080                         /* Last ace - this is "other" */
2081                         other_ace = ace;
2082                 }
2083         }
2084                 
2085         if (!owner_ace || !other_ace) {
2086                 DEBUG(0,("arrange_posix_perms: Invalid POSIX permissions for file %s, missing owner or other.\n",
2087                         filename ));
2088                 return;
2089         }
2090
2091         /*
2092          * The POSIX algorithm applies to owner first, and other last,
2093          * so ensure they are arranged in this order.
2094          */
2095
2096         if (owner_ace) {
2097                 DLIST_PROMOTE(list_head, owner_ace);
2098         }
2099
2100         if (other_ace) {
2101                 DLIST_DEMOTE(list_head, other_ace, canon_ace *);
2102         }
2103
2104         /* We have probably changed the head of the list. */
2105
2106         *pp_list_head = list_head;
2107 }
2108                 
2109 /****************************************************************************
2110  Create a linked list of canonical ACE entries.
2111 ****************************************************************************/
2112
2113 static canon_ace *canonicalise_acl( const files_struct *fsp, SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf,
2114                                         const DOM_SID *powner, const DOM_SID *pgroup, struct pai_val *pal, SMB_ACL_TYPE_T the_acl_type)
2115 {
2116         connection_struct *conn = fsp->conn;
2117         mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR);
2118         canon_ace *list_head = NULL;
2119         canon_ace *ace = NULL;
2120         canon_ace *next_ace = NULL;
2121         int entry_id = SMB_ACL_FIRST_ENTRY;
2122         SMB_ACL_ENTRY_T entry;
2123         size_t ace_count;
2124
2125         while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
2126                 SMB_ACL_TAG_T tagtype;
2127                 SMB_ACL_PERMSET_T permset;
2128                 DOM_SID sid;
2129                 posix_id unix_ug;
2130                 enum ace_owner owner_type;
2131
2132                 /* get_next... */
2133                 if (entry_id == SMB_ACL_FIRST_ENTRY)
2134                         entry_id = SMB_ACL_NEXT_ENTRY;
2135
2136                 /* Is this a MASK entry ? */
2137                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
2138                         continue;
2139
2140                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
2141                         continue;
2142
2143                 /* Decide which SID to use based on the ACL type. */
2144                 switch(tagtype) {
2145                         case SMB_ACL_USER_OBJ:
2146                                 /* Get the SID from the owner. */
2147                                 sid_copy(&sid, powner);
2148                                 unix_ug.uid = psbuf->st_uid;
2149                                 owner_type = UID_ACE;
2150                                 break;
2151                         case SMB_ACL_USER:
2152                                 {
2153                                         uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
2154                                         if (puid == NULL) {
2155                                                 DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
2156                                                 continue;
2157                                         }
2158                                         /*
2159                                          * A SMB_ACL_USER entry for the owner is shadowed by the
2160                                          * SMB_ACL_USER_OBJ entry and Windows also cannot represent
2161                                          * that entry, so we ignore it. We also don't create such
2162                                          * entries out of the blue when setting ACLs, so a get/set
2163                                          * cycle will drop them.
2164                                          */
2165                                         if (the_acl_type == SMB_ACL_TYPE_ACCESS && *puid == psbuf->st_uid) {
2166                                                 SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
2167                                                 continue;
2168                                         }
2169                                         uid_to_sid( &sid, *puid);
2170                                         unix_ug.uid = *puid;
2171                                         owner_type = UID_ACE;
2172                                         SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
2173                                         break;
2174                                 }
2175                         case SMB_ACL_GROUP_OBJ:
2176                                 /* Get the SID from the owning group. */
2177                                 sid_copy(&sid, pgroup);
2178                                 unix_ug.gid = psbuf->st_gid;
2179                                 owner_type = GID_ACE;
2180                                 break;
2181                         case SMB_ACL_GROUP:
2182                                 {
2183                                         gid_t *pgid = (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
2184                                         if (pgid == NULL) {
2185                                                 DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
2186                                                 continue;
2187                                         }
2188                                         gid_to_sid( &sid, *pgid);
2189                                         unix_ug.gid = *pgid;
2190                                         owner_type = GID_ACE;
2191                                         SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)pgid,tagtype);
2192                                         break;
2193                                 }
2194                         case SMB_ACL_MASK:
2195                                 acl_mask = convert_permset_to_mode_t(conn, permset);
2196                                 continue; /* Don't count the mask as an entry. */
2197                         case SMB_ACL_OTHER:
2198                                 /* Use the Everyone SID */
2199                                 sid = global_sid_World;
2200                                 unix_ug.world = -1;
2201                                 owner_type = WORLD_ACE;
2202                                 break;
2203                         default:
2204                                 DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype));
2205                                 continue;
2206                 }
2207
2208                 /*
2209                  * Add this entry to the list.
2210                  */
2211
2212                 if ((ace = SMB_MALLOC_P(canon_ace)) == NULL)
2213                         goto fail;
2214
2215                 ZERO_STRUCTP(ace);
2216                 ace->type = tagtype;
2217                 ace->perms = convert_permset_to_mode_t(conn, permset);
2218                 ace->attr = ALLOW_ACE;
2219                 ace->trustee = sid;
2220                 ace->unix_ug = unix_ug;
2221                 ace->owner_type = owner_type;
2222                 ace->inherited = get_inherited_flag(pal, ace, (the_acl_type == SMB_ACL_TYPE_DEFAULT));
2223
2224                 DLIST_ADD(list_head, ace);
2225         }
2226
2227         /*
2228          * This next call will ensure we have at least a user/group/world set.
2229          */
2230
2231         if (!ensure_canon_entry_valid(&list_head, fsp, powner, pgroup, psbuf, False))
2232                 goto fail;
2233
2234         /*
2235          * Now go through the list, masking the permissions with the
2236          * acl_mask. Ensure all DENY Entries are at the start of the list.
2237          */
2238
2239         DEBUG(10,("canonicalise_acl: %s ace entries before arrange :\n", the_acl_type == SMB_ACL_TYPE_ACCESS ? "Access" : "Default" ));
2240
2241         for ( ace_count = 0, ace = list_head; ace; ace = next_ace, ace_count++) {
2242                 next_ace = ace->next;
2243
2244                 /* Masks are only applied to entries other than USER_OBJ and OTHER. */
2245                 if (ace->type != SMB_ACL_OTHER && ace->type != SMB_ACL_USER_OBJ)
2246                         ace->perms &= acl_mask;
2247
2248                 if (ace->perms == 0) {
2249                         DLIST_PROMOTE(list_head, ace);
2250                 }
2251
2252                 if( DEBUGLVL( 10 ) ) {
2253                         print_canon_ace(ace, ace_count);
2254                 }
2255         }
2256
2257         arrange_posix_perms(fsp->fsp_name,&list_head );
2258
2259         print_canon_ace_list( "canonicalise_acl: ace entries after arrange", list_head );
2260
2261         return list_head;
2262
2263   fail:
2264
2265         free_canon_ace_list(list_head);
2266         return NULL;
2267 }
2268
2269 /****************************************************************************
2270  Check if the current user group list contains a given group.
2271 ****************************************************************************/
2272
2273 static BOOL current_user_in_group(gid_t gid)
2274 {
2275         int i;
2276
2277         for (i = 0; i < current_user.ut.ngroups; i++) {
2278                 if (current_user.ut.groups[i] == gid) {
2279                         return True;
2280                 }
2281         }
2282
2283         return False;
2284 }
2285
2286 /****************************************************************************
2287  Should we override a deny ?  Check deprecated 'acl group control'
2288  and 'dos filemode'
2289 ****************************************************************************/
2290
2291 static BOOL acl_group_override(connection_struct *conn, gid_t prim_gid)
2292 {
2293         if ( (errno == EACCES || errno == EPERM) 
2294                 && (lp_acl_group_control(SNUM(conn)) || lp_dos_filemode(SNUM(conn)))
2295                 && current_user_in_group(prim_gid)) 
2296         {
2297                 return True;
2298         } 
2299
2300         return False;
2301 }
2302
2303 /****************************************************************************
2304  Attempt to apply an ACL to a file or directory.
2305 ****************************************************************************/
2306
2307 static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL default_ace, gid_t prim_gid, BOOL *pacl_set_support)
2308 {
2309         connection_struct *conn = fsp->conn;
2310         BOOL ret = False;
2311         SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, (int)count_canon_ace_list(the_ace) + 1);
2312         canon_ace *p_ace;
2313         int i;
2314         SMB_ACL_ENTRY_T mask_entry;
2315         BOOL got_mask_entry = False;
2316         SMB_ACL_PERMSET_T mask_permset;
2317         SMB_ACL_TYPE_T the_acl_type = (default_ace ? SMB_ACL_TYPE_DEFAULT : SMB_ACL_TYPE_ACCESS);
2318         BOOL needs_mask = False;
2319         mode_t mask_perms = 0;
2320
2321 #if defined(POSIX_ACL_NEEDS_MASK)
2322         /* HP-UX always wants to have a mask (called "class" there). */
2323         needs_mask = True;
2324 #endif
2325
2326         if (the_acl == NULL) {
2327
2328                 if (!no_acl_syscall_error(errno)) {
2329                         /*
2330                          * Only print this error message if we have some kind of ACL
2331                          * support that's not working. Otherwise we would always get this.
2332                          */
2333                         DEBUG(0,("set_canon_ace_list: Unable to init %s ACL. (%s)\n",
2334                                 default_ace ? "default" : "file", strerror(errno) ));
2335                 }
2336                 *pacl_set_support = False;
2337                 return False;
2338         }
2339
2340         if( DEBUGLVL( 10 )) {
2341                 dbgtext("set_canon_ace_list: setting ACL:\n");
2342                 for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
2343                         print_canon_ace( p_ace, i);
2344                 }
2345         }
2346
2347         for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
2348                 SMB_ACL_ENTRY_T the_entry;
2349                 SMB_ACL_PERMSET_T the_permset;
2350
2351                 /*
2352                  * ACLs only "need" an ACL_MASK entry if there are any named user or
2353                  * named group entries. But if there is an ACL_MASK entry, it applies
2354                  * to ACL_USER, ACL_GROUP, and ACL_GROUP_OBJ entries. Set the mask
2355                  * so that it doesn't deny (i.e., mask off) any permissions.
2356                  */
2357
2358                 if (p_ace->type == SMB_ACL_USER || p_ace->type == SMB_ACL_GROUP) {
2359                         needs_mask = True;
2360                         mask_perms |= p_ace->perms;
2361                 } else if (p_ace->type == SMB_ACL_GROUP_OBJ) {
2362                         mask_perms |= p_ace->perms;
2363                 }
2364
2365                 /*
2366                  * Get the entry for this ACE.
2367                  */
2368
2369                 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) {
2370                         DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n",
2371                                 i, strerror(errno) ));
2372                         goto fail;
2373                 }
2374
2375                 if (p_ace->type == SMB_ACL_MASK) {
2376                         mask_entry = the_entry;
2377                         got_mask_entry = True;
2378                 }
2379
2380                 /*
2381                  * Ok - we now know the ACL calls should be working, don't
2382                  * allow fallback to chmod.
2383                  */
2384
2385                 *pacl_set_support = True;
2386
2387                 /*
2388                  * Initialise the entry from the canon_ace.
2389                  */
2390
2391                 /*
2392                  * First tell the entry what type of ACE this is.
2393                  */
2394
2395                 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, p_ace->type) == -1) {
2396                         DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n",
2397                                 i, strerror(errno) ));
2398                         goto fail;
2399                 }
2400
2401                 /*
2402                  * Only set the qualifier (user or group id) if the entry is a user
2403                  * or group id ACE.
2404                  */
2405
2406                 if ((p_ace->type == SMB_ACL_USER) || (p_ace->type == SMB_ACL_GROUP)) {
2407                         if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&p_ace->unix_ug.uid) == -1) {
2408                                 DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n",
2409                                         i, strerror(errno) ));
2410                                 goto fail;
2411                         }
2412                 }
2413
2414                 /*
2415                  * Convert the mode_t perms in the canon_ace to a POSIX permset.
2416                  */
2417
2418                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) {
2419                         DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n",
2420                                 i, strerror(errno) ));
2421                         goto fail;
2422                 }
2423
2424                 if (map_acl_perms_to_permset(conn, p_ace->perms, &the_permset) == -1) {
2425                         DEBUG(0,("set_canon_ace_list: Failed to create permset for mode (%u) on entry %d. (%s)\n",
2426                                 (unsigned int)p_ace->perms, i, strerror(errno) ));
2427                         goto fail;
2428                 }
2429
2430                 /*
2431                  * ..and apply them to the entry.
2432                  */
2433
2434                 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) {
2435                         DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n",
2436                                 i, strerror(errno) ));
2437                         goto fail;
2438                 }
2439
2440                 if( DEBUGLVL( 10 ))
2441                         print_canon_ace( p_ace, i);
2442
2443         }
2444
2445         if (needs_mask && !got_mask_entry) {
2446                 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &mask_entry) == -1) {
2447                         DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) ));
2448                         goto fail;
2449                 }
2450
2451                 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, mask_entry, SMB_ACL_MASK) == -1) {
2452                         DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno) ));
2453                         goto fail;
2454                 }
2455
2456                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, mask_entry, &mask_permset) == -1) {
2457                         DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) ));
2458                         goto fail;
2459                 }
2460
2461                 if (map_acl_perms_to_permset(conn, S_IRUSR|S_IWUSR|S_IXUSR, &mask_permset) == -1) {
2462                         DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno) ));
2463                         goto fail;
2464                 }
2465
2466                 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, mask_entry, mask_permset) == -1) {
2467                         DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) ));
2468                         goto fail;
2469                 }
2470         }
2471
2472         /*
2473          * Finally apply it to the file or directory.
2474          */
2475
2476         if(default_ace || fsp->is_directory || fsp->fh->fd == -1) {
2477                 if (SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name, the_acl_type, the_acl) == -1) {
2478                         /*
2479                          * Some systems allow all the above calls and only fail with no ACL support
2480                          * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
2481                          */
2482                         if (no_acl_syscall_error(errno)) {
2483                                 *pacl_set_support = False;
2484                         }
2485
2486                         if (acl_group_override(conn, prim_gid)) {
2487                                 int sret;
2488
2489                                 DEBUG(5,("set_canon_ace_list: acl group control on and current user in file %s primary group.\n",
2490                                         fsp->fsp_name ));
2491
2492                                 become_root();
2493                                 sret = SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name, the_acl_type, the_acl);
2494                                 unbecome_root();
2495                                 if (sret == 0) {
2496                                         ret = True;     
2497                                 }
2498                         }
2499
2500                         if (ret == False) {
2501                                 DEBUG(2,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n",
2502                                                 the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
2503                                                 fsp->fsp_name, strerror(errno) ));
2504                                 goto fail;
2505                         }
2506                 }
2507         } else {
2508                 if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fh->fd, the_acl) == -1) {
2509                         /*
2510                          * Some systems allow all the above calls and only fail with no ACL support
2511                          * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
2512                          */
2513                         if (no_acl_syscall_error(errno)) {
2514                                 *pacl_set_support = False;
2515                         }
2516
2517                         if (acl_group_override(conn, prim_gid)) {
2518                                 int sret;
2519
2520                                 DEBUG(5,("set_canon_ace_list: acl group control on and current user in file %s primary group.\n",
2521                                         fsp->fsp_name ));
2522
2523                                 become_root();
2524                                 sret = SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fh->fd, the_acl);
2525                                 unbecome_root();
2526                                 if (sret == 0) {
2527                                         ret = True;
2528                                 }
2529                         }
2530
2531                         if (ret == False) {
2532                                 DEBUG(2,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n",
2533                                                 fsp->fsp_name, strerror(errno) ));
2534                                 goto fail;
2535                         }
2536                 }
2537         }
2538
2539         ret = True;
2540
2541   fail:
2542
2543         if (the_acl != NULL) {
2544                 SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
2545         }
2546
2547         return ret;
2548 }
2549
2550 /****************************************************************************
2551  Find a particular canon_ace entry.
2552 ****************************************************************************/
2553
2554 static struct canon_ace *canon_ace_entry_for(struct canon_ace *list, SMB_ACL_TAG_T type, posix_id *id)
2555 {
2556         while (list) {
2557                 if (list->type == type && ((type != SMB_ACL_USER && type != SMB_ACL_GROUP) ||
2558                                 (type == SMB_ACL_USER  && id && id->uid == list->unix_ug.uid) ||
2559                                 (type == SMB_ACL_GROUP && id && id->gid == list->unix_ug.gid)))
2560                         break;
2561                 list = list->next;
2562         }
2563         return list;
2564 }
2565
2566 /****************************************************************************
2567  
2568 ****************************************************************************/
2569
2570 SMB_ACL_T free_empty_sys_acl(connection_struct *conn, SMB_ACL_T the_acl)
2571 {
2572         SMB_ACL_ENTRY_T entry;
2573
2574         if (!the_acl)
2575                 return NULL;
2576         if (SMB_VFS_SYS_ACL_GET_ENTRY(conn, the_acl, SMB_ACL_FIRST_ENTRY, &entry) != 1) {
2577                 SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
2578                 return NULL;
2579         }
2580         return the_acl;
2581 }
2582
2583 /****************************************************************************
2584  Convert a canon_ace to a generic 3 element permission - if possible.
2585 ****************************************************************************/
2586
2587 #define MAP_PERM(p,mask,result) (((p) & (mask)) ? (result) : 0 )
2588
2589 static BOOL convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file_ace_list, mode_t *posix_perms)
2590 {
2591         int snum = SNUM(fsp->conn);
2592         size_t ace_count = count_canon_ace_list(file_ace_list);
2593         canon_ace *ace_p;
2594         canon_ace *owner_ace = NULL;
2595         canon_ace *group_ace = NULL;
2596         canon_ace *other_ace = NULL;
2597         mode_t and_bits;
2598         mode_t or_bits;
2599
2600         if (ace_count != 3) {
2601                 DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE entries for file %s to convert to \
2602 posix perms.\n", fsp->fsp_name ));
2603                 return False;
2604         }
2605
2606         for (ace_p = file_ace_list; ace_p; ace_p = ace_p->next) {
2607                 if (ace_p->owner_type == UID_ACE)
2608                         owner_ace = ace_p;
2609                 else if (ace_p->owner_type == GID_ACE)
2610                         group_ace = ace_p;
2611                 else if (ace_p->owner_type == WORLD_ACE)
2612                         other_ace = ace_p;
2613         }
2614
2615         if (!owner_ace || !group_ace || !other_ace) {
2616                 DEBUG(3,("convert_canon_ace_to_posix_perms: Can't get standard entries for file %s.\n",
2617                                 fsp->fsp_name ));
2618                 return False;
2619         }
2620
2621         *posix_perms = (mode_t)0;
2622
2623         *posix_perms |= owner_ace->perms;
2624         *posix_perms |= MAP_PERM(group_ace->perms, S_IRUSR, S_IRGRP);
2625         *posix_perms |= MAP_PERM(group_ace->perms, S_IWUSR, S_IWGRP);
2626         *posix_perms |= MAP_PERM(group_ace->perms, S_IXUSR, S_IXGRP);
2627         *posix_perms |= MAP_PERM(other_ace->perms, S_IRUSR, S_IROTH);
2628         *posix_perms |= MAP_PERM(other_ace->perms, S_IWUSR, S_IWOTH);
2629         *posix_perms |= MAP_PERM(other_ace->perms, S_IXUSR, S_IXOTH);
2630
2631         /* The owner must have at least read access. */
2632
2633         *posix_perms |= S_IRUSR;
2634         if (fsp->is_directory)
2635                 *posix_perms |= (S_IWUSR|S_IXUSR);
2636
2637         /* If requested apply the masks. */
2638
2639         /* Get the initial bits to apply. */
2640
2641         if (fsp->is_directory) {
2642                 and_bits = lp_dir_security_mask(snum);
2643                 or_bits = lp_force_dir_security_mode(snum);
2644         } else {
2645                 and_bits = lp_security_mask(snum);
2646                 or_bits = lp_force_security_mode(snum);
2647         }
2648
2649         *posix_perms = (((*posix_perms) & and_bits)|or_bits);
2650
2651         DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o to perm=0%o for file %s.\n",
2652                 (int)owner_ace->perms, (int)group_ace->perms, (int)other_ace->perms, (int)*posix_perms,
2653                 fsp->fsp_name ));
2654
2655         return True;
2656 }
2657
2658 /****************************************************************************
2659   Incoming NT ACLs on a directory can be split into a default POSIX acl (CI|OI|IO) and
2660   a normal POSIX acl. Win2k needs these split acls re-merging into one ACL
2661   with CI|OI set so it is inherited and also applies to the directory.
2662   Based on code from "Jim McDonough" <jmcd@us.ibm.com>.
2663 ****************************************************************************/
2664
2665 static size_t merge_default_aces( SEC_ACE *nt_ace_list, size_t num_aces)
2666 {
2667         size_t i, j;
2668
2669         for (i = 0; i < num_aces; i++) {
2670                 for (j = i+1; j < num_aces; j++) {
2671                         uint32 i_flags_ni = (nt_ace_list[i].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
2672                         uint32 j_flags_ni = (nt_ace_list[j].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
2673                         BOOL i_inh = (nt_ace_list[i].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
2674                         BOOL j_inh = (nt_ace_list[j].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
2675
2676                         /* We know the lower number ACE's are file entries. */
2677                         if ((nt_ace_list[i].type == nt_ace_list[j].type) &&
2678                                 (nt_ace_list[i].size == nt_ace_list[j].size) &&
2679                                 (nt_ace_list[i].access_mask == nt_ace_list[j].access_mask) &&
2680                                 sid_equal(&nt_ace_list[i].trustee, &nt_ace_list[j].trustee) &&
2681                                 (i_inh == j_inh) &&
2682                                 (i_flags_ni == 0) &&
2683                                 (j_flags_ni == (SEC_ACE_FLAG_OBJECT_INHERIT|
2684                                                   SEC_ACE_FLAG_CONTAINER_INHERIT|
2685                                                   SEC_ACE_FLAG_INHERIT_ONLY))) {
2686                                 /*
2687                                  * W2K wants to have access allowed zero access ACE's
2688                                  * at the end of the list. If the mask is zero, merge
2689                                  * the non-inherited ACE onto the inherited ACE.
2690                                  */
2691
2692                                 if (nt_ace_list[i].access_mask == 0) {
2693                                         nt_ace_list[j].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2694                                                                 (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2695                                         if (num_aces - i - 1 > 0)
2696                                                 memmove(&nt_ace_list[i], &nt_ace_list[i+1], (num_aces-i-1) *
2697                                                                 sizeof(SEC_ACE));
2698
2699                                         DEBUG(10,("merge_default_aces: Merging zero access ACE %u onto ACE %u.\n",
2700                                                 (unsigned int)i, (unsigned int)j ));
2701                                 } else {
2702                                         /*
2703                                          * These are identical except for the flags.
2704                                          * Merge the inherited ACE onto the non-inherited ACE.
2705                                          */
2706
2707                                         nt_ace_list[i].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2708                                                                 (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2709                                         if (num_aces - j - 1 > 0)
2710                                                 memmove(&nt_ace_list[j], &nt_ace_list[j+1], (num_aces-j-1) *
2711                                                                 sizeof(SEC_ACE));
2712
2713                                         DEBUG(10,("merge_default_aces: Merging ACE %u onto ACE %u.\n",
2714                                                 (unsigned int)j, (unsigned int)i ));
2715                                 }
2716                                 num_aces--;
2717                                 break;
2718                         }
2719                 }
2720         }
2721
2722         return num_aces;
2723 }
2724 /****************************************************************************
2725  Reply to query a security descriptor from an fsp. If it succeeds it allocates
2726  the space for the return elements and returns the size needed to return the
2727  security descriptor. This should be the only external function needed for
2728  the UNIX style get ACL.
2729 ****************************************************************************/
2730
2731 size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc)
2732 {
2733         connection_struct *conn = fsp->conn;
2734         SMB_STRUCT_STAT sbuf;
2735         SEC_ACE *nt_ace_list = NULL;
2736         DOM_SID owner_sid;
2737         DOM_SID group_sid;
2738         size_t sd_size = 0;
2739         SEC_ACL *psa = NULL;
2740         size_t num_acls = 0;
2741         size_t num_def_acls = 0;
2742         size_t num_aces = 0;
2743         SMB_ACL_T posix_acl = NULL;
2744         SMB_ACL_T def_acl = NULL;
2745         canon_ace *file_ace = NULL;
2746         canon_ace *dir_ace = NULL;
2747         size_t num_profile_acls = 0;
2748         struct pai_val *pal = NULL;
2749         SEC_DESC *psd = NULL;
2750
2751         *ppdesc = NULL;
2752
2753         DEBUG(10,("get_nt_acl: called for file %s\n", fsp->fsp_name ));
2754
2755         if(fsp->is_directory || fsp->fh->fd == -1) {
2756
2757                 /* Get the stat struct for the owner info. */
2758                 if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) {
2759                         return 0;
2760                 }
2761                 /*
2762                  * Get the ACL from the path.
2763                  */
2764
2765                 posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_ACCESS);
2766
2767                 /*
2768                  * If it's a directory get the default POSIX ACL.
2769                  */
2770
2771                 if(fsp->is_directory) {
2772                         def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_DEFAULT);
2773                         def_acl = free_empty_sys_acl(conn, def_acl);
2774                 }
2775
2776         } else {
2777
2778                 /* Get the stat struct for the owner info. */
2779                 if(SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf) != 0) {
2780                         return 0;
2781                 }
2782                 /*
2783                  * Get the ACL from the fd.
2784                  */
2785                 posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fh->fd);
2786         }
2787
2788         DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n",
2789                         posix_acl ? "present" :  "absent",
2790                         def_acl ? "present" :  "absent" ));
2791
2792         pal = load_inherited_info(fsp);
2793
2794         /*
2795          * Get the owner, group and world SIDs.
2796          */
2797
2798         if (lp_profile_acls(SNUM(conn))) {
2799                 /* For WXP SP1 the owner must be administrators. */
2800                 sid_copy(&owner_sid, &global_sid_Builtin_Administrators);
2801                 sid_copy(&group_sid, &global_sid_Builtin_Users);
2802                 num_profile_acls = 2;
2803         } else {
2804                 create_file_sids(&sbuf, &owner_sid, &group_sid);
2805         }
2806
2807         if ((security_info & DACL_SECURITY_INFORMATION) && !(security_info & PROTECTED_DACL_SECURITY_INFORMATION)) {
2808
2809                 /*
2810                  * In the optimum case Creator Owner and Creator Group would be used for
2811                  * the ACL_USER_OBJ and ACL_GROUP_OBJ entries, respectively, but this
2812                  * would lead to usability problems under Windows: The Creator entries
2813                  * are only available in browse lists of directories and not for files;
2814                  * additionally the identity of the owning group couldn't be determined.
2815                  * We therefore use those identities only for Default ACLs. 
2816                  */
2817
2818                 /* Create the canon_ace lists. */
2819                 file_ace = canonicalise_acl( fsp, posix_acl, &sbuf, &owner_sid, &group_sid, pal, SMB_ACL_TYPE_ACCESS );
2820
2821                 /* We must have *some* ACLS. */
2822         
2823                 if (count_canon_ace_list(file_ace) == 0) {
2824                         DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", fsp->fsp_name ));
2825                         goto done;
2826                 }
2827
2828                 if (fsp->is_directory && def_acl) {
2829                         dir_ace = canonicalise_acl(fsp, def_acl, &sbuf,
2830                                         &global_sid_Creator_Owner,
2831                                         &global_sid_Creator_Group, pal, SMB_ACL_TYPE_DEFAULT );
2832                 }
2833
2834                 /*
2835                  * Create the NT ACE list from the canonical ace lists.
2836                  */
2837
2838                 {
2839                         canon_ace *ace;
2840                         int nt_acl_type;
2841                         int i;
2842
2843                         if (nt4_compatible_acls() && dir_ace) {
2844                                 /*
2845                                  * NT 4 chokes if an ACL contains an INHERIT_ONLY entry
2846                                  * but no non-INHERIT_ONLY entry for one SID. So we only
2847                                  * remove entries from the Access ACL if the
2848                                  * corresponding Default ACL entries have also been
2849                                  * removed. ACEs for CREATOR-OWNER and CREATOR-GROUP
2850                                  * are exceptions. We can do nothing
2851                                  * intelligent if the Default ACL contains entries that
2852                                  * are not also contained in the Access ACL, so this
2853                                  * case will still fail under NT 4.
2854                                  */
2855
2856                                 ace = canon_ace_entry_for(dir_ace, SMB_ACL_OTHER, NULL);
2857                                 if (ace && !ace->perms) {
2858                                         DLIST_REMOVE(dir_ace, ace);
2859                                         SAFE_FREE(ace);
2860
2861                                         ace = canon_ace_entry_for(file_ace, SMB_ACL_OTHER, NULL);
2862                                         if (ace && !ace->perms) {
2863                                                 DLIST_REMOVE(file_ace, ace);
2864                                                 SAFE_FREE(ace);
2865                                         }
2866                                 }
2867
2868                                 /*
2869                                  * WinNT doesn't usually have Creator Group
2870                                  * in browse lists, so we send this entry to
2871                                  * WinNT even if it contains no relevant
2872                                  * permissions. Once we can add
2873                                  * Creator Group to browse lists we can
2874                                  * re-enable this.
2875                                  */
2876
2877 #if 0
2878                                 ace = canon_ace_entry_for(dir_ace, SMB_ACL_GROUP_OBJ, NULL);
2879                                 if (ace && !ace->perms) {
2880                                         DLIST_REMOVE(dir_ace, ace);
2881                                         SAFE_FREE(ace);
2882                                 }
2883 #endif
2884
2885                                 ace = canon_ace_entry_for(file_ace, SMB_ACL_GROUP_OBJ, NULL);
2886                                 if (ace && !ace->perms) {
2887                                         DLIST_REMOVE(file_ace, ace);
2888                                         SAFE_FREE(ace);
2889                                 }
2890                         }
2891
2892                         num_acls = count_canon_ace_list(file_ace);
2893                         num_def_acls = count_canon_ace_list(dir_ace);
2894
2895                         /* Allocate the ace list. */
2896                         if ((nt_ace_list = SMB_MALLOC_ARRAY(SEC_ACE,num_acls + num_profile_acls + num_def_acls)) == NULL) {
2897                                 DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
2898                                 goto done;
2899                         }
2900
2901                         memset(nt_ace_list, '\0', (num_acls + num_def_acls) * sizeof(SEC_ACE) );
2902
2903                         /*
2904                          * Create the NT ACE list from the canonical ace lists.
2905                          */
2906
2907                         ace = file_ace;
2908
2909                         for (i = 0; i < num_acls; i++, ace = ace->next) {
2910                                 SEC_ACCESS acc;
2911
2912                                 acc = map_canon_ace_perms(SNUM(conn),
2913                                                 &nt_acl_type,
2914                                                 ace->perms,
2915                                                 fsp->is_directory);
2916                                 init_sec_ace(&nt_ace_list[num_aces++],
2917                                         &ace->trustee,
2918                                         nt_acl_type,
2919                                         acc,
2920                                         ace->inherited ?
2921                                                 SEC_ACE_FLAG_INHERITED_ACE : 0);
2922                         }
2923
2924                         /* The User must have access to a profile share - even
2925                          * if we can't map the SID. */
2926                         if (lp_profile_acls(SNUM(conn))) {
2927                                 SEC_ACCESS acc;
2928
2929                                 init_sec_access(&acc,FILE_GENERIC_ALL);
2930                                 init_sec_ace(&nt_ace_list[num_aces++],
2931                                                 &global_sid_Builtin_Users,
2932                                                 SEC_ACE_TYPE_ACCESS_ALLOWED,
2933                                                 acc, 0);
2934                         }
2935
2936                         ace = dir_ace;
2937
2938                         for (i = 0; i < num_def_acls; i++, ace = ace->next) {
2939                                 SEC_ACCESS acc;
2940
2941                                 acc = map_canon_ace_perms(SNUM(conn),
2942                                                 &nt_acl_type,
2943                                                 ace->perms,
2944                                                 fsp->is_directory);
2945                                 init_sec_ace(&nt_ace_list[num_aces++],
2946                                         &ace->trustee,
2947                                         nt_acl_type,
2948                                         acc,
2949                                         SEC_ACE_FLAG_OBJECT_INHERIT|
2950                                         SEC_ACE_FLAG_CONTAINER_INHERIT|
2951                                         SEC_ACE_FLAG_INHERIT_ONLY|
2952                                         (ace->inherited ?
2953                                            SEC_ACE_FLAG_INHERITED_ACE : 0));
2954                         }
2955
2956                         /* The User must have access to a profile share - even
2957                          * if we can't map the SID. */
2958                         if (lp_profile_acls(SNUM(conn))) {
2959                                 SEC_ACCESS acc;
2960
2961                                 init_sec_access(&acc,FILE_GENERIC_ALL);
2962                                 init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, acc,
2963                                                 SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2964                                                 SEC_ACE_FLAG_INHERIT_ONLY|0);
2965                         }
2966
2967                         /*
2968                          * Merge POSIX default ACLs and normal ACLs into one NT ACE.
2969                          * Win2K needs this to get the inheritance correct when replacing ACLs
2970                          * on a directory tree. Based on work by Jim @ IBM.
2971                          */
2972
2973                         num_aces = merge_default_aces(nt_ace_list, num_aces);
2974
2975                 }
2976
2977                 if (num_aces) {
2978                         if((psa = make_sec_acl( talloc_tos(), NT4_ACL_REVISION, num_aces, nt_ace_list)) == NULL) {
2979                                 DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
2980                                 goto done;
2981                         }
2982                 }
2983         } /* security_info & DACL_SECURITY_INFORMATION */
2984
2985         psd = make_standard_sec_desc( talloc_tos(),
2986                         (security_info & OWNER_SECURITY_INFORMATION) ? &owner_sid : NULL,
2987                         (security_info & GROUP_SECURITY_INFORMATION) ? &group_sid : NULL,
2988                         psa,
2989                         &sd_size);
2990
2991         if(!psd) {
2992                 DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
2993                 sd_size = 0;
2994                 goto done;
2995         }
2996