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