Implemented default ACL patch (set inherit acls = true on a per share basis).
[ira/wip.git] / source / smbd / posix_acls.c
1 /*
2    Unix SMB/CIFS implementation.
3    SMB NT Security Descriptor / Unix permission conversion.
4    Copyright (C) Jeremy Allison 1994-2000
5
6    This program is free software; you can redistribute it and/or modify
7    it under the terms of the GNU General Public License as published by
8    the Free Software Foundation; either version 2 of the License, or
9    (at your option) any later version.
10
11    This program is distributed in the hope that it will be useful,
12    but WITHOUT ANY WARRANTY; without even the implied warranty of
13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14    GNU General Public License for more details.
15
16    You should have received a copy of the GNU General Public License
17    along with this program; if not, write to the Free Software
18    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19 */
20
21 #include "includes.h"
22
23 /****************************************************************************
24  Data structures representing the internal ACE format.
25 ****************************************************************************/
26
27 enum ace_owner {UID_ACE, GID_ACE, WORLD_ACE};
28 enum ace_attribute {ALLOW_ACE, DENY_ACE}; /* Used for incoming NT ACLS. */
29
30 typedef union posix_id {
31                 uid_t uid;
32                 gid_t gid;
33                 int world;
34 } posix_id;
35
36 typedef struct canon_ace {
37         struct canon_ace *next, *prev;
38         SMB_ACL_TAG_T type;
39         mode_t perms; /* Only use S_I(R|W|X)USR mode bits here. */
40         DOM_SID trustee;
41         enum ace_owner owner_type;
42         enum ace_attribute attr;
43         posix_id unix_ug; 
44 } canon_ace;
45
46 #define ALL_ACE_PERMS (S_IRUSR|S_IWUSR|S_IXUSR)
47
48 /****************************************************************************
49  Functions to manipulate the internal ACE format.
50 ****************************************************************************/
51
52 /****************************************************************************
53  Count a linked list of canonical ACE entries.
54 ****************************************************************************/
55
56 static size_t count_canon_ace_list( canon_ace *list_head )
57 {
58         size_t count = 0;
59         canon_ace *ace;
60
61         for (ace = list_head; ace; ace = ace->next)
62                 count++;
63
64         return count;
65 }
66
67 /****************************************************************************
68  Free a linked list of canonical ACE entries.
69 ****************************************************************************/
70
71 static void free_canon_ace_list( canon_ace *list_head )
72 {
73         while (list_head) {
74                 canon_ace *old_head = list_head;
75                 DLIST_REMOVE(list_head, list_head);
76                 SAFE_FREE(old_head);
77         }
78 }
79
80 /****************************************************************************
81  Function to duplicate a canon_ace entry.
82 ****************************************************************************/
83
84 static canon_ace *dup_canon_ace( canon_ace *src_ace)
85 {
86         canon_ace *dst_ace = (canon_ace *)malloc(sizeof(canon_ace));
87
88         if (dst_ace == NULL)
89                 return NULL;
90
91         *dst_ace = *src_ace;
92         dst_ace->prev = dst_ace->next = NULL;
93         return dst_ace;
94 }
95
96 /****************************************************************************
97  Print out a canon ace.
98 ****************************************************************************/
99
100 static void print_canon_ace(canon_ace *pace, int num)
101 {
102         fstring str;
103
104         dbgtext( "canon_ace index %d. Type = %s ", num, pace->attr == ALLOW_ACE ? "allow" : "deny" );
105         dbgtext( "SID = %s ", sid_to_string( str, &pace->trustee));
106         if (pace->owner_type == UID_ACE) {
107                 char *u_name = uidtoname(pace->unix_ug.uid);
108                 dbgtext( "uid %u (%s) ", (unsigned int)pace->unix_ug.uid, u_name);
109         } else if (pace->owner_type == GID_ACE) {
110                 char *g_name = gidtoname(pace->unix_ug.gid);
111                 dbgtext( "gid %u (%s) ", (unsigned int)pace->unix_ug.gid, g_name);
112         } else
113                 dbgtext( "other ");
114         switch (pace->type) {
115                 case SMB_ACL_USER:
116                         dbgtext( "SMB_ACL_USER ");
117                         break;
118                 case SMB_ACL_USER_OBJ:
119                         dbgtext( "SMB_ACL_USER_OBJ ");
120                         break;
121                 case SMB_ACL_GROUP:
122                         dbgtext( "SMB_ACL_GROUP ");
123                         break;
124                 case SMB_ACL_GROUP_OBJ:
125                         dbgtext( "SMB_ACL_GROUP_OBJ ");
126                         break;
127                 case SMB_ACL_OTHER:
128                         dbgtext( "SMB_ACL_OTHER ");
129                         break;
130         }
131         dbgtext( "perms ");
132         dbgtext( "%c", pace->perms & S_IRUSR ? 'r' : '-');
133         dbgtext( "%c", pace->perms & S_IWUSR ? 'w' : '-');
134         dbgtext( "%c\n", pace->perms & S_IXUSR ? 'x' : '-');
135 }
136
137 /****************************************************************************
138  Print out a canon ace list.
139 ****************************************************************************/
140
141 static void print_canon_ace_list(const char *name, canon_ace *ace_list)
142 {
143         int count = 0;
144
145         if( DEBUGLVL( 10 )) {
146                 dbgtext( "print_canon_ace_list: %s\n", name );
147                 for (;ace_list; ace_list = ace_list->next, count++)
148                         print_canon_ace(ace_list, count );
149         }
150 }
151
152 /****************************************************************************
153  Map POSIX ACL perms to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
154 ****************************************************************************/
155
156 static mode_t convert_permset_to_mode_t(SMB_ACL_PERMSET_T permset)
157 {
158         mode_t ret = 0;
159
160         ret |= (sys_acl_get_perm(permset, SMB_ACL_READ) ? S_IRUSR : 0);
161         ret |= (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? S_IWUSR : 0);
162         ret |= (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? S_IXUSR : 0);
163
164         return ret;
165 }
166
167 /****************************************************************************
168  Map generic UNIX permissions to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
169 ****************************************************************************/
170
171 static mode_t unix_perms_to_acl_perms(mode_t mode, int r_mask, int w_mask, int x_mask)
172 {
173         mode_t ret = 0;
174
175         if (mode & r_mask)
176                 ret |= S_IRUSR;
177         if (mode & w_mask)
178                 ret |= S_IWUSR;
179         if (mode & x_mask)
180                 ret |= S_IXUSR;
181
182         return ret;
183 }
184
185 /****************************************************************************
186  Map canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits) to
187  an SMB_ACL_PERMSET_T.
188 ****************************************************************************/
189
190 static int map_acl_perms_to_permset(mode_t mode, SMB_ACL_PERMSET_T *p_permset)
191 {
192         if (sys_acl_clear_perms(*p_permset) ==  -1)
193                 return -1;
194         if (mode & S_IRUSR) {
195                 if (sys_acl_add_perm(*p_permset, SMB_ACL_READ) == -1)
196                         return -1;
197         }
198         if (mode & S_IWUSR) {
199                 if (sys_acl_add_perm(*p_permset, SMB_ACL_WRITE) == -1)
200                         return -1;
201         }
202         if (mode & S_IXUSR) {
203                 if (sys_acl_add_perm(*p_permset, SMB_ACL_EXECUTE) == -1)
204                         return -1;
205         }
206         return 0;
207 }
208 /****************************************************************************
209  Function to create owner and group SIDs from a SMB_STRUCT_STAT.
210 ****************************************************************************/
211
212 static void create_file_sids(SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SID *pgroup_sid)
213 {
214         uid_to_sid( powner_sid, psbuf->st_uid );
215         gid_to_sid( pgroup_sid, psbuf->st_gid );
216 }
217
218 /****************************************************************************
219  Merge aces with a common sid - if both are allow or deny, OR the permissions together and
220  delete the second one. If the first is deny, mask the permissions off and delete the allow
221  if the permissions become zero, delete the deny if the permissions are non zero.
222 ****************************************************************************/
223
224 static void merge_aces( canon_ace **pp_list_head )
225 {
226         canon_ace *list_head = *pp_list_head;
227         canon_ace *curr_ace_outer;
228         canon_ace *curr_ace_outer_next;
229
230         /*
231          * First, merge allow entries with identical SIDs, and deny entries
232          * with identical SIDs.
233          */
234
235         for (curr_ace_outer = list_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
236                 canon_ace *curr_ace;
237                 canon_ace *curr_ace_next;
238
239                 curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
240
241                 for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
242
243                         curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
244
245                         if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
246                                 (curr_ace->attr == curr_ace_outer->attr)) {
247
248                                 if( DEBUGLVL( 10 )) {
249                                         dbgtext("merge_aces: Merging ACE's\n");
250                                         print_canon_ace( curr_ace_outer, 0);
251                                         print_canon_ace( curr_ace, 0);
252                                 }
253
254                                 /* Merge two allow or two deny ACE's. */
255
256                                 curr_ace_outer->perms |= curr_ace->perms;
257                                 DLIST_REMOVE(list_head, curr_ace);
258                                 SAFE_FREE(curr_ace);
259                                 curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
260                         }
261                 }
262         }
263
264         /*
265          * Now go through and mask off allow permissions with deny permissions.
266          * We can delete either the allow or deny here as we know that each SID
267          * appears only once in the list.
268          */
269
270         for (curr_ace_outer = list_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
271                 canon_ace *curr_ace;
272                 canon_ace *curr_ace_next;
273
274                 curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
275
276                 for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
277
278                         curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
279
280                         /*
281                          * Subtract ACE's with different entries. Due to the ordering constraints
282                          * we've put on the ACL, we know the deny must be the first one.
283                          */
284
285                         if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
286                                 (curr_ace_outer->attr == DENY_ACE) && (curr_ace->attr == ALLOW_ACE)) {
287
288                                 if( DEBUGLVL( 10 )) {
289                                         dbgtext("merge_aces: Masking ACE's\n");
290                                         print_canon_ace( curr_ace_outer, 0);
291                                         print_canon_ace( curr_ace, 0);
292                                 }
293
294                                 curr_ace->perms &= ~curr_ace_outer->perms;
295
296                                 if (curr_ace->perms == 0) {
297
298                                         /*
299                                          * The deny overrides the allow. Remove the allow.
300                                          */
301
302                                         DLIST_REMOVE(list_head, curr_ace);
303                                         SAFE_FREE(curr_ace);
304                                         curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
305
306                                 } else {
307
308                                         /*
309                                          * Even after removing permissions, there
310                                          * are still allow permissions - delete the deny.
311                                          * It is safe to delete the deny here,
312                                          * as we are guarenteed by the deny first
313                                          * ordering that all the deny entries for
314                                          * this SID have already been merged into one
315                                          * before we can get to an allow ace.
316                                          */
317
318                                         DLIST_REMOVE(list_head, curr_ace_outer);
319                                         SAFE_FREE(curr_ace_outer);
320                                         break;
321                                 }
322                         }
323
324                 } /* end for curr_ace */
325         } /* end for curr_ace_outer */
326
327         /* We may have modified the list. */
328
329         *pp_list_head = list_head;
330 }
331
332 /****************************************************************************
333  Map canon_ace perms to permission bits NT.
334  The attr element is not used here - we only process deny entries on set,
335  not get. Deny entries are implicit on get with ace->perms = 0.
336 ****************************************************************************/
337
338 static SEC_ACCESS map_canon_ace_perms(int *pacl_type, DOM_SID *powner_sid, canon_ace *ace)
339 {
340         SEC_ACCESS sa;
341         uint32 nt_mask = 0;
342
343         *pacl_type = SEC_ACE_TYPE_ACCESS_ALLOWED;
344
345         if ((ace->perms & ALL_ACE_PERMS) == ALL_ACE_PERMS) {
346                         nt_mask = UNIX_ACCESS_RWX;
347         } else if ((ace->perms & ALL_ACE_PERMS) == (mode_t)0) {
348                 nt_mask = UNIX_ACCESS_NONE;
349         } else {
350                 nt_mask |= ((ace->perms & S_IRUSR) ? UNIX_ACCESS_R : 0 );
351                 nt_mask |= ((ace->perms & S_IWUSR) ? UNIX_ACCESS_W : 0 );
352                 nt_mask |= ((ace->perms & S_IXUSR) ? UNIX_ACCESS_X : 0 );
353         }
354
355         DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n",
356                         (unsigned int)ace->perms, (unsigned int)nt_mask ));
357
358         init_sec_access(&sa,nt_mask);
359         return sa;
360 }
361
362 /****************************************************************************
363  Map NT perms to a UNIX mode_t.
364 ****************************************************************************/
365
366 #define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES)
367 #define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA|FILE_WRITE_ATTRIBUTES)
368 #define FILE_SPECIFIC_EXECUTE_BITS (FILE_EXECUTE)
369
370 static mode_t map_nt_perms( SEC_ACCESS sec_access, int type)
371 {
372         mode_t mode = 0;
373
374         switch(type) {
375         case S_IRUSR:
376                 if(sec_access.mask & GENERIC_ALL_ACCESS)
377                         mode = S_IRUSR|S_IWUSR|S_IXUSR;
378                 else {
379                         mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRUSR : 0;
380                         mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWUSR : 0;
381                         mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXUSR : 0;
382                 }
383                 break;
384         case S_IRGRP:
385                 if(sec_access.mask & GENERIC_ALL_ACCESS)
386                         mode = S_IRGRP|S_IWGRP|S_IXGRP;
387                 else {
388                         mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRGRP : 0;
389                         mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWGRP : 0;
390                         mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXGRP : 0;
391                 }
392                 break;
393         case S_IROTH:
394                 if(sec_access.mask & GENERIC_ALL_ACCESS)
395                         mode = S_IROTH|S_IWOTH|S_IXOTH;
396                 else {
397                         mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IROTH : 0;
398                         mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWOTH : 0;
399                         mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXOTH : 0;
400                 }
401                 break;
402         }
403
404         return mode;
405 }
406
407 /****************************************************************************
408  Unpack a SEC_DESC into a UNIX owner and group.
409 ****************************************************************************/
410
411 static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, SEC_DESC *psd)
412 {
413         DOM_SID owner_sid;
414         DOM_SID grp_sid;
415         enum SID_NAME_USE sid_type;
416
417         *puser = (uid_t)-1;
418         *pgrp = (gid_t)-1;
419
420         if(security_info_sent == 0) {
421                 DEBUG(0,("unpack_nt_owners: no security info sent !\n"));
422                 return True;
423         }
424
425         /*
426          * Validate the owner and group SID's.
427          */
428
429         memset(&owner_sid, '\0', sizeof(owner_sid));
430         memset(&grp_sid, '\0', sizeof(grp_sid));
431
432         DEBUG(5,("unpack_nt_owners: validating owner_sids.\n"));
433
434         /*
435          * Don't immediately fail if the owner sid cannot be validated.
436          * This may be a group chown only set.
437          */
438
439         if (security_info_sent & OWNER_SECURITY_INFORMATION) {
440                 sid_copy(&owner_sid, psd->owner_sid);
441                 if (!sid_to_uid( &owner_sid, puser, &sid_type)) {
442                         DEBUG(3,("unpack_nt_owners: unable to validate owner sid for %s\n",
443                                  sid_string_static(&owner_sid)));
444                         return False;
445                 }
446         }
447
448         /*
449          * Don't immediately fail if the group sid cannot be validated.
450          * This may be an owner chown only set.
451          */
452
453         if (security_info_sent & GROUP_SECURITY_INFORMATION) {
454                 sid_copy(&grp_sid, psd->grp_sid);
455                 if (!sid_to_gid( &grp_sid, pgrp, &sid_type)) {
456                         DEBUG(3,("unpack_nt_owners: unable to validate group sid.\n"));
457                         return False;
458                 }
459         }
460
461         DEBUG(5,("unpack_nt_owners: owner_sids validated.\n"));
462
463         return True;
464 }
465
466 /****************************************************************************
467  Ensure the enforced permissions for this share apply.
468 ****************************************************************************/
469
470 static mode_t apply_default_perms(files_struct *fsp, mode_t perms, mode_t type)
471 {
472         int snum = SNUM(fsp->conn);
473         mode_t and_bits = (mode_t)0;
474         mode_t or_bits = (mode_t)0;
475
476         /* Get the initial bits to apply. */
477
478         if (fsp->is_directory) {
479                 and_bits = lp_dir_security_mask(snum);
480                 or_bits = lp_force_dir_security_mode(snum);
481         } else {
482                 and_bits = lp_security_mask(snum);
483                 or_bits = lp_force_security_mode(snum);
484         }
485
486         /* Now bounce them into the S_USR space. */     
487         switch(type) {
488         case S_IRUSR:
489                 and_bits = unix_perms_to_acl_perms(and_bits, S_IRUSR, S_IWUSR, S_IXUSR);
490                 or_bits = unix_perms_to_acl_perms(or_bits, S_IRUSR, S_IWUSR, S_IXUSR);
491                 break;
492         case S_IRGRP:
493                 and_bits = unix_perms_to_acl_perms(and_bits, S_IRGRP, S_IWGRP, S_IXGRP);
494                 or_bits = unix_perms_to_acl_perms(or_bits, S_IRGRP, S_IWGRP, S_IXGRP);
495                 break;
496         case S_IROTH:
497                 and_bits = unix_perms_to_acl_perms(and_bits, S_IROTH, S_IWOTH, S_IXOTH);
498                 or_bits = unix_perms_to_acl_perms(or_bits, S_IROTH, S_IWOTH, S_IXOTH);
499                 break;
500         }
501
502         return ((perms & and_bits)|or_bits);
503 }
504
505 /****************************************************************************
506  A well formed POSIX file or default ACL has at least 3 entries, a 
507  SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ.
508  In addition, the owner must always have at least read access.
509  When using this call on get_acl, the pst struct is valid and contains
510  the mode of the file. When using this call on set_acl, the pst struct has
511  been modified to have a mode containing the default for this file or directory
512  type.
513 ****************************************************************************/
514
515 static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
516                                                         files_struct *fsp,
517                                                         DOM_SID *pfile_owner_sid,
518                                                         DOM_SID *pfile_grp_sid,
519                                                         SMB_STRUCT_STAT *pst,
520                                                         BOOL setting_acl)
521 {
522         extern DOM_SID global_sid_World;
523         canon_ace *pace;
524         BOOL got_user = False;
525         BOOL got_grp = False;
526         BOOL got_other = False;
527
528         for (pace = *pp_ace; pace; pace = pace->next) {
529                 if (pace->type == SMB_ACL_USER_OBJ) {
530
531                         if (setting_acl) {
532                                 /* Ensure owner has read access. */
533                                 pace->perms |= S_IRUSR;
534                                 if (fsp->is_directory)
535                                         pace->perms |= (S_IWUSR|S_IXUSR);
536
537                                 /*
538                                  * Ensure create mask/force create mode is respected on set.
539                                  */
540
541                                 pace->perms = apply_default_perms(fsp, pace->perms, S_IRUSR);
542                         }
543
544                         got_user = True;
545                 } else if (pace->type == SMB_ACL_GROUP_OBJ) {
546
547                         /*
548                          * Ensure create mask/force create mode is respected on set.
549                          */
550
551                         if (setting_acl)
552                                 pace->perms = apply_default_perms(fsp, pace->perms, S_IRGRP);
553                         got_grp = True;
554                 } else if (pace->type == SMB_ACL_OTHER) {
555
556                         /*
557                          * Ensure create mask/force create mode is respected on set.
558                          */
559
560                         if (setting_acl)
561                                 pace->perms = apply_default_perms(fsp, pace->perms, S_IROTH);
562                         got_other = True;
563                 }
564         }
565
566         if (!got_user) {
567                 if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
568                         DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
569                         return False;
570                 }
571
572                 ZERO_STRUCTP(pace);
573                 pace->type = SMB_ACL_USER_OBJ;
574                 pace->owner_type = UID_ACE;
575                 pace->unix_ug.uid = pst->st_uid;
576                 pace->trustee = *pfile_owner_sid;
577                 pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR);
578                 pace->attr = ALLOW_ACE;
579
580                 DLIST_ADD(*pp_ace, pace);
581         }
582
583         if (!got_grp) {
584                 if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
585                         DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
586                         return False;
587                 }
588
589                 ZERO_STRUCTP(pace);
590                 pace->type = SMB_ACL_GROUP_OBJ;
591                 pace->owner_type = GID_ACE;
592                 pace->unix_ug.uid = pst->st_gid;
593                 pace->trustee = *pfile_grp_sid;
594                 pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP);
595                 pace->attr = ALLOW_ACE;
596
597                 DLIST_ADD(*pp_ace, pace);
598         }
599
600         if (!got_other) {
601                 if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
602                         DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
603                         return False;
604                 }
605
606                 ZERO_STRUCTP(pace);
607                 pace->type = SMB_ACL_OTHER;
608                 pace->owner_type = WORLD_ACE;
609                 pace->unix_ug.world = -1;
610                 pace->trustee = global_sid_World;
611                 pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IROTH, S_IWOTH, S_IXOTH);
612                 pace->attr = ALLOW_ACE;
613
614                 DLIST_ADD(*pp_ace, pace);
615         }
616
617         return True;
618 }
619
620 /****************************************************************************
621  Unpack a SEC_DESC into two canonical ace lists.
622 ****************************************************************************/
623
624 static BOOL create_canon_ace_lists(files_struct *fsp, 
625                                                         DOM_SID *pfile_owner_sid,
626                                                         DOM_SID *pfile_grp_sid,
627                                                         canon_ace **ppfile_ace, canon_ace **ppdir_ace,
628                                                         SEC_ACL *dacl)
629 {
630         extern DOM_SID global_sid_World;
631         extern struct generic_mapping file_generic_mapping;
632         BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False);
633         canon_ace *file_ace = NULL;
634         canon_ace *dir_ace = NULL;
635         canon_ace *tmp_ace = NULL;
636         canon_ace *current_ace = NULL;
637         BOOL got_dir_allow = False;
638         BOOL got_file_allow = False;
639         int i, j;
640
641         *ppfile_ace = NULL;
642         *ppdir_ace = NULL;
643
644         /*
645          * Convert the incoming ACL into a more regular form.
646          */
647
648         for(i = 0; i < dacl->num_aces; i++) {
649                 SEC_ACE *psa = &dacl->ace[i];
650
651                 if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) && (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
652                         DEBUG(3,("create_canon_ace_lists: unable to set anything but an ALLOW or DENY ACE.\n"));
653                         return False;
654                 }
655
656                 /*
657                  * The security mask may be UNIX_ACCESS_NONE which should map into
658                  * no permissions (we overload the WRITE_OWNER bit for this) or it
659                  * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
660                  * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
661                  */
662
663                 /*
664                  * Convert GENERIC bits to specific bits.
665                  */
666  
667                 se_map_generic(&psa->info.mask, &file_generic_mapping);
668
669                 psa->info.mask &= (UNIX_ACCESS_NONE|FILE_ALL_ACCESS);
670
671                 if(psa->info.mask != UNIX_ACCESS_NONE)
672                         psa->info.mask &= ~UNIX_ACCESS_NONE;
673         }
674
675         /*
676          * Deal with the fact that NT 4.x re-writes the canonical format
677          * that we return for default ACLs. If a directory ACE is identical
678          * to a inherited directory ACE then NT changes the bits so that the
679          * first ACE is set to OI|IO and the second ACE for this SID is set
680          * to CI. We need to repair this. JRA.
681          */
682
683         for(i = 0; i < dacl->num_aces; i++) {
684                 SEC_ACE *psa1 = &dacl->ace[i];
685
686                 for (j = i + 1; j < dacl->num_aces; j++) {
687                         SEC_ACE *psa2 = &dacl->ace[j];
688
689                         if (psa1->info.mask != psa2->info.mask)
690                                 continue;
691
692                         if (!sid_equal(&psa1->trustee, &psa2->trustee))
693                                 continue;
694
695                         /*
696                          * Ok - permission bits and SIDs are equal.
697                          * Check if flags were re-written.
698                          */
699
700                         if (psa1->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
701
702                                 psa1->flags |= (psa2->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
703                                 psa2->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
704                                 
705                         } else if (psa2->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
706
707                                 psa2->flags |= (psa1->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
708                                 psa1->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
709                                 
710                         }
711                 }
712         }
713
714         for(i = 0; i < dacl->num_aces; i++) {
715                 enum SID_NAME_USE sid_type;
716                 SEC_ACE *psa = &dacl->ace[i];
717
718                 /*
719                  * Ignore non-mappable SIDs (NT Authority, BUILTIN etc).
720                  */
721
722                 if (non_mappable_sid(&psa->trustee)) {
723                         fstring str;
724                         DEBUG(10,("create_canon_ace_lists: ignoring non-mappable SID %s\n",
725                                 sid_to_string(str, &psa->trustee) ));
726                         continue;
727                 }
728
729                 /*
730                  * Create a cannon_ace entry representing this NT DACL ACE.
731                  */
732
733                 if ((current_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
734                         free_canon_ace_list(file_ace);
735                         free_canon_ace_list(dir_ace);
736                         DEBUG(0,("create_canon_ace_lists: malloc fail.\n"));
737                         return False;
738                 }
739
740                 ZERO_STRUCTP(current_ace);
741
742                 sid_copy(&current_ace->trustee, &psa->trustee);
743
744                 /*
745                  * Try and work out if the SID is a user or group
746                  * as we need to flag these differently for POSIX.
747                  */
748
749                 if( sid_equal(&current_ace->trustee, &global_sid_World)) {
750                         current_ace->owner_type = WORLD_ACE;
751                         current_ace->unix_ug.world = -1;
752                 } else if (sid_to_uid( &current_ace->trustee, &current_ace->unix_ug.uid, &sid_type)) {
753                         current_ace->owner_type = UID_ACE;
754                 } else if (sid_to_gid( &current_ace->trustee, &current_ace->unix_ug.gid, &sid_type)) {
755                         current_ace->owner_type = GID_ACE;
756                 } else {
757                         fstring str;
758
759                         free_canon_ace_list(file_ace);
760                         free_canon_ace_list(dir_ace);
761                         DEBUG(0,("create_canon_ace_lists: unable to map SID %s to uid or gid.\n",
762                                 sid_to_string(str, &current_ace->trustee) ));
763                         SAFE_FREE(current_ace);
764                         return False;
765                 }
766
767                 /*
768                  * Map the given NT permissions into a UNIX mode_t containing only
769                  * S_I(R|W|X)USR bits.
770                  */
771
772                 current_ace->perms |= map_nt_perms( psa->info, S_IRUSR);
773                 current_ace->attr = (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? ALLOW_ACE : DENY_ACE;
774
775                 /*
776                  * Now note what kind of a POSIX ACL this should map to.
777                  */
778
779                 if(sid_equal(&current_ace->trustee, pfile_owner_sid)) {
780
781                         current_ace->type = SMB_ACL_USER_OBJ;
782
783                 } else if( sid_equal(&current_ace->trustee, pfile_grp_sid)) {
784
785                         current_ace->type = SMB_ACL_GROUP_OBJ;
786
787                 } else if( sid_equal(&current_ace->trustee, &global_sid_World)) {
788
789                         current_ace->type = SMB_ACL_OTHER;
790
791                 } else {
792                         /*
793                          * Could be a SMB_ACL_USER or SMB_ACL_GROUP. Check by
794                          * looking at owner_type.
795                          */
796
797                         current_ace->type = (current_ace->owner_type == UID_ACE) ? SMB_ACL_USER : SMB_ACL_GROUP;
798                 }
799
800                 /*
801                  * Now add the created ace to either the file list, the directory
802                  * list, or both. We *MUST* preserve the order here (hence we use
803                  * DLIST_ADD_END) as NT ACLs are order dependent.
804                  */
805
806                 if (fsp->is_directory) {
807
808                         /*
809                          * We can only add to the default POSIX ACE list if the ACE is
810                          * designed to be inherited by both files and directories.
811                          */
812
813                         if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) ==
814                                 (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) {
815
816                                 DLIST_ADD_END(dir_ace, current_ace, tmp_ace);
817
818                                 /*
819                                  * Note if this was an allow ace. We can't process
820                                  * any further deny ace's after this.
821                                  */
822
823                                 if (current_ace->attr == ALLOW_ACE)
824                                         got_dir_allow = True;
825
826                                 if ((current_ace->attr == DENY_ACE) && got_dir_allow) {
827                                         DEBUG(0,("create_canon_ace_lists: malformed ACL in inheritable ACL ! \
828 Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
829                                         free_canon_ace_list(file_ace);
830                                         free_canon_ace_list(dir_ace);
831                                         SAFE_FREE(current_ace);
832                                         return False;
833                                 }       
834
835                                 if( DEBUGLVL( 10 )) {
836                                         dbgtext("create_canon_ace_lists: adding dir ACL:\n");
837                                         print_canon_ace( current_ace, 0);
838                                 }
839
840                                 /*
841                                  * If this is not an inherit only ACE we need to add a duplicate
842                                  * to the file acl.
843                                  */
844
845                                 if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
846                                         canon_ace *dup_ace = dup_canon_ace(current_ace);
847
848                                         if (!dup_ace) {
849                                                 DEBUG(0,("create_canon_ace_lists: malloc fail !\n"));
850                                                 free_canon_ace_list(file_ace);
851                                                 free_canon_ace_list(dir_ace);
852                                                 return False;
853                                         }
854
855                                         current_ace = dup_ace;
856                                 } else {
857                                         current_ace = NULL;
858                                 }
859                         }
860                 }
861
862                 /*
863                  * Only add to the file ACL if not inherit only.
864                  */
865
866                 if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
867                         DLIST_ADD_END(file_ace, current_ace, tmp_ace);
868
869                         /*
870                          * Note if this was an allow ace. We can't process
871                          * any further deny ace's after this.
872                          */
873
874                         if (current_ace->attr == ALLOW_ACE)
875                                 got_file_allow = True;
876
877                         if ((current_ace->attr == DENY_ACE) && got_file_allow) {
878                                 DEBUG(0,("create_canon_ace_lists: malformed ACL in file ACL ! \
879 Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
880                                 free_canon_ace_list(file_ace);
881                                 free_canon_ace_list(dir_ace);
882                                 SAFE_FREE(current_ace);
883                                 return False;
884                         }       
885
886                         if( DEBUGLVL( 10 )) {
887                                 dbgtext("create_canon_ace_lists: adding file ACL:\n");
888                                 print_canon_ace( current_ace, 0);
889                         }
890                         all_aces_are_inherit_only = False;
891                         current_ace = NULL;
892                 }
893
894                 /*
895                  * Free if ACE was not added.
896                  */
897
898                 SAFE_FREE(current_ace);
899         }
900
901         if (fsp->is_directory && all_aces_are_inherit_only) {
902                 /*
903                  * Windows 2000 is doing one of these weird 'inherit acl'
904                  * traverses to conserve NTFS ACL resources. Just pretend
905                  * there was no DACL sent. JRA.
906                  */
907
908                 DEBUG(10,("create_canon_ace_lists: Win2k inherit acl traverse. Ignoring DACL.\n"));
909                 free_canon_ace_list(file_ace);
910                 free_canon_ace_list(dir_ace);
911                 file_ace = NULL;
912                 dir_ace = NULL;
913         }
914
915         *ppfile_ace = file_ace;
916         *ppdir_ace = dir_ace;
917
918         return True;
919 }
920
921 /****************************************************************************
922  Check if a given uid/SID is in a group gid/SID. This is probably very
923  expensive and will need optimisation. A *lot* of optimisation :-). JRA.
924 ****************************************************************************/
925
926 static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace )
927 {
928         extern DOM_SID global_sid_World;
929         fstring u_name;
930         fstring g_name;
931
932         /* "Everyone" always matches every uid. */
933
934         if (sid_equal(&group_ace->trustee, &global_sid_World))
935                 return True;
936
937         fstrcpy(u_name, uidtoname(uid_ace->unix_ug.uid));
938         fstrcpy(g_name, gidtoname(group_ace->unix_ug.gid));
939
940         /*
941          * Due to the winbind interfaces we need to do this via names,
942          * not uids/gids.
943          */
944
945         return user_in_group_list(u_name, g_name );
946 }
947
948 /****************************************************************************
949  ASCII art time again... JRA :-).
950
951  We have 3 cases to process when moving from an NT ACL to a POSIX ACL. Firstly,
952  we insist the ACL is in canonical form (ie. all DENY entries preceede ALLOW
953  entries). Secondly, the merge code has ensured that all duplicate SID entries for
954  allow or deny have been merged, so the same SID can only appear once in the deny
955  list or once in the allow list.
956
957  We then process as follows :
958
959  ---------------------------------------------------------------------------
960  First pass - look for a Everyone DENY entry.
961
962  If it is deny all (rwx) trunate the list at this point.
963  Else, walk the list from this point and use the deny permissions of this
964  entry as a mask on all following allow entries. Finally, delete
965  the Everyone DENY entry (we have applied it to everything possible).
966
967  In addition, in this pass we remove any DENY entries that have 
968  no permissions (ie. they are a DENY nothing).
969  ---------------------------------------------------------------------------
970  Second pass - only deal with deny user entries.
971
972  DENY user1 (perms XXX)
973
974  new_perms = 0
975  for all following allow group entries where user1 is in group
976         new_perms |= group_perms;
977
978  user1 entry perms = new_perms & ~ XXX;
979
980  Convert the deny entry to an allow entry with the new perms and
981  push to the end of the list. Note if the user was in no groups
982  this maps to a specific allow nothing entry for this user.
983
984  The common case from the NT ACL choser (userX deny all) is
985  optimised so we don't do the group lookup - we just map to
986  an allow nothing entry.
987
988  What we're doing here is inferring the allow permissions the
989  person setting the ACE on user1 wanted by looking at the allow
990  permissions on the groups the user is currently in. This will
991  be a snapshot, depending on group membership but is the best
992  we can do and has the advantage of failing closed rather than
993  open.
994  ---------------------------------------------------------------------------
995  Third pass - only deal with deny group entries.
996
997  DENY group1 (perms XXX)
998
999  for all following allow user entries where user is in group1
1000    user entry perms = user entry perms & ~ XXX;
1001
1002  If there is a group Everyone allow entry with permissions YYY,
1003  convert the group1 entry to an allow entry and modify its
1004  permissions to be :
1005
1006  new_perms = YYY & ~ XXX
1007
1008  and push to the end of the list.
1009
1010  If there is no group Everyone allow entry then convert the
1011  group1 entry to a allow nothing entry and push to the end of the list.
1012
1013  Note that the common case from the NT ACL choser (groupX deny all)
1014  cannot be optimised here as we need to modify user entries who are
1015  in the group to change them to a deny all also.
1016
1017  What we're doing here is modifying the allow permissions of
1018  user entries (which are more specific in POSIX ACLs) to mask
1019  out the explicit deny set on the group they are in. This will
1020  be a snapshot depending on current group membership but is the
1021  best we can do and has the advantage of failing closed rather
1022  than open.
1023  ---------------------------------------------------------------------------
1024
1025  Note we *MUST* do the deny user pass first as this will convert deny user
1026  entries into allow user entries which can then be processed by the deny
1027  group pass.
1028
1029  The above algorithm took a *lot* of thinking about - hence this
1030  explaination :-). JRA.
1031 ****************************************************************************/
1032
1033 /****************************************************************************
1034  Process a canon_ace list entries. This is very complex code. We need
1035  to go through and remove the "deny" permissions from any allow entry that matches
1036  the id of this entry. We have already refused any NT ACL that wasn't in correct
1037  order (DENY followed by ALLOW). If any allow entry ends up with zero permissions,
1038  we just remove it (to fail safe). We have already removed any duplicate ace
1039  entries. Treat an "Everyone" DENY_ACE as a special case - use it to mask all
1040  allow entries.
1041 ****************************************************************************/
1042
1043 static void process_deny_list( canon_ace **pp_ace_list )
1044 {
1045         extern DOM_SID global_sid_World;
1046         canon_ace *ace_list = *pp_ace_list;
1047         canon_ace *curr_ace = NULL;
1048         canon_ace *curr_ace_next = NULL;
1049
1050         /* Pass 1 above - look for an Everyone, deny entry. */
1051
1052         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1053                 canon_ace *allow_ace_p;
1054
1055                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1056
1057                 if (curr_ace->attr != DENY_ACE)
1058                         continue;
1059
1060                 if (curr_ace->perms == (mode_t)0) {
1061
1062                         /* Deny nothing entry - delete. */
1063
1064                         DLIST_REMOVE(ace_list, curr_ace);
1065                         continue;
1066                 }
1067
1068                 if (!sid_equal(&curr_ace->trustee, &global_sid_World))
1069                         continue;
1070
1071                 /* JRATEST - assert. */
1072                 SMB_ASSERT(curr_ace->owner_type == WORLD_ACE);
1073
1074                 if (curr_ace->perms == ALL_ACE_PERMS) {
1075
1076                         /*
1077                          * Optimisation. This is a DENY_ALL to Everyone. Truncate the
1078                          * list at this point including this entry.
1079                          */
1080
1081                         canon_ace *prev_entry = curr_ace->prev;
1082
1083                         free_canon_ace_list( curr_ace );
1084                         if (prev_entry)
1085                                 prev_entry->next = NULL;
1086                         else {
1087                                 /* We deleted the entire list. */
1088                                 ace_list = NULL;
1089                         }
1090                         break;
1091                 }
1092
1093                 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1094
1095                         /* 
1096                          * Only mask off allow entries.
1097                          */
1098
1099                         if (allow_ace_p->attr != ALLOW_ACE)
1100                                 continue;
1101
1102                         allow_ace_p->perms &= ~curr_ace->perms;
1103                 }
1104
1105                 /*
1106                  * Now it's been applied, remove it.
1107                  */
1108
1109                 DLIST_REMOVE(ace_list, curr_ace);
1110         }
1111
1112         /* Pass 2 above - deal with deny user entries. */
1113
1114         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1115                 mode_t new_perms = (mode_t)0;
1116                 canon_ace *allow_ace_p;
1117                 canon_ace *tmp_ace;
1118
1119                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1120
1121                 if (curr_ace->attr != DENY_ACE)
1122                         continue;
1123
1124                 if (curr_ace->owner_type != UID_ACE)
1125                         continue;
1126
1127                 if (curr_ace->perms == ALL_ACE_PERMS) {
1128
1129                         /*
1130                          * Optimisation - this is a deny everything to this user.
1131                          * Convert to an allow nothing and push to the end of the list.
1132                          */
1133
1134                         curr_ace->attr = ALLOW_ACE;
1135                         curr_ace->perms = (mode_t)0;
1136                         DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
1137                         continue;
1138                 }
1139
1140                 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1141
1142                         if (allow_ace_p->attr != ALLOW_ACE)
1143                                 continue;
1144
1145                         /* We process GID_ACE and WORLD_ACE entries only. */
1146
1147                         if (allow_ace_p->owner_type == UID_ACE)
1148                                 continue;
1149
1150                         if (uid_entry_in_group( curr_ace, allow_ace_p))
1151                                 new_perms |= allow_ace_p->perms;
1152                 }
1153
1154                 /*
1155                  * Convert to a allow entry, modify the perms and push to the end
1156                  * of the list.
1157                  */
1158
1159                 curr_ace->attr = ALLOW_ACE;
1160                 curr_ace->perms = (new_perms & ~curr_ace->perms);
1161                 DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
1162         }
1163
1164         /* Pass 3 above - deal with deny group entries. */
1165
1166         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1167                 canon_ace *tmp_ace;
1168                 canon_ace *allow_ace_p;
1169                 canon_ace *allow_everyone_p = NULL;
1170
1171                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1172
1173                 if (curr_ace->attr != DENY_ACE)
1174                         continue;
1175
1176                 if (curr_ace->owner_type != GID_ACE)
1177                         continue;
1178
1179                 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1180
1181                         if (allow_ace_p->attr != ALLOW_ACE)
1182                                 continue;
1183
1184                         /* Store a pointer to the Everyone allow, if it exists. */
1185                         if (allow_ace_p->owner_type == WORLD_ACE)
1186                                 allow_everyone_p = allow_ace_p;
1187
1188                         /* We process UID_ACE entries only. */
1189
1190                         if (allow_ace_p->owner_type != UID_ACE)
1191                                 continue;
1192
1193                         /* Mask off the deny group perms. */
1194
1195                         if (uid_entry_in_group( allow_ace_p, curr_ace))
1196                                 allow_ace_p->perms &= ~curr_ace->perms;
1197                 }
1198
1199                 /*
1200                  * Convert the deny to an allow with the correct perms and
1201                  * push to the end of the list.
1202                  */
1203
1204                 curr_ace->attr = ALLOW_ACE;
1205                 if (allow_everyone_p)
1206                         curr_ace->perms = allow_everyone_p->perms & ~curr_ace->perms;
1207                 else
1208                         curr_ace->perms = (mode_t)0;
1209                 DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
1210
1211         }
1212
1213         *pp_ace_list = ace_list;
1214 }
1215
1216 /****************************************************************************
1217  Create a default mode that will be used if a security descriptor entry has
1218  no user/group/world entries.
1219 ****************************************************************************/
1220
1221 static mode_t create_default_mode(files_struct *fsp, BOOL interitable_mode)
1222 {
1223         int snum = SNUM(fsp->conn);
1224         mode_t and_bits = (mode_t)0;
1225         mode_t or_bits = (mode_t)0;
1226         mode_t mode = interitable_mode ? unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name) : S_IRUSR;
1227
1228         if (fsp->is_directory)
1229                 mode |= (S_IWUSR|S_IXUSR);
1230
1231         /*
1232          * Now AND with the create mode/directory mode bits then OR with the
1233          * force create mode/force directory mode bits.
1234          */
1235
1236         if (fsp->is_directory) {
1237                 and_bits = lp_dir_security_mask(snum);
1238                 or_bits = lp_force_dir_security_mode(snum);
1239         } else {
1240                 and_bits = lp_security_mask(snum);
1241                 or_bits = lp_force_security_mode(snum);
1242         }
1243
1244         return ((mode & and_bits)|or_bits);
1245 }
1246
1247 /****************************************************************************
1248  Unpack a SEC_DESC into two canonical ace lists. We don't depend on this
1249  succeeding.
1250 ****************************************************************************/
1251
1252 static BOOL unpack_canon_ace(files_struct *fsp, 
1253                                                         SMB_STRUCT_STAT *pst,
1254                                                         DOM_SID *pfile_owner_sid,
1255                                                         DOM_SID *pfile_grp_sid,
1256                                                         canon_ace **ppfile_ace, canon_ace **ppdir_ace,
1257                                                         uint32 security_info_sent, SEC_DESC *psd)
1258 {
1259         canon_ace *file_ace = NULL;
1260         canon_ace *dir_ace = NULL;
1261
1262         *ppfile_ace = NULL;
1263         *ppdir_ace = NULL;
1264
1265         if(security_info_sent == 0) {
1266                 DEBUG(0,("unpack_canon_ace: no security info sent !\n"));
1267                 return False;
1268         }
1269
1270         /*
1271          * If no DACL then this is a chown only security descriptor.
1272          */
1273
1274         if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !psd->dacl)
1275                 return True;
1276
1277         /*
1278          * Now go through the DACL and create the canon_ace lists.
1279          */
1280
1281         if (!create_canon_ace_lists( fsp, pfile_owner_sid, pfile_grp_sid,
1282                                                                 &file_ace, &dir_ace, psd->dacl))
1283                 return False;
1284
1285         if ((file_ace == NULL) && (dir_ace == NULL)) {
1286                 /* W2K traverse DACL set - ignore. */
1287                 return True;
1288         }
1289
1290         /*
1291          * Go through the canon_ace list and merge entries
1292          * belonging to identical users of identical allow or deny type.
1293          * We can do this as all deny entries come first, followed by
1294          * all allow entries (we have mandated this before accepting this acl).
1295          */
1296
1297         print_canon_ace_list( "file ace - before merge", file_ace);
1298         merge_aces( &file_ace );
1299
1300         print_canon_ace_list( "dir ace - before merge", dir_ace);
1301         merge_aces( &dir_ace );
1302
1303         /*
1304          * NT ACLs are order dependent. Go through the acl lists and
1305          * process DENY entries by masking the allow entries.
1306          */
1307
1308         print_canon_ace_list( "file ace - before deny", file_ace);
1309         process_deny_list( &file_ace);
1310
1311         print_canon_ace_list( "dir ace - before deny", dir_ace);
1312         process_deny_list( &dir_ace);
1313
1314         /*
1315          * A well formed POSIX file or default ACL has at least 3 entries, a 
1316          * SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ
1317          * and optionally a mask entry. Ensure this is the case.
1318          */
1319
1320         print_canon_ace_list( "file ace - before valid", file_ace);
1321
1322         /*
1323          * A default 3 element mode entry for a file should be r-- --- ---.
1324          * A default 3 element mode entry for a directory should be rwx --- ---.
1325          */
1326
1327         pst->st_mode = create_default_mode(fsp, False);
1328
1329         if (!ensure_canon_entry_valid(&file_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
1330                 free_canon_ace_list(file_ace);
1331                 free_canon_ace_list(dir_ace);
1332                 return False;
1333         }
1334
1335         print_canon_ace_list( "dir ace - before valid", dir_ace);
1336
1337         /*
1338          * A default inheritable 3 element mode entry for a directory should be the
1339          * mode Samba will use to create a file within. Ensure user rwx bits are set if
1340          * it's a directory.
1341          */
1342
1343         pst->st_mode = create_default_mode(fsp, True);
1344
1345         if (!ensure_canon_entry_valid(&dir_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
1346                 free_canon_ace_list(file_ace);
1347                 free_canon_ace_list(dir_ace);
1348                 return False;
1349         }
1350
1351         print_canon_ace_list( "file ace - return", file_ace);
1352         print_canon_ace_list( "dir ace - return", dir_ace);
1353
1354         *ppfile_ace = file_ace;
1355         *ppdir_ace = dir_ace;
1356         return True;
1357
1358 }
1359
1360 /******************************************************************************
1361  When returning permissions, try and fit NT display
1362  semantics if possible. Note the the canon_entries here must have been malloced.
1363  The list format should be - first entry = owner, followed by group and other user
1364  entries, last entry = other.
1365
1366  Note that this doesn't exactly match the NT semantics for an ACL. As POSIX entries
1367  are not ordered, and match on the most specific entry rather than walking a list,
1368  then a simple POSIX permission of rw-r--r-- should really map to 6 entries,
1369
1370  Entry 0: owner : deny all except read and write.
1371  Entry 1: group : deny all except read.
1372  Entry 2: Everyone : deny all except read.
1373  Entry 3: owner : allow read and write.
1374  Entry 4: group : allow read.
1375  Entry 5: Everyone : allow read.
1376
1377  But NT cannot display this in their ACL editor !
1378 ********************************************************************************/
1379
1380 static void arrange_posix_perms( char *filename, canon_ace **pp_list_head)
1381 {
1382         canon_ace *list_head = *pp_list_head;
1383         canon_ace *owner_ace = NULL;
1384         canon_ace *other_ace = NULL;
1385         canon_ace *ace = NULL;
1386
1387         for (ace = list_head; ace; ace = ace->next) {
1388                 if (ace->type == SMB_ACL_USER_OBJ)
1389                         owner_ace = ace;
1390                 else if (ace->type == SMB_ACL_OTHER) {
1391                         /* Last ace - this is "other" */
1392                         other_ace = ace;
1393                 }
1394         }
1395                 
1396         if (!owner_ace || !other_ace) {
1397                 DEBUG(0,("arrange_posix_perms: Invalid POSIX permissions for file %s, missing owner or other.\n",
1398                         filename ));
1399                 return;
1400         }
1401
1402         /*
1403          * The POSIX algorithm applies to owner first, and other last,
1404          * so ensure they are arranged in this order.
1405          */
1406
1407         if (owner_ace) {
1408                 DLIST_PROMOTE(list_head, owner_ace);
1409         }
1410
1411         if (other_ace) {
1412                 DLIST_DEMOTE(list_head, other_ace, ace);
1413         }
1414
1415         /* We have probably changed the head of the list. */
1416
1417         *pp_list_head = list_head;
1418 }
1419                 
1420 /****************************************************************************
1421  Create a linked list of canonical ACE entries.
1422 ****************************************************************************/
1423
1424 static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf,
1425                                                                         DOM_SID *powner, DOM_SID *pgroup)
1426 {
1427         extern DOM_SID global_sid_World;
1428         mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR);
1429         canon_ace *list_head = NULL;
1430         canon_ace *ace = NULL;
1431         canon_ace *next_ace = NULL;
1432         int entry_id = SMB_ACL_FIRST_ENTRY;
1433         SMB_ACL_ENTRY_T entry;
1434         size_t ace_count;
1435
1436         while ( posix_acl && (sys_acl_get_entry(posix_acl, entry_id, &entry) == 1)) {
1437                 SMB_ACL_TAG_T tagtype;
1438                 SMB_ACL_PERMSET_T permset;
1439                 DOM_SID sid;
1440                 posix_id unix_ug;
1441                 enum ace_owner owner_type;
1442
1443                 /* get_next... */
1444                 if (entry_id == SMB_ACL_FIRST_ENTRY)
1445                         entry_id = SMB_ACL_NEXT_ENTRY;
1446
1447                 /* Is this a MASK entry ? */
1448                 if (sys_acl_get_tag_type(entry, &tagtype) == -1)
1449                         continue;
1450
1451                 if (sys_acl_get_permset(entry, &permset) == -1)
1452                         continue;
1453
1454                 /* Decide which SID to use based on the ACL type. */
1455                 switch(tagtype) {
1456                         case SMB_ACL_USER_OBJ:
1457                                 /* Get the SID from the owner. */
1458                                 uid_to_sid( &sid, psbuf->st_uid );
1459                                 unix_ug.uid = psbuf->st_uid;
1460                                 owner_type = UID_ACE;
1461                                 break;
1462                         case SMB_ACL_USER:
1463                                 {
1464                                         uid_t *puid = (uid_t *)sys_acl_get_qualifier(entry);
1465                                         if (puid == NULL) {
1466                                                 DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
1467                                                 continue;
1468                                         }
1469                                         uid_to_sid( &sid, *puid);
1470                                         unix_ug.uid = *puid;
1471                                         owner_type = UID_ACE;
1472                                         sys_acl_free_qualifier((void *)puid,tagtype);
1473                                         break;
1474                                 }
1475                         case SMB_ACL_GROUP_OBJ:
1476                                 /* Get the SID from the owning group. */
1477                                 gid_to_sid( &sid, psbuf->st_gid );
1478                                 unix_ug.gid = psbuf->st_gid;
1479                                 owner_type = GID_ACE;
1480                                 break;
1481                         case SMB_ACL_GROUP:
1482                                 {
1483                                         gid_t *pgid = (gid_t *)sys_acl_get_qualifier(entry);
1484                                         if (pgid == NULL) {
1485                                                 DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
1486                                                 continue;
1487                                         }
1488                                         gid_to_sid( &sid, *pgid);
1489                                         unix_ug.gid = *pgid;
1490                                         owner_type = GID_ACE;
1491                                         sys_acl_free_qualifier((void *)pgid,tagtype);
1492                                         break;
1493                                 }
1494                         case SMB_ACL_MASK:
1495                                 acl_mask = convert_permset_to_mode_t(permset);
1496                                 continue; /* Don't count the mask as an entry. */
1497                         case SMB_ACL_OTHER:
1498                                 /* Use the Everyone SID */
1499                                 sid = global_sid_World;
1500                                 unix_ug.world = -1;
1501                                 owner_type = WORLD_ACE;
1502                                 break;
1503                         default:
1504                                 DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype));
1505                                 continue;
1506                 }
1507
1508                 /*
1509                  * Add this entry to the list.
1510                  */
1511
1512                 if ((ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
1513                         goto fail;
1514
1515                 ZERO_STRUCTP(ace);
1516                 ace->type = tagtype;
1517                 ace->perms = convert_permset_to_mode_t(permset);
1518                 ace->attr = ALLOW_ACE;
1519                 ace->trustee = sid;
1520                 ace->unix_ug = unix_ug;
1521                 ace->owner_type = owner_type;
1522
1523                 DLIST_ADD(list_head, ace);
1524         }
1525
1526         /*
1527          * This next call will ensure we have at least a user/group/world set.
1528          */
1529
1530         if (!ensure_canon_entry_valid(&list_head, fsp, powner, pgroup, psbuf, False))
1531                 goto fail;
1532
1533         arrange_posix_perms(fsp->fsp_name,&list_head );
1534
1535         /*
1536          * Now go through the list, masking the permissions with the
1537          * acl_mask. Ensure all DENY Entries are at the start of the list.
1538          */
1539
1540         DEBUG(10,("canonicalise_acl: ace entries before arrange :\n"));
1541
1542         for ( ace_count = 0, ace = list_head; ace; ace = next_ace, ace_count++) {
1543                 next_ace = ace->next;
1544
1545                 /* Masks are only applied to entries other than USER_OBJ and OTHER. */
1546                 if (ace->type != SMB_ACL_OTHER && ace->type != SMB_ACL_USER_OBJ)
1547                         ace->perms &= acl_mask;
1548
1549                 if (ace->perms == 0) {
1550                         DLIST_PROMOTE(list_head, ace);
1551                 }
1552
1553                 if( DEBUGLVL( 10 ) ) {
1554                         print_canon_ace(ace, ace_count);
1555                 }
1556         }
1557
1558         print_canon_ace_list( "canonicalise_acl: ace entries after arrange", list_head );
1559
1560         return list_head;
1561
1562   fail:
1563
1564         free_canon_ace_list(list_head);
1565         return NULL;
1566 }
1567
1568 /****************************************************************************
1569  Attempt to apply an ACL to a file or directory.
1570 ****************************************************************************/
1571
1572 static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL default_ace, BOOL *pacl_set_support)
1573 {
1574         BOOL ret = False;
1575         SMB_ACL_T the_acl = sys_acl_init((int)count_canon_ace_list(the_ace) + 1);
1576         canon_ace *p_ace;
1577         int i;
1578         SMB_ACL_ENTRY_T mask_entry;
1579         SMB_ACL_PERMSET_T mask_permset;
1580         SMB_ACL_TYPE_T the_acl_type = (default_ace ? SMB_ACL_TYPE_DEFAULT : SMB_ACL_TYPE_ACCESS);
1581
1582         if (the_acl == NULL) {
1583
1584                 if (errno != ENOSYS) {
1585                         /*
1586                          * Only print this error message if we have some kind of ACL
1587                          * support that's not working. Otherwise we would always get this.
1588                          */
1589                         DEBUG(0,("set_canon_ace_list: Unable to init %s ACL. (%s)\n",
1590                                 default_ace ? "default" : "file", strerror(errno) ));
1591                 }
1592                 *pacl_set_support = False;
1593                 return False;
1594         }
1595
1596         for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
1597                 SMB_ACL_ENTRY_T the_entry;
1598                 SMB_ACL_PERMSET_T the_permset;
1599
1600                 /*
1601                  * Get the entry for this ACE.
1602                  */
1603
1604                 if (sys_acl_create_entry( &the_acl, &the_entry) == -1) {
1605                         DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n",
1606                                 i, strerror(errno) ));
1607                         goto done;
1608                 }
1609
1610                 /*
1611                  * Ok - we now know the ACL calls should be working, don't
1612                  * allow fallback to chmod.
1613                  */
1614
1615                 *pacl_set_support = True;
1616
1617                 /*
1618                  * Initialise the entry from the canon_ace.
1619                  */
1620
1621                 /*
1622                  * First tell the entry what type of ACE this is.
1623                  */
1624
1625                 if (sys_acl_set_tag_type(the_entry, p_ace->type) == -1) {
1626                         DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n",
1627                                 i, strerror(errno) ));
1628                         goto done;
1629                 }
1630
1631                 /*
1632                  * Only set the qualifier (user or group id) if the entry is a user
1633                  * or group id ACE.
1634                  */
1635
1636                 if ((p_ace->type == SMB_ACL_USER) || (p_ace->type == SMB_ACL_GROUP)) {
1637                         if (sys_acl_set_qualifier(the_entry,(void *)&p_ace->unix_ug.uid) == -1) {
1638                                 DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n",
1639                                         i, strerror(errno) ));
1640                                 goto done;
1641                         }
1642                 }
1643
1644                 /*
1645                  * Convert the mode_t perms in the canon_ace to a POSIX permset.
1646                  */
1647
1648                 if (sys_acl_get_permset(the_entry, &the_permset) == -1) {
1649                         DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n",
1650                                 i, strerror(errno) ));
1651                         goto done;
1652                 }
1653
1654                 if (map_acl_perms_to_permset(p_ace->perms, &the_permset) == -1) {
1655                         DEBUG(0,("set_canon_ace_list: Failed to create permset for mode (%u) on entry %d. (%s)\n",
1656                                 (unsigned int)p_ace->perms, i, strerror(errno) ));
1657                         goto done;
1658                 }
1659
1660                 /*
1661                  * ..and apply them to the entry.
1662                  */
1663
1664                 if (sys_acl_set_permset(the_entry, the_permset) == -1) {
1665                         DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n",
1666                                 i, strerror(errno) ));
1667                         goto done;
1668                 }
1669
1670                 if( DEBUGLVL( 10 ))
1671                         print_canon_ace( p_ace, i);
1672         }
1673
1674         /*
1675          * Add in a mask of rwx.
1676          */
1677
1678         if (sys_acl_create_entry( &the_acl, &mask_entry) == -1) {
1679                 DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) ));
1680                 goto done;
1681         }
1682
1683         if (sys_acl_set_tag_type(mask_entry, SMB_ACL_MASK) == -1) {
1684                 DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno) ));
1685                 goto done;
1686         }
1687
1688         if (sys_acl_get_permset(mask_entry, &mask_permset) == -1) {
1689                 DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) ));
1690                 goto done;
1691         }
1692
1693         if (map_acl_perms_to_permset(S_IRUSR|S_IWUSR|S_IXUSR, &mask_permset) == -1) {
1694                 DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno) ));
1695                 goto done;
1696         }
1697
1698         if (sys_acl_set_permset(mask_entry, mask_permset) == -1) {
1699                 DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) ));
1700                 goto done;
1701         }
1702
1703         /*
1704          * Check if the ACL is valid.
1705          */
1706
1707         if (sys_acl_valid(the_acl) == -1) {
1708                 DEBUG(0,("set_canon_ace_list: ACL type (%s) is invalid for set (%s).\n",
1709                                 the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
1710                                 strerror(errno) ));
1711                 goto done;
1712         }
1713
1714         /*
1715          * Finally apply it to the file or directory.
1716          */
1717
1718         if(default_ace || fsp->is_directory || fsp->fd == -1) {
1719                 if (sys_acl_set_file(fsp->fsp_name, the_acl_type, the_acl) == -1) {
1720                         /*
1721                          * Some systems allow all the above calls and only fail with no ACL support
1722                          * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
1723                          */
1724                         if (errno == ENOSYS)
1725                                 *pacl_set_support = False;
1726                         DEBUG(2,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n",
1727                                         the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
1728                                         fsp->fsp_name, strerror(errno) ));
1729                         goto done;
1730                 }
1731         } else {
1732                 if (sys_acl_set_fd(fsp->fd, the_acl) == -1) {
1733                         /*
1734                          * Some systems allow all the above calls and only fail with no ACL support
1735                          * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
1736                          */
1737                         if (errno == ENOSYS)
1738                                 *pacl_set_support = False;
1739                         DEBUG(2,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n",
1740                                         fsp->fsp_name, strerror(errno) ));
1741                         goto done;
1742                 }
1743         }
1744
1745         ret = True;
1746
1747   done:
1748
1749         if (the_acl != NULL)
1750             sys_acl_free_acl(the_acl);
1751
1752         return ret;
1753 }
1754
1755 /****************************************************************************
1756  Convert a canon_ace to a generic 3 element permission - if possible.
1757 ****************************************************************************/
1758
1759 #define MAP_PERM(p,mask,result) (((p) & (mask)) ? (result) : 0 )
1760
1761 static BOOL convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file_ace_list, mode_t *posix_perms)
1762 {
1763         int snum = SNUM(fsp->conn);
1764         size_t ace_count = count_canon_ace_list(file_ace_list);
1765         canon_ace *ace_p;
1766         canon_ace *owner_ace = NULL;
1767         canon_ace *group_ace = NULL;
1768         canon_ace *other_ace = NULL;
1769         mode_t and_bits;
1770         mode_t or_bits;
1771
1772         if (ace_count != 3) {
1773                 DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE entries for file %s to convert to \
1774 posix perms.\n", fsp->fsp_name ));
1775                 return False;
1776         }
1777
1778         for (ace_p = file_ace_list; ace_p; ace_p = ace_p->next) {
1779                 if (ace_p->owner_type == UID_ACE)
1780                         owner_ace = ace_p;
1781                 else if (ace_p->owner_type == GID_ACE)
1782                         group_ace = ace_p;
1783                 else if (ace_p->owner_type == WORLD_ACE)
1784                         other_ace = ace_p;
1785         }
1786
1787         if (!owner_ace || !group_ace || !other_ace) {
1788                 DEBUG(3,("convert_canon_ace_to_posix_perms: Can't get standard entries for file %s.\n",
1789                                 fsp->fsp_name ));
1790                 return False;
1791         }
1792
1793         *posix_perms = (mode_t)0;
1794
1795         *posix_perms |= owner_ace->perms;
1796         *posix_perms |= MAP_PERM(group_ace->perms, S_IRUSR, S_IRGRP);
1797         *posix_perms |= MAP_PERM(group_ace->perms, S_IWUSR, S_IWGRP);
1798         *posix_perms |= MAP_PERM(group_ace->perms, S_IXUSR, S_IXGRP);
1799         *posix_perms |= MAP_PERM(other_ace->perms, S_IRUSR, S_IROTH);
1800         *posix_perms |= MAP_PERM(other_ace->perms, S_IWUSR, S_IWOTH);
1801         *posix_perms |= MAP_PERM(other_ace->perms, S_IXUSR, S_IXOTH);
1802
1803         /* The owner must have at least read access. */
1804
1805         *posix_perms |= S_IRUSR;
1806         if (fsp->is_directory)
1807                 *posix_perms |= (S_IWUSR|S_IXUSR);
1808
1809         /* If requested apply the masks. */
1810
1811         /* Get the initial bits to apply. */
1812
1813         if (fsp->is_directory) {
1814                 and_bits = lp_dir_security_mask(snum);
1815                 or_bits = lp_force_dir_security_mode(snum);
1816         } else {
1817                 and_bits = lp_security_mask(snum);
1818                 or_bits = lp_force_security_mode(snum);
1819         }
1820
1821         *posix_perms = (((*posix_perms) & and_bits)|or_bits);
1822
1823         DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o to perm=0%o for file %s.\n",
1824                 (int)owner_ace->perms, (int)group_ace->perms, (int)other_ace->perms, (int)*posix_perms,
1825                 fsp->fsp_name ));
1826
1827         return True;
1828 }
1829
1830 static int nt_ace_comp( SEC_ACE *a1, SEC_ACE *a2)
1831 {
1832         if (a1->type == a2->type)
1833                 return 0;
1834
1835         if (a1->type == SEC_ACE_TYPE_ACCESS_DENIED && a2->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
1836                 return -1;
1837         return 1;
1838 }
1839
1840 /****************************************************************************
1841  Reply to query a security descriptor from an fsp. If it succeeds it allocates
1842  the space for the return elements and returns the size needed to return the
1843  security descriptor. This should be the only external function needed for
1844  the UNIX style get ACL.
1845 ****************************************************************************/
1846
1847 size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc)
1848 {
1849         SMB_STRUCT_STAT sbuf;
1850         SEC_ACE *nt_ace_list = NULL;
1851         DOM_SID owner_sid;
1852         DOM_SID group_sid;
1853         size_t sd_size = 0;
1854         SEC_ACL *psa = NULL;
1855         size_t num_acls = 0;
1856         size_t num_dir_acls = 0;
1857         size_t num_aces = 0;
1858         SMB_ACL_T posix_acl = NULL;
1859         SMB_ACL_T dir_acl = NULL;
1860         canon_ace *file_ace = NULL;
1861         canon_ace *dir_ace = NULL;
1862  
1863         *ppdesc = NULL;
1864
1865         DEBUG(10,("get_nt_acl: called for file %s\n", fsp->fsp_name ));
1866
1867         if(fsp->is_directory || fsp->fd == -1) {
1868
1869                 /* Get the stat struct for the owner info. */
1870                 if(vfs_stat(fsp->conn,fsp->fsp_name, &sbuf) != 0) {
1871                         return 0;
1872                 }
1873                 /*
1874                  * Get the ACL from the path.
1875                  */
1876
1877                 posix_acl = sys_acl_get_file(fsp->fsp_name, SMB_ACL_TYPE_ACCESS);
1878
1879                 /*
1880                  * If it's a directory get the default POSIX ACL.
1881                  */
1882
1883                 if(fsp->is_directory)
1884                         dir_acl = sys_acl_get_file(fsp->fsp_name, SMB_ACL_TYPE_DEFAULT);
1885
1886         } else {
1887
1888                 /* Get the stat struct for the owner info. */
1889                 if(vfs_fstat(fsp,fsp->fd,&sbuf) != 0) {
1890                         return 0;
1891                 }
1892                 /*
1893                  * Get the ACL from the fd.
1894                  */
1895                 posix_acl = sys_acl_get_fd(fsp->fd);
1896         }
1897
1898         DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n",
1899                         posix_acl ? "present" :  "absent",
1900                         dir_acl ? "present" :  "absent" ));
1901
1902         /*
1903          * Get the owner, group and world SIDs.
1904          */
1905
1906         create_file_sids(&sbuf, &owner_sid, &group_sid);
1907
1908         /* Create the canon_ace lists. */
1909         file_ace = canonicalise_acl( fsp, posix_acl, &sbuf,  &owner_sid, &group_sid);
1910         num_acls = count_canon_ace_list(file_ace);
1911
1912         /* We must have *some* ACLS. */
1913
1914         if (num_acls == 0) {
1915                 DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", fsp->fsp_name ));
1916                 return 0;
1917         }
1918
1919         if (fsp->is_directory) { 
1920                 /*
1921                  * If we have to fake a default ACL then this is the mode to use.
1922                  */
1923                 sbuf.st_mode = unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name);
1924
1925                 dir_ace = canonicalise_acl(fsp, dir_acl, &sbuf, &owner_sid, &group_sid);
1926                 num_dir_acls = count_canon_ace_list(dir_ace);
1927         }
1928
1929         /* Allocate the ace list. */
1930         if ((nt_ace_list = (SEC_ACE *)malloc((num_acls + num_dir_acls)* sizeof(SEC_ACE))) == NULL) {
1931                 DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
1932                 goto done;
1933         }
1934
1935         memset(nt_ace_list, '\0', (num_acls + num_dir_acls) * sizeof(SEC_ACE) );
1936
1937         /*
1938          * Create the NT ACE list from the canonical ace lists.
1939          */
1940
1941         {
1942                 canon_ace *ace;
1943                 int nt_acl_type;
1944                 int i;
1945
1946                 ace = file_ace;
1947
1948                 for (i = 0; i < num_acls; i++, ace = ace->next) {
1949                         SEC_ACCESS acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
1950                         init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc, 0);
1951                 }
1952
1953                 ace = dir_ace;
1954
1955                 for (i = 0; i < num_dir_acls; i++, ace = ace->next) {
1956                         SEC_ACCESS acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
1957                         init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc, 
1958                                         SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY);
1959                 }
1960
1961                 /*
1962                  * Sort to force deny entries to the front.
1963                  */
1964
1965                 if (num_acls + num_dir_acls)
1966                         qsort( nt_ace_list, num_acls + num_dir_acls, sizeof(nt_ace_list[0]), QSORT_CAST nt_ace_comp);
1967         }
1968
1969         if (num_acls) {
1970                 if((psa = make_sec_acl( main_loop_talloc_get(), ACL_REVISION, num_aces, nt_ace_list)) == NULL) {
1971                         DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
1972                         goto done;
1973                 }
1974         }
1975
1976         *ppdesc = make_standard_sec_desc( main_loop_talloc_get(), &owner_sid, &group_sid, psa, &sd_size);
1977
1978         if(!*ppdesc) {
1979                 DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
1980                 sd_size = 0;
1981         }
1982
1983   done:
1984
1985         if (posix_acl)  
1986                 sys_acl_free_acl(posix_acl);
1987         if (dir_acl)
1988                 sys_acl_free_acl(dir_acl);
1989         free_canon_ace_list(file_ace);
1990         free_canon_ace_list(dir_ace);
1991         SAFE_FREE(nt_ace_list);
1992
1993         return sd_size;
1994 }
1995
1996 /****************************************************************************
1997  Reply to set a security descriptor on an fsp. security_info_sent is the
1998  description of the following NT ACL.
1999  This should be the only external function needed for the UNIX style set ACL.
2000 ****************************************************************************/
2001
2002 BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
2003 {
2004         connection_struct *conn = fsp->conn;
2005         uid_t user = (uid_t)-1;
2006         gid_t grp = (gid_t)-1;
2007         SMB_STRUCT_STAT sbuf;  
2008         DOM_SID file_owner_sid;
2009         DOM_SID file_grp_sid;
2010         canon_ace *file_ace_list = NULL;
2011         canon_ace *dir_ace_list = NULL;
2012         BOOL acl_perms = False;
2013         mode_t orig_mode = (mode_t)0;
2014         uid_t orig_uid;
2015         gid_t orig_gid;
2016
2017         DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name ));
2018
2019         /*
2020          * Get the current state of the file.
2021          */
2022
2023         if(fsp->is_directory || fsp->fd == -1) {
2024                 if(vfs_stat(fsp->conn,fsp->fsp_name, &sbuf) != 0)
2025                         return False;
2026         } else {
2027                 if(vfs_fstat(fsp,fsp->fd,&sbuf) != 0)
2028                         return False;
2029         }
2030
2031         /* Save the original elements we check against. */
2032         orig_mode = sbuf.st_mode;
2033         orig_uid = sbuf.st_uid;
2034         orig_gid = sbuf.st_gid;
2035
2036         /*
2037          * Unpack the user/group/world id's.
2038          */
2039
2040         if (!unpack_nt_owners( &sbuf, &user, &grp, security_info_sent, psd))
2041                 return False;
2042
2043         /*
2044          * Do we need to chown ?
2045          */
2046
2047         if((user != (uid_t)-1 || grp != (uid_t)-1) && (orig_uid != user || orig_gid != grp)) {
2048
2049                 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
2050                                 fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
2051
2052                 if(vfs_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
2053                         DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
2054                                 fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
2055                         return False;
2056                 }
2057
2058                 /*
2059                  * Recheck the current state of the file, which may have changed.
2060                  * (suid/sgid bits, for instance)
2061                  */
2062
2063                 if(fsp->is_directory) {
2064                         if(vfs_stat(fsp->conn, fsp->fsp_name, &sbuf) != 0) {
2065                                 return False;
2066                         }
2067                 } else {
2068
2069                         int ret;
2070     
2071                         if(fsp->fd == -1)
2072                                 ret = vfs_stat(fsp->conn, fsp->fsp_name, &sbuf);
2073                         else
2074                                 ret = vfs_fstat(fsp,fsp->fd,&sbuf);
2075   
2076                         if(ret != 0)
2077                                 return False;
2078                 }
2079
2080                 /* Save the original elements we check against. */
2081                 orig_mode = sbuf.st_mode;
2082                 orig_uid = sbuf.st_uid;
2083                 orig_gid = sbuf.st_gid;
2084         }
2085
2086         create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid);
2087
2088         acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid,
2089                                                                         &file_ace_list, &dir_ace_list, security_info_sent, psd);
2090
2091         if ((file_ace_list == NULL) && (dir_ace_list == NULL)) {
2092                 /* W2K traverse DACL set - ignore. */
2093                 return True;
2094     }
2095
2096         if (!acl_perms) {
2097                 DEBUG(3,("set_nt_acl: cannot set permissions\n"));
2098                 free_canon_ace_list(file_ace_list);
2099                 free_canon_ace_list(dir_ace_list); 
2100                 return False;
2101         }
2102
2103         /*
2104          * Only change security if we got a DACL.
2105          */
2106
2107         if((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl != NULL)) {
2108
2109                 BOOL acl_set_support = False;
2110                 BOOL ret = False;
2111
2112                 /*
2113                  * Try using the POSIX ACL set first. Fall back to chmod if
2114                  * we have no ACL support on this filesystem.
2115                  */
2116
2117                 if (acl_perms && file_ace_list) {
2118                         ret = set_canon_ace_list(fsp, file_ace_list, False, &acl_set_support);
2119                         if (acl_set_support && ret == False) {
2120                                 DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) ));
2121                                 free_canon_ace_list(file_ace_list);
2122                                 free_canon_ace_list(dir_ace_list); 
2123                                 return False;
2124                         }
2125                 }
2126
2127                 if (acl_perms && acl_set_support && fsp->is_directory) {
2128                         if (dir_ace_list) {
2129                                 if (!set_canon_ace_list(fsp, dir_ace_list, True, &acl_set_support)) {
2130                                         DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) ));
2131                                         free_canon_ace_list(file_ace_list);
2132                                         free_canon_ace_list(dir_ace_list); 
2133                                         return False;
2134                                 }
2135                         } else {
2136
2137                                 /*
2138                                  * No default ACL - delete one if it exists.
2139                                  */
2140
2141                                 if (sys_acl_delete_def_file(fsp->fsp_name) == -1) {
2142                                         DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno)));
2143                                         free_canon_ace_list(file_ace_list);
2144                                         return False;
2145                                 }
2146                         }
2147                 }
2148
2149                 /*
2150                  * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
2151                  */
2152
2153                 if(!acl_set_support && acl_perms) {
2154                         mode_t posix_perms;
2155
2156                         if (!convert_canon_ace_to_posix_perms( fsp, file_ace_list, &posix_perms)) {
2157                                 free_canon_ace_list(file_ace_list);
2158                                 free_canon_ace_list(dir_ace_list);
2159                                 DEBUG(3,("set_nt_acl: failed to convert file acl to posix permissions for file %s.\n",
2160                                         fsp->fsp_name ));
2161                                 return False;
2162                         }
2163
2164                         if (orig_mode != posix_perms) {
2165
2166                                 DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
2167                                         fsp->fsp_name, (unsigned int)posix_perms ));
2168
2169                                 if(conn->vfs_ops.chmod(conn,fsp->fsp_name, posix_perms) == -1) {
2170                                         DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n",
2171                                                         fsp->fsp_name, (unsigned int)posix_perms, strerror(errno) ));
2172                                         free_canon_ace_list(file_ace_list);
2173                                         free_canon_ace_list(dir_ace_list);
2174                                         return False;
2175                                 }
2176                         }
2177                 }
2178         }
2179
2180         free_canon_ace_list(file_ace_list);
2181         free_canon_ace_list(dir_ace_list); 
2182
2183         return True;
2184 }
2185
2186 /****************************************************************************
2187  Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
2188  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
2189 ****************************************************************************/
2190
2191 static int chmod_acl_internals( SMB_ACL_T posix_acl, mode_t mode)
2192 {
2193         int entry_id = SMB_ACL_FIRST_ENTRY;
2194         SMB_ACL_ENTRY_T entry;
2195         int num_entries = 0;
2196
2197         while ( sys_acl_get_entry(posix_acl, entry_id, &entry) == 1) {
2198                 SMB_ACL_TAG_T tagtype;
2199                 SMB_ACL_PERMSET_T permset;
2200                 mode_t perms;
2201
2202                 /* get_next... */
2203                 if (entry_id == SMB_ACL_FIRST_ENTRY)
2204                         entry_id = SMB_ACL_NEXT_ENTRY;
2205
2206                 if (sys_acl_get_tag_type(entry, &tagtype) == -1)
2207                         return -1;
2208
2209                 if (sys_acl_get_permset(entry, &permset) == -1)
2210                         return -1;
2211
2212                 num_entries++;
2213
2214                 switch(tagtype) {
2215                         case SMB_ACL_USER_OBJ:
2216                                 perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
2217                 break;
2218                         case SMB_ACL_GROUP_OBJ:
2219                                 perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
2220                                 break;
2221                         case SMB_ACL_MASK:
2222                                 perms = S_IRUSR|S_IWUSR|S_IXUSR;
2223                                 break;
2224                         case SMB_ACL_OTHER:
2225                                 perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
2226                                 break;
2227                         default:
2228                                 continue;
2229                 }
2230
2231                 if (map_acl_perms_to_permset(perms, &permset) == -1)
2232                         return -1;
2233
2234                 if (sys_acl_set_permset(entry, permset) == -1)
2235                         return -1;
2236         }
2237
2238         /*
2239          * If this is a simple 3 element ACL or no elements then it's a standard
2240          * UNIX permission set. Just use chmod...       
2241          */
2242
2243         if ((num_entries == 3) || (num_entries == 0))
2244                 return -1;
2245
2246         return 0;
2247 }
2248
2249 /****************************************************************************
2250  Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
2251  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
2252  Note that name is in UNIX character set.
2253 ****************************************************************************/
2254
2255 int chmod_acl(const char *name, mode_t mode)
2256 {
2257         SMB_ACL_T posix_acl = NULL;
2258         int ret = -1;
2259
2260         if ((posix_acl = sys_acl_get_file(name, SMB_ACL_TYPE_ACCESS)) == NULL)
2261                 return -1;
2262
2263         if ((ret = chmod_acl_internals(posix_acl, mode)) == -1)
2264                 goto done;
2265
2266         ret = sys_acl_set_file(name, SMB_ACL_TYPE_ACCESS, posix_acl);
2267
2268   done:
2269
2270         sys_acl_free_acl(posix_acl);
2271         return ret;
2272 }
2273
2274 /****************************************************************************
2275  Do an fchmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
2276  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
2277 ****************************************************************************/
2278
2279 int fchmod_acl(int fd, mode_t mode)
2280 {
2281         SMB_ACL_T posix_acl = NULL;
2282         int ret = -1;
2283
2284         if ((posix_acl = sys_acl_get_fd(fd)) == NULL)
2285                 return -1;
2286
2287         if ((ret = chmod_acl_internals(posix_acl, mode)) == -1)
2288                 goto done;
2289
2290         ret = sys_acl_set_fd(fd, posix_acl);
2291
2292   done:
2293
2294         sys_acl_free_acl(posix_acl);
2295         return ret;
2296 }
2297
2298 BOOL directory_has_default_acl(const char *fname)
2299 {
2300         SMB_ACL_T dir_acl = sys_acl_get_file( fname, SMB_ACL_TYPE_DEFAULT);
2301         BOOL has_acl = False;
2302         SMB_ACL_ENTRY_T entry;
2303
2304         if (dir_acl != NULL && (sys_acl_get_entry(dir_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1))
2305                 has_acl = True;
2306
2307         sys_acl_free_acl(dir_acl);
2308         return has_acl;
2309 }