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