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