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