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