Ensure 'blank' entries show up in both default and normal entries to
[sfrench/samba-autobuild/.git] / source / smbd / posix_acls.c
1 /*
2    Unix SMB/CIFS implementation.
3    SMB NT Security Descriptor / Unix permission conversion.
4    Copyright (C) Jeremy Allison 1994-2000.
5    Copyright (C) Andreas Gruenbacher 2002.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 /****************************************************************************
25  Data structures representing the internal ACE format.
26 ****************************************************************************/
27
28 enum ace_owner {UID_ACE, GID_ACE, WORLD_ACE};
29 enum ace_attribute {ALLOW_ACE, DENY_ACE}; /* Used for incoming NT ACLS. */
30
31 typedef union posix_id {
32                 uid_t uid;
33                 gid_t gid;
34                 int world;
35 } posix_id;
36
37 typedef struct canon_ace {
38         struct canon_ace *next, *prev;
39         SMB_ACL_TAG_T type;
40         mode_t perms; /* Only use S_I(R|W|X)USR mode bits here. */
41         DOM_SID trustee;
42         enum ace_owner owner_type;
43         enum ace_attribute attr;
44         posix_id unix_ug; 
45 } canon_ace;
46
47 #define ALL_ACE_PERMS (S_IRUSR|S_IWUSR|S_IXUSR)
48
49 /****************************************************************************
50  Functions to manipulate the internal ACE format.
51 ****************************************************************************/
52
53 /****************************************************************************
54  Count a linked list of canonical ACE entries.
55 ****************************************************************************/
56
57 static size_t count_canon_ace_list( canon_ace *list_head )
58 {
59         size_t count = 0;
60         canon_ace *ace;
61
62         for (ace = list_head; ace; ace = ace->next)
63                 count++;
64
65         return count;
66 }
67
68 /****************************************************************************
69  Free a linked list of canonical ACE entries.
70 ****************************************************************************/
71
72 static void free_canon_ace_list( canon_ace *list_head )
73 {
74         while (list_head) {
75                 canon_ace *old_head = list_head;
76                 DLIST_REMOVE(list_head, list_head);
77                 SAFE_FREE(old_head);
78         }
79 }
80
81 /****************************************************************************
82  Function to duplicate a canon_ace entry.
83 ****************************************************************************/
84
85 static canon_ace *dup_canon_ace( canon_ace *src_ace)
86 {
87         canon_ace *dst_ace = (canon_ace *)malloc(sizeof(canon_ace));
88
89         if (dst_ace == NULL)
90                 return NULL;
91
92         *dst_ace = *src_ace;
93         dst_ace->prev = dst_ace->next = NULL;
94         return dst_ace;
95 }
96
97 /****************************************************************************
98  Print out a canon ace.
99 ****************************************************************************/
100
101 static void print_canon_ace(canon_ace *pace, int num)
102 {
103         fstring str;
104
105         dbgtext( "canon_ace index %d. Type = %s ", num, pace->attr == ALLOW_ACE ? "allow" : "deny" );
106         dbgtext( "SID = %s ", sid_to_string( str, &pace->trustee));
107         if (pace->owner_type == UID_ACE) {
108                 const char *u_name = uidtoname(pace->unix_ug.uid);
109                 dbgtext( "uid %u (%s) ", (unsigned int)pace->unix_ug.uid, u_name);
110         } else if (pace->owner_type == GID_ACE) {
111                 char *g_name = gidtoname(pace->unix_ug.gid);
112                 dbgtext( "gid %u (%s) ", (unsigned int)pace->unix_ug.gid, g_name);
113         } else
114                 dbgtext( "other ");
115         switch (pace->type) {
116                 case SMB_ACL_USER:
117                         dbgtext( "SMB_ACL_USER ");
118                         break;
119                 case SMB_ACL_USER_OBJ:
120                         dbgtext( "SMB_ACL_USER_OBJ ");
121                         break;
122                 case SMB_ACL_GROUP:
123                         dbgtext( "SMB_ACL_GROUP ");
124                         break;
125                 case SMB_ACL_GROUP_OBJ:
126                         dbgtext( "SMB_ACL_GROUP_OBJ ");
127                         break;
128                 case SMB_ACL_OTHER:
129                         dbgtext( "SMB_ACL_OTHER ");
130                         break;
131         }
132         dbgtext( "perms ");
133         dbgtext( "%c", pace->perms & S_IRUSR ? 'r' : '-');
134         dbgtext( "%c", pace->perms & S_IWUSR ? 'w' : '-');
135         dbgtext( "%c\n", pace->perms & S_IXUSR ? 'x' : '-');
136 }
137
138 /****************************************************************************
139  Print out a canon ace list.
140 ****************************************************************************/
141
142 static void print_canon_ace_list(const char *name, canon_ace *ace_list)
143 {
144         int count = 0;
145
146         if( DEBUGLVL( 10 )) {
147                 dbgtext( "print_canon_ace_list: %s\n", name );
148                 for (;ace_list; ace_list = ace_list->next, count++)
149                         print_canon_ace(ace_list, count );
150         }
151 }
152
153 /****************************************************************************
154  Map POSIX ACL perms to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
155 ****************************************************************************/
156
157 static mode_t convert_permset_to_mode_t(connection_struct *conn, SMB_ACL_PERMSET_T permset)
158 {
159         mode_t ret = 0;
160
161         ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRUSR : 0);
162         ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWUSR : 0);
163         ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXUSR : 0);
164
165         return ret;
166 }
167
168 /****************************************************************************
169  Map generic UNIX permissions to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
170 ****************************************************************************/
171
172 static mode_t unix_perms_to_acl_perms(mode_t mode, int r_mask, int w_mask, int x_mask)
173 {
174         mode_t ret = 0;
175
176         if (mode & r_mask)
177                 ret |= S_IRUSR;
178         if (mode & w_mask)
179                 ret |= S_IWUSR;
180         if (mode & x_mask)
181                 ret |= S_IXUSR;
182
183         return ret;
184 }
185
186 /****************************************************************************
187  Map canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits) to
188  an SMB_ACL_PERMSET_T.
189 ****************************************************************************/
190
191 static int map_acl_perms_to_permset(connection_struct *conn, mode_t mode, SMB_ACL_PERMSET_T *p_permset)
192 {
193         if (SMB_VFS_SYS_ACL_CLEAR_PERMS(conn, *p_permset) ==  -1)
194                 return -1;
195         if (mode & S_IRUSR) {
196                 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_READ) == -1)
197                         return -1;
198         }
199         if (mode & S_IWUSR) {
200                 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_WRITE) == -1)
201                         return -1;
202         }
203         if (mode & S_IXUSR) {
204                 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_EXECUTE) == -1)
205                         return -1;
206         }
207         return 0;
208 }
209 /****************************************************************************
210  Function to create owner and group SIDs from a SMB_STRUCT_STAT.
211 ****************************************************************************/
212
213 static void create_file_sids(SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SID *pgroup_sid)
214 {
215         uid_to_sid( powner_sid, psbuf->st_uid );
216         gid_to_sid( pgroup_sid, psbuf->st_gid );
217 }
218
219 /****************************************************************************
220  Merge aces with a common sid - if both are allow or deny, OR the permissions together and
221  delete the second one. If the first is deny, mask the permissions off and delete the allow
222  if the permissions become zero, delete the deny if the permissions are non zero.
223 ****************************************************************************/
224
225 static void merge_aces( canon_ace **pp_list_head )
226 {
227         canon_ace *list_head = *pp_list_head;
228         canon_ace *curr_ace_outer;
229         canon_ace *curr_ace_outer_next;
230
231         /*
232          * First, merge allow entries with identical SIDs, and deny entries
233          * with identical SIDs.
234          */
235
236         for (curr_ace_outer = list_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
237                 canon_ace *curr_ace;
238                 canon_ace *curr_ace_next;
239
240                 curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
241
242                 for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
243
244                         curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
245
246                         if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
247                                 (curr_ace->attr == curr_ace_outer->attr)) {
248
249                                 if( DEBUGLVL( 10 )) {
250                                         dbgtext("merge_aces: Merging ACE's\n");
251                                         print_canon_ace( curr_ace_outer, 0);
252                                         print_canon_ace( curr_ace, 0);
253                                 }
254
255                                 /* Merge two allow or two deny ACE's. */
256
257                                 curr_ace_outer->perms |= curr_ace->perms;
258                                 DLIST_REMOVE(list_head, curr_ace);
259                                 SAFE_FREE(curr_ace);
260                                 curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
261                         }
262                 }
263         }
264
265         /*
266          * Now go through and mask off allow permissions with deny permissions.
267          * We can delete either the allow or deny here as we know that each SID
268          * appears only once in the list.
269          */
270
271         for (curr_ace_outer = list_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
272                 canon_ace *curr_ace;
273                 canon_ace *curr_ace_next;
274
275                 curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
276
277                 for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
278
279                         curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
280
281                         /*
282                          * Subtract ACE's with different entries. Due to the ordering constraints
283                          * we've put on the ACL, we know the deny must be the first one.
284                          */
285
286                         if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
287                                 (curr_ace_outer->attr == DENY_ACE) && (curr_ace->attr == ALLOW_ACE)) {
288
289                                 if( DEBUGLVL( 10 )) {
290                                         dbgtext("merge_aces: Masking ACE's\n");
291                                         print_canon_ace( curr_ace_outer, 0);
292                                         print_canon_ace( curr_ace, 0);
293                                 }
294
295                                 curr_ace->perms &= ~curr_ace_outer->perms;
296
297                                 if (curr_ace->perms == 0) {
298
299                                         /*
300                                          * The deny overrides the allow. Remove the allow.
301                                          */
302
303                                         DLIST_REMOVE(list_head, curr_ace);
304                                         SAFE_FREE(curr_ace);
305                                         curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
306
307                                 } else {
308
309                                         /*
310                                          * Even after removing permissions, there
311                                          * are still allow permissions - delete the deny.
312                                          * It is safe to delete the deny here,
313                                          * as we are guarenteed by the deny first
314                                          * ordering that all the deny entries for
315                                          * this SID have already been merged into one
316                                          * before we can get to an allow ace.
317                                          */
318
319                                         DLIST_REMOVE(list_head, curr_ace_outer);
320                                         SAFE_FREE(curr_ace_outer);
321                                         break;
322                                 }
323                         }
324
325                 } /* end for curr_ace */
326         } /* end for curr_ace_outer */
327
328         /* We may have modified the list. */
329
330         *pp_list_head = list_head;
331 }
332
333 /****************************************************************************
334  Check if we need to return NT4.x compatible ACL entries.
335 ****************************************************************************/
336
337 static BOOL nt4_compatible_acls(void)
338 {
339         const char *compat = lp_acl_compatibility();
340
341         if (*compat == '\0') {
342                 enum remote_arch_types ra_type = get_remote_arch();
343
344                 /* Automatically adapt to client */
345                 return (ra_type <= RA_WINNT);
346         } else
347                 return (strequal(compat, "winnt"));
348 }
349
350
351 /****************************************************************************
352  Map canon_ace perms to permission bits NT.
353  The attr element is not used here - we only process deny entries on set,
354  not get. Deny entries are implicit on get with ace->perms = 0.
355 ****************************************************************************/
356
357 static SEC_ACCESS map_canon_ace_perms(int *pacl_type, DOM_SID *powner_sid, canon_ace *ace)
358 {
359         SEC_ACCESS sa;
360         uint32 nt_mask = 0;
361
362         *pacl_type = SEC_ACE_TYPE_ACCESS_ALLOWED;
363
364         if ((ace->perms & ALL_ACE_PERMS) == ALL_ACE_PERMS) {
365                         nt_mask = UNIX_ACCESS_RWX;
366         } else if ((ace->perms & ALL_ACE_PERMS) == (mode_t)0) {
367                 /*
368                  * Windows NT refuses to display ACEs with no permissions in them (but
369                  * they are perfectly legal with Windows 2000). If the ACE has empty
370                  * permissions we cannot use 0, so we use the otherwise unused
371                  * WRITE_OWNER permission, which we ignore when we set an ACL.
372                  * We abstract this into a #define of UNIX_ACCESS_NONE to allow this
373                  * to be changed in the future.
374                  */
375
376                 if (nt4_compatible_acls())
377                         nt_mask = UNIX_ACCESS_NONE;
378                 else
379                         nt_mask = 0;
380         } else {
381                 nt_mask |= ((ace->perms & S_IRUSR) ? UNIX_ACCESS_R : 0 );
382                 nt_mask |= ((ace->perms & S_IWUSR) ? UNIX_ACCESS_W : 0 );
383                 nt_mask |= ((ace->perms & S_IXUSR) ? UNIX_ACCESS_X : 0 );
384         }
385
386         DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n",
387                         (unsigned int)ace->perms, (unsigned int)nt_mask ));
388
389         init_sec_access(&sa,nt_mask);
390         return sa;
391 }
392
393 /****************************************************************************
394  Map NT perms to a UNIX mode_t.
395 ****************************************************************************/
396
397 #define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES)
398 #define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA|FILE_WRITE_ATTRIBUTES)
399 #define FILE_SPECIFIC_EXECUTE_BITS (FILE_EXECUTE)
400
401 static mode_t map_nt_perms( SEC_ACCESS sec_access, int type)
402 {
403         mode_t mode = 0;
404
405         switch(type) {
406         case S_IRUSR:
407                 if(sec_access.mask & GENERIC_ALL_ACCESS)
408                         mode = S_IRUSR|S_IWUSR|S_IXUSR;
409                 else {
410                         mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRUSR : 0;
411                         mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWUSR : 0;
412                         mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXUSR : 0;
413                 }
414                 break;
415         case S_IRGRP:
416                 if(sec_access.mask & GENERIC_ALL_ACCESS)
417                         mode = S_IRGRP|S_IWGRP|S_IXGRP;
418                 else {
419                         mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRGRP : 0;
420                         mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWGRP : 0;
421                         mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXGRP : 0;
422                 }
423                 break;
424         case S_IROTH:
425                 if(sec_access.mask & GENERIC_ALL_ACCESS)
426                         mode = S_IROTH|S_IWOTH|S_IXOTH;
427                 else {
428                         mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IROTH : 0;
429                         mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWOTH : 0;
430                         mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXOTH : 0;
431                 }
432                 break;
433         }
434
435         return mode;
436 }
437
438 /****************************************************************************
439  Unpack a SEC_DESC into a UNIX owner and group.
440 ****************************************************************************/
441
442 static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, SEC_DESC *psd)
443 {
444         DOM_SID owner_sid;
445         DOM_SID grp_sid;
446
447         *puser = (uid_t)-1;
448         *pgrp = (gid_t)-1;
449
450         if(security_info_sent == 0) {
451                 DEBUG(0,("unpack_nt_owners: no security info sent !\n"));
452                 return True;
453         }
454
455         /*
456          * Validate the owner and group SID's.
457          */
458
459         memset(&owner_sid, '\0', sizeof(owner_sid));
460         memset(&grp_sid, '\0', sizeof(grp_sid));
461
462         DEBUG(5,("unpack_nt_owners: validating owner_sids.\n"));
463
464         /*
465          * Don't immediately fail if the owner sid cannot be validated.
466          * This may be a group chown only set.
467          */
468
469         if (security_info_sent & OWNER_SECURITY_INFORMATION) {
470                 sid_copy(&owner_sid, psd->owner_sid);
471                 if (NT_STATUS_IS_ERR(sid_to_uid(&owner_sid, puser))) {
472 #if ACL_FORCE_UNMAPPABLE
473                         /* this allows take ownership to work reasonably */
474                         extern struct current_user current_user;
475                         *puser = current_user.uid;
476 #else
477                         DEBUG(3,("unpack_nt_owners: unable to validate owner sid for %s\n",
478                                  sid_string_static(&owner_sid)));
479                         return False;
480 #endif
481                 }
482         }
483
484         /*
485          * Don't immediately fail if the group sid cannot be validated.
486          * This may be an owner chown only set.
487          */
488
489         if (security_info_sent & GROUP_SECURITY_INFORMATION) {
490                 sid_copy(&grp_sid, psd->grp_sid);
491                 if (NT_STATUS_IS_ERR(sid_to_gid( &grp_sid, pgrp))) {
492 #if ACL_FORCE_UNMAPPABLE
493                         /* this allows take group ownership to work reasonably */
494                         extern struct current_user current_user;
495                         *pgrp = current_user.gid;
496 #else
497                         DEBUG(3,("unpack_nt_owners: unable to validate group sid.\n"));
498                         return False;
499 #endif
500                 }
501         }
502
503         DEBUG(5,("unpack_nt_owners: owner_sids validated.\n"));
504
505         return True;
506 }
507
508 /****************************************************************************
509  Ensure the enforced permissions for this share apply.
510 ****************************************************************************/
511
512 static void apply_default_perms(files_struct *fsp, canon_ace *pace, mode_t type)
513 {
514         int snum = SNUM(fsp->conn);
515         mode_t and_bits = (mode_t)0;
516         mode_t or_bits = (mode_t)0;
517
518         /* Get the initial bits to apply. */
519
520         if (fsp->is_directory) {
521                 and_bits = lp_dir_security_mask(snum);
522                 or_bits = lp_force_dir_security_mode(snum);
523         } else {
524                 and_bits = lp_security_mask(snum);
525                 or_bits = lp_force_security_mode(snum);
526         }
527
528         /* Now bounce them into the S_USR space. */     
529         switch(type) {
530         case S_IRUSR:
531                 /* Ensure owner has read access. */
532                 pace->perms |= S_IRUSR;
533                 if (fsp->is_directory)
534                         pace->perms |= (S_IWUSR|S_IXUSR);
535                 and_bits = unix_perms_to_acl_perms(and_bits, S_IRUSR, S_IWUSR, S_IXUSR);
536                 or_bits = unix_perms_to_acl_perms(or_bits, S_IRUSR, S_IWUSR, S_IXUSR);
537                 break;
538         case S_IRGRP:
539                 and_bits = unix_perms_to_acl_perms(and_bits, S_IRGRP, S_IWGRP, S_IXGRP);
540                 or_bits = unix_perms_to_acl_perms(or_bits, S_IRGRP, S_IWGRP, S_IXGRP);
541                 break;
542         case S_IROTH:
543                 and_bits = unix_perms_to_acl_perms(and_bits, S_IROTH, S_IWOTH, S_IXOTH);
544                 or_bits = unix_perms_to_acl_perms(or_bits, S_IROTH, S_IWOTH, S_IXOTH);
545                 break;
546         }
547
548         pace->perms = ((pace->perms & and_bits)|or_bits);
549 }
550
551 /****************************************************************************
552  Check if a given uid/SID is in a group gid/SID. This is probably very
553  expensive and will need optimisation. A *lot* of optimisation :-). JRA.
554 ****************************************************************************/
555
556 static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace )
557 {
558         extern DOM_SID global_sid_World;
559         fstring u_name;
560         fstring g_name;
561         extern struct current_user current_user;
562
563         /* "Everyone" always matches every uid. */
564
565         if (sid_equal(&group_ace->trustee, &global_sid_World))
566                 return True;
567
568         /* Assume that the current user is in the current group (force group) */
569
570         if (uid_ace->unix_ug.uid == current_user.uid && group_ace->unix_ug.gid == current_user.gid)
571                 return True;
572
573         fstrcpy(u_name, uidtoname(uid_ace->unix_ug.uid));
574         fstrcpy(g_name, gidtoname(group_ace->unix_ug.gid));
575
576         /*
577          * Due to the winbind interfaces we need to do this via names,
578          * not uids/gids.
579          */
580
581         return user_in_group_list(u_name, g_name, NULL, 0);
582 }
583
584 /****************************************************************************
585  A well formed POSIX file or default ACL has at least 3 entries, a 
586  SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ.
587  In addition, the owner must always have at least read access.
588  When using this call on get_acl, the pst struct is valid and contains
589  the mode of the file. When using this call on set_acl, the pst struct has
590  been modified to have a mode containing the default for this file or directory
591  type.
592 ****************************************************************************/
593
594 static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
595                                                         files_struct *fsp,
596                                                         DOM_SID *pfile_owner_sid,
597                                                         DOM_SID *pfile_grp_sid,
598                                                         SMB_STRUCT_STAT *pst,
599                                                         BOOL setting_acl)
600 {
601         extern DOM_SID global_sid_World;
602         canon_ace *pace;
603         BOOL got_user = False;
604         BOOL got_grp = False;
605         BOOL got_other = False;
606         canon_ace *pace_other = NULL;
607         canon_ace *pace_group = NULL;
608
609         for (pace = *pp_ace; pace; pace = pace->next) {
610                 if (pace->type == SMB_ACL_USER_OBJ) {
611
612                         if (setting_acl)
613                                 apply_default_perms(fsp, pace, S_IRUSR);
614                         got_user = True;
615
616                 } else if (pace->type == SMB_ACL_GROUP_OBJ) {
617
618                         /*
619                          * Ensure create mask/force create mode is respected on set.
620                          */
621
622                         if (setting_acl)
623                                 apply_default_perms(fsp, pace, S_IRGRP);
624                         got_grp = True;
625                         pace_group = pace;
626
627                 } else if (pace->type == SMB_ACL_OTHER) {
628
629                         /*
630                          * Ensure create mask/force create mode is respected on set.
631                          */
632
633                         if (setting_acl)
634                                 apply_default_perms(fsp, pace, S_IROTH);
635                         got_other = True;
636                         pace_other = pace;
637                 }
638         }
639
640         if (!got_user) {
641                 if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
642                         DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
643                         return False;
644                 }
645
646                 ZERO_STRUCTP(pace);
647                 pace->type = SMB_ACL_USER_OBJ;
648                 pace->owner_type = UID_ACE;
649                 pace->unix_ug.uid = pst->st_uid;
650                 pace->trustee = *pfile_owner_sid;
651                 pace->attr = ALLOW_ACE;
652
653                 if (setting_acl) {
654                         /* If we only got an "everyone" perm, just use that. */
655                         if (!got_grp && got_other)
656                                 pace->perms = pace_other->perms;
657                         else if (got_grp && uid_entry_in_group(pace, pace_group))
658                                 pace->perms = pace_group->perms;
659                         else
660                                 pace->perms = 0;
661
662                         apply_default_perms(fsp, pace, S_IRUSR);
663                 } else {
664                         pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR);
665                 }
666
667                 DLIST_ADD(*pp_ace, pace);
668         }
669
670         if (!got_grp) {
671                 if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
672                         DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
673                         return False;
674                 }
675
676                 ZERO_STRUCTP(pace);
677                 pace->type = SMB_ACL_GROUP_OBJ;
678                 pace->owner_type = GID_ACE;
679                 pace->unix_ug.uid = pst->st_gid;
680                 pace->trustee = *pfile_grp_sid;
681                 pace->attr = ALLOW_ACE;
682                 if (setting_acl) {
683                         /* If we only got an "everyone" perm, just use that. */
684                         if (got_other)
685                                 pace->perms = pace_other->perms;
686                         else
687                                 pace->perms = 0;
688                         apply_default_perms(fsp, pace, S_IRGRP);
689                 } else {
690                         pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP);
691                 }
692
693                 DLIST_ADD(*pp_ace, pace);
694         }
695
696         if (!got_other) {
697                 if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
698                         DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
699                         return False;
700                 }
701
702                 ZERO_STRUCTP(pace);
703                 pace->type = SMB_ACL_OTHER;
704                 pace->owner_type = WORLD_ACE;
705                 pace->unix_ug.world = -1;
706                 pace->trustee = global_sid_World;
707                 pace->attr = ALLOW_ACE;
708                 if (setting_acl) {
709                         pace->perms = 0;
710                         apply_default_perms(fsp, pace, S_IROTH);
711                 } else
712                         pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IROTH, S_IWOTH, S_IXOTH);
713
714                 DLIST_ADD(*pp_ace, pace);
715         }
716
717         return True;
718 }
719
720 /****************************************************************************
721  Check if a POSIX ACL has the required SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries.
722  If it does not have them, check if there are any entries where the trustee is the
723  file owner or the owning group, and map these to SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ.
724 ****************************************************************************/
725
726 static void check_owning_objs(canon_ace *ace, DOM_SID *pfile_owner_sid, DOM_SID *pfile_grp_sid)
727 {
728         BOOL got_user_obj, got_group_obj;
729         canon_ace *current_ace;
730         int i, entries;
731
732         entries = count_canon_ace_list(ace);
733         got_user_obj = False;
734         got_group_obj = False;
735
736         for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
737                 if (current_ace->type == SMB_ACL_USER_OBJ)
738                         got_user_obj = True;
739                 else if (current_ace->type == SMB_ACL_GROUP_OBJ)
740                         got_group_obj = True;
741         }
742         if (got_user_obj && got_group_obj) {
743                 DEBUG(10,("check_owning_objs: ACL had owning user/group entries.\n"));
744                 return;
745         }
746
747         for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
748                 if (!got_user_obj && current_ace->owner_type == UID_ACE &&
749                                 sid_equal(&current_ace->trustee, pfile_owner_sid)) {
750                         current_ace->type = SMB_ACL_USER_OBJ;
751                         got_user_obj = True;
752                 }
753                 if (!got_group_obj && current_ace->owner_type == GID_ACE &&
754                                 sid_equal(&current_ace->trustee, pfile_grp_sid)) {
755                         current_ace->type = SMB_ACL_GROUP_OBJ;
756                         got_group_obj = True;
757                 }
758         }
759         if (!got_user_obj)
760                 DEBUG(10,("check_owning_objs: ACL is missing an owner entry.\n"));
761         if (!got_group_obj)
762                 DEBUG(10,("check_owning_objs: ACL is missing an owning group entry.\n"));
763 }
764
765 /****************************************************************************
766  Unpack a SEC_DESC into two canonical ace lists.
767 ****************************************************************************/
768
769 static BOOL create_canon_ace_lists(files_struct *fsp, 
770                                                         DOM_SID *pfile_owner_sid,
771                                                         DOM_SID *pfile_grp_sid,
772                                                         canon_ace **ppfile_ace, canon_ace **ppdir_ace,
773                                                         SEC_ACL *dacl)
774 {
775         extern DOM_SID global_sid_Creator_Owner;
776         extern DOM_SID global_sid_Creator_Group;
777         extern DOM_SID global_sid_World;
778         extern struct generic_mapping file_generic_mapping;
779         BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False);
780         canon_ace *file_ace = NULL;
781         canon_ace *dir_ace = NULL;
782         canon_ace *tmp_ace = NULL;
783         canon_ace *current_ace = NULL;
784         BOOL got_dir_allow = False;
785         BOOL got_file_allow = False;
786         int i, j;
787
788         *ppfile_ace = NULL;
789         *ppdir_ace = NULL;
790
791         /*
792          * Convert the incoming ACL into a more regular form.
793          */
794
795         for(i = 0; i < dacl->num_aces; i++) {
796                 SEC_ACE *psa = &dacl->ace[i];
797
798                 if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) && (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
799                         DEBUG(3,("create_canon_ace_lists: unable to set anything but an ALLOW or DENY ACE.\n"));
800                         return False;
801                 }
802
803                 if (nt4_compatible_acls()) {
804                         /*
805                          * The security mask may be UNIX_ACCESS_NONE which should map into
806                          * no permissions (we overload the WRITE_OWNER bit for this) or it
807                          * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
808                          * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
809                          */
810
811                         /*
812                          * Convert GENERIC bits to specific bits.
813                          */
814  
815                         se_map_generic(&psa->info.mask, &file_generic_mapping);
816
817                         psa->info.mask &= (UNIX_ACCESS_NONE|FILE_ALL_ACCESS);
818
819                         if(psa->info.mask != UNIX_ACCESS_NONE)
820                                 psa->info.mask &= ~UNIX_ACCESS_NONE;
821                 }
822         }
823
824         /*
825          * Deal with the fact that NT 4.x re-writes the canonical format
826          * that we return for default ACLs. If a directory ACE is identical
827          * to a inherited directory ACE then NT changes the bits so that the
828          * first ACE is set to OI|IO and the second ACE for this SID is set
829          * to CI. We need to repair this. JRA.
830          */
831
832         for(i = 0; i < dacl->num_aces; i++) {
833                 SEC_ACE *psa1 = &dacl->ace[i];
834
835                 for (j = i + 1; j < dacl->num_aces; j++) {
836                         SEC_ACE *psa2 = &dacl->ace[j];
837
838                         if (psa1->info.mask != psa2->info.mask)
839                                 continue;
840
841                         if (!sid_equal(&psa1->trustee, &psa2->trustee))
842                                 continue;
843
844                         /*
845                          * Ok - permission bits and SIDs are equal.
846                          * Check if flags were re-written.
847                          */
848
849                         if (psa1->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
850
851                                 psa1->flags |= (psa2->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
852                                 psa2->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
853                                 
854                         } else if (psa2->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
855
856                                 psa2->flags |= (psa1->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
857                                 psa1->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
858                                 
859                         }
860                 }
861         }
862
863         for(i = 0; i < dacl->num_aces; i++) {
864                 SEC_ACE *psa = &dacl->ace[i];
865
866                 /*
867                  * Ignore non-mappable SIDs (NT Authority, BUILTIN etc).
868                  */
869
870                 if (non_mappable_sid(&psa->trustee)) {
871                         fstring str;
872                         DEBUG(10,("create_canon_ace_lists: ignoring non-mappable SID %s\n",
873                                 sid_to_string(str, &psa->trustee) ));
874                         continue;
875                 }
876
877                 /*
878                  * Create a cannon_ace entry representing this NT DACL ACE.
879                  */
880
881                 if ((current_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
882                         free_canon_ace_list(file_ace);
883                         free_canon_ace_list(dir_ace);
884                         DEBUG(0,("create_canon_ace_lists: malloc fail.\n"));
885                         return False;
886                 }
887
888                 ZERO_STRUCTP(current_ace);
889
890                 sid_copy(&current_ace->trustee, &psa->trustee);
891
892                 /*
893                  * Try and work out if the SID is a user or group
894                  * as we need to flag these differently for POSIX.
895                  * Note what kind of a POSIX ACL this should map to.
896                  */
897
898                 if( sid_equal(&current_ace->trustee, &global_sid_World)) {
899                         current_ace->owner_type = WORLD_ACE;
900                         current_ace->unix_ug.world = -1;
901                         current_ace->type = SMB_ACL_OTHER;
902                 } else if (sid_equal(&current_ace->trustee, &global_sid_Creator_Owner)) {
903                         current_ace->owner_type = UID_ACE;
904                         current_ace->unix_ug.world = -1;
905                         current_ace->type = SMB_ACL_USER_OBJ;
906
907                         /*
908                          * The Creator Owner entry only specifies inheritable permissions,
909                          * never access permissions. WinNT doesn't always set the ACE to
910                          *INHERIT_ONLY, though.
911                          */
912
913                         if (nt4_compatible_acls())
914                                 psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
915                 } else if (sid_equal(&current_ace->trustee, &global_sid_Creator_Group)) {
916                         current_ace->owner_type = GID_ACE;
917                         current_ace->unix_ug.world = -1;
918                         current_ace->type = SMB_ACL_GROUP_OBJ;
919
920                         /*
921                          * The Creator Group entry only specifies inheritable permissions,
922                          * never access permissions. WinNT doesn't always set the ACE to
923                          *INHERIT_ONLY, though.
924                          */
925                         if (nt4_compatible_acls())
926                                 psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
927
928                 } else if (NT_STATUS_IS_OK(sid_to_gid( &current_ace->trustee, &current_ace->unix_ug.gid))) {
929                         current_ace->owner_type = GID_ACE;
930                         current_ace->type = SMB_ACL_GROUP;
931                 } else if (NT_STATUS_IS_OK(sid_to_uid( &current_ace->trustee, &current_ace->unix_ug.uid))) {
932                         current_ace->owner_type = UID_ACE;
933                         current_ace->type = SMB_ACL_USER;
934                 } else {
935                         fstring str;
936
937                         free_canon_ace_list(file_ace);
938                         free_canon_ace_list(dir_ace);
939                         DEBUG(0,("create_canon_ace_lists: unable to map SID %s to uid or gid.\n",
940                                 sid_to_string(str, &current_ace->trustee) ));
941                         SAFE_FREE(current_ace);
942                         return False;
943                 }
944
945                 /*
946                  * Map the given NT permissions into a UNIX mode_t containing only
947                  * S_I(R|W|X)USR bits.
948                  */
949
950                 current_ace->perms |= map_nt_perms( psa->info, S_IRUSR);
951                 current_ace->attr = (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? ALLOW_ACE : DENY_ACE;
952
953                 /*
954                  * Now add the created ace to either the file list, the directory
955                  * list, or both. We *MUST* preserve the order here (hence we use
956                  * DLIST_ADD_END) as NT ACLs are order dependent.
957                  */
958
959                 if (fsp->is_directory) {
960
961                         /*
962                          * We can only add to the default POSIX ACE list if the ACE is
963                          * designed to be inherited by both files and directories.
964                          */
965
966                         if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) ==
967                                 (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) {
968
969                                 DLIST_ADD_END(dir_ace, current_ace, tmp_ace);
970
971                                 /*
972                                  * Note if this was an allow ace. We can't process
973                                  * any further deny ace's after this.
974                                  */
975
976                                 if (current_ace->attr == ALLOW_ACE)
977                                         got_dir_allow = True;
978
979                                 if ((current_ace->attr == DENY_ACE) && got_dir_allow) {
980                                         DEBUG(0,("create_canon_ace_lists: malformed ACL in inheritable ACL ! \
981 Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
982                                         free_canon_ace_list(file_ace);
983                                         free_canon_ace_list(dir_ace);
984                                         SAFE_FREE(current_ace);
985                                         return False;
986                                 }       
987
988                                 if( DEBUGLVL( 10 )) {
989                                         dbgtext("create_canon_ace_lists: adding dir ACL:\n");
990                                         print_canon_ace( current_ace, 0);
991                                 }
992
993                                 /*
994                                  * If this is not an inherit only ACE we need to add a duplicate
995                                  * to the file acl.
996                                  */
997
998                                 if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
999                                         canon_ace *dup_ace = dup_canon_ace(current_ace);
1000
1001                                         if (!dup_ace) {
1002                                                 DEBUG(0,("create_canon_ace_lists: malloc fail !\n"));
1003                                                 free_canon_ace_list(file_ace);
1004                                                 free_canon_ace_list(dir_ace);
1005                                                 return False;
1006                                         }
1007
1008                                         /*
1009                                          * We must not free current_ace here as its
1010                                          * pointer is now owned by the dir_ace list.
1011                                          */
1012                                         current_ace = dup_ace;
1013                                 } else {
1014                                         /*
1015                                          * We must not free current_ace here as its
1016                                          * pointer is now owned by the dir_ace list.
1017                                          */
1018                                         current_ace = NULL;
1019                                 }
1020                         }
1021                 }
1022
1023                 /*
1024                  * Only add to the file ACL if not inherit only.
1025                  */
1026
1027                 if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
1028                         DLIST_ADD_END(file_ace, current_ace, tmp_ace);
1029
1030                         /*
1031                          * Note if this was an allow ace. We can't process
1032                          * any further deny ace's after this.
1033                          */
1034
1035                         if (current_ace->attr == ALLOW_ACE)
1036                                 got_file_allow = True;
1037
1038                         if ((current_ace->attr == DENY_ACE) && got_file_allow) {
1039                                 DEBUG(0,("create_canon_ace_lists: malformed ACL in file ACL ! \
1040 Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
1041                                 free_canon_ace_list(file_ace);
1042                                 free_canon_ace_list(dir_ace);
1043                                 SAFE_FREE(current_ace);
1044                                 return False;
1045                         }       
1046
1047                         if( DEBUGLVL( 10 )) {
1048                                 dbgtext("create_canon_ace_lists: adding file ACL:\n");
1049                                 print_canon_ace( current_ace, 0);
1050                         }
1051                         all_aces_are_inherit_only = False;
1052                         /*
1053                          * We must not free current_ace here as its
1054                          * pointer is now owned by the file_ace list.
1055                          */
1056                         current_ace = NULL;
1057                 }
1058
1059                 /*
1060                  * Free if ACE was not added.
1061                  */
1062
1063                 SAFE_FREE(current_ace);
1064         }
1065
1066         if (fsp->is_directory && all_aces_are_inherit_only) {
1067                 /*
1068                  * Windows 2000 is doing one of these weird 'inherit acl'
1069                  * traverses to conserve NTFS ACL resources. Just pretend
1070                  * there was no DACL sent. JRA.
1071                  */
1072
1073                 DEBUG(10,("create_canon_ace_lists: Win2k inherit acl traverse. Ignoring DACL.\n"));
1074                 free_canon_ace_list(file_ace);
1075                 free_canon_ace_list(dir_ace);
1076                 file_ace = NULL;
1077                 dir_ace = NULL;
1078         } else {
1079                 /*
1080                  * Check if we have SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries in each
1081                  * ACL. If we don't have them, check if any SMB_ACL_USER/SMB_ACL_GROUP
1082                  * entries can be converted to *_OBJ. Usually we will already have these
1083                  * entries in the Default ACL, and the Access ACL will not have them.
1084                  */
1085                 check_owning_objs(file_ace, pfile_owner_sid, pfile_grp_sid);
1086                 check_owning_objs(dir_ace, pfile_owner_sid, pfile_grp_sid);
1087         }
1088
1089         *ppfile_ace = file_ace;
1090         *ppdir_ace = dir_ace;
1091
1092         return True;
1093 }
1094
1095 /****************************************************************************
1096  ASCII art time again... JRA :-).
1097
1098  We have 4 cases to process when moving from an NT ACL to a POSIX ACL. Firstly,
1099  we insist the ACL is in canonical form (ie. all DENY entries preceede ALLOW
1100  entries). Secondly, the merge code has ensured that all duplicate SID entries for
1101  allow or deny have been merged, so the same SID can only appear once in the deny
1102  list or once in the allow list.
1103
1104  We then process as follows :
1105
1106  ---------------------------------------------------------------------------
1107  First pass - look for a Everyone DENY entry.
1108
1109  If it is deny all (rwx) trunate the list at this point.
1110  Else, walk the list from this point and use the deny permissions of this
1111  entry as a mask on all following allow entries. Finally, delete
1112  the Everyone DENY entry (we have applied it to everything possible).
1113
1114  In addition, in this pass we remove any DENY entries that have 
1115  no permissions (ie. they are a DENY nothing).
1116  ---------------------------------------------------------------------------
1117  Second pass - only deal with deny user entries.
1118
1119  DENY user1 (perms XXX)
1120
1121  new_perms = 0
1122  for all following allow group entries where user1 is in group
1123         new_perms |= group_perms;
1124
1125  user1 entry perms = new_perms & ~ XXX;
1126
1127  Convert the deny entry to an allow entry with the new perms and
1128  push to the end of the list. Note if the user was in no groups
1129  this maps to a specific allow nothing entry for this user.
1130
1131  The common case from the NT ACL choser (userX deny all) is
1132  optimised so we don't do the group lookup - we just map to
1133  an allow nothing entry.
1134
1135  What we're doing here is inferring the allow permissions the
1136  person setting the ACE on user1 wanted by looking at the allow
1137  permissions on the groups the user is currently in. This will
1138  be a snapshot, depending on group membership but is the best
1139  we can do and has the advantage of failing closed rather than
1140  open.
1141  ---------------------------------------------------------------------------
1142  Third pass - only deal with deny group entries.
1143
1144  DENY group1 (perms XXX)
1145
1146  for all following allow user entries where user is in group1
1147    user entry perms = user entry perms & ~ XXX;
1148
1149  If there is a group Everyone allow entry with permissions YYY,
1150  convert the group1 entry to an allow entry and modify its
1151  permissions to be :
1152
1153  new_perms = YYY & ~ XXX
1154
1155  and push to the end of the list.
1156
1157  If there is no group Everyone allow entry then convert the
1158  group1 entry to a allow nothing entry and push to the end of the list.
1159
1160  Note that the common case from the NT ACL choser (groupX deny all)
1161  cannot be optimised here as we need to modify user entries who are
1162  in the group to change them to a deny all also.
1163
1164  What we're doing here is modifying the allow permissions of
1165  user entries (which are more specific in POSIX ACLs) to mask
1166  out the explicit deny set on the group they are in. This will
1167  be a snapshot depending on current group membership but is the
1168  best we can do and has the advantage of failing closed rather
1169  than open.
1170  ---------------------------------------------------------------------------
1171  Fourth pass - cope with cumulative permissions.
1172
1173  for all allow user entries, if there exists an allow group entry with
1174  more permissive permissions, and the user is in that group, rewrite the
1175  allow user permissions to contain both sets of permissions.
1176
1177  Currently the code for this is #ifdef'ed out as these semantics make
1178  no sense to me. JRA.
1179  ---------------------------------------------------------------------------
1180
1181  Note we *MUST* do the deny user pass first as this will convert deny user
1182  entries into allow user entries which can then be processed by the deny
1183  group pass.
1184
1185  The above algorithm took a *lot* of thinking about - hence this
1186  explaination :-). JRA.
1187 ****************************************************************************/
1188
1189 /****************************************************************************
1190  Process a canon_ace list entries. This is very complex code. We need
1191  to go through and remove the "deny" permissions from any allow entry that matches
1192  the id of this entry. We have already refused any NT ACL that wasn't in correct
1193  order (DENY followed by ALLOW). If any allow entry ends up with zero permissions,
1194  we just remove it (to fail safe). We have already removed any duplicate ace
1195  entries. Treat an "Everyone" DENY_ACE as a special case - use it to mask all
1196  allow entries.
1197 ****************************************************************************/
1198
1199 static void process_deny_list( canon_ace **pp_ace_list )
1200 {
1201         extern DOM_SID global_sid_World;
1202         canon_ace *ace_list = *pp_ace_list;
1203         canon_ace *curr_ace = NULL;
1204         canon_ace *curr_ace_next = NULL;
1205
1206         /* Pass 1 above - look for an Everyone, deny entry. */
1207
1208         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1209                 canon_ace *allow_ace_p;
1210
1211                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1212
1213                 if (curr_ace->attr != DENY_ACE)
1214                         continue;
1215
1216                 if (curr_ace->perms == (mode_t)0) {
1217
1218                         /* Deny nothing entry - delete. */
1219
1220                         DLIST_REMOVE(ace_list, curr_ace);
1221                         continue;
1222                 }
1223
1224                 if (!sid_equal(&curr_ace->trustee, &global_sid_World))
1225                         continue;
1226
1227                 /* JRATEST - assert. */
1228                 SMB_ASSERT(curr_ace->owner_type == WORLD_ACE);
1229
1230                 if (curr_ace->perms == ALL_ACE_PERMS) {
1231
1232                         /*
1233                          * Optimisation. This is a DENY_ALL to Everyone. Truncate the
1234                          * list at this point including this entry.
1235                          */
1236
1237                         canon_ace *prev_entry = curr_ace->prev;
1238
1239                         free_canon_ace_list( curr_ace );
1240                         if (prev_entry)
1241                                 prev_entry->next = NULL;
1242                         else {
1243                                 /* We deleted the entire list. */
1244                                 ace_list = NULL;
1245                         }
1246                         break;
1247                 }
1248
1249                 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1250
1251                         /* 
1252                          * Only mask off allow entries.
1253                          */
1254
1255                         if (allow_ace_p->attr != ALLOW_ACE)
1256                                 continue;
1257
1258                         allow_ace_p->perms &= ~curr_ace->perms;
1259                 }
1260
1261                 /*
1262                  * Now it's been applied, remove it.
1263                  */
1264
1265                 DLIST_REMOVE(ace_list, curr_ace);
1266         }
1267
1268         /* Pass 2 above - deal with deny user entries. */
1269
1270         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1271                 mode_t new_perms = (mode_t)0;
1272                 canon_ace *allow_ace_p;
1273                 canon_ace *tmp_ace;
1274
1275                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1276
1277                 if (curr_ace->attr != DENY_ACE)
1278                         continue;
1279
1280                 if (curr_ace->owner_type != UID_ACE)
1281                         continue;
1282
1283                 if (curr_ace->perms == ALL_ACE_PERMS) {
1284
1285                         /*
1286                          * Optimisation - this is a deny everything to this user.
1287                          * Convert to an allow nothing and push to the end of the list.
1288                          */
1289
1290                         curr_ace->attr = ALLOW_ACE;
1291                         curr_ace->perms = (mode_t)0;
1292                         DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
1293                         continue;
1294                 }
1295
1296                 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1297
1298                         if (allow_ace_p->attr != ALLOW_ACE)
1299                                 continue;
1300
1301                         /* We process GID_ACE and WORLD_ACE entries only. */
1302
1303                         if (allow_ace_p->owner_type == UID_ACE)
1304                                 continue;
1305
1306                         if (uid_entry_in_group( curr_ace, allow_ace_p))
1307                                 new_perms |= allow_ace_p->perms;
1308                 }
1309
1310                 /*
1311                  * Convert to a allow entry, modify the perms and push to the end
1312                  * of the list.
1313                  */
1314
1315                 curr_ace->attr = ALLOW_ACE;
1316                 curr_ace->perms = (new_perms & ~curr_ace->perms);
1317                 DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
1318         }
1319
1320         /* Pass 3 above - deal with deny group entries. */
1321
1322         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1323                 canon_ace *tmp_ace;
1324                 canon_ace *allow_ace_p;
1325                 canon_ace *allow_everyone_p = NULL;
1326
1327                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1328
1329                 if (curr_ace->attr != DENY_ACE)
1330                         continue;
1331
1332                 if (curr_ace->owner_type != GID_ACE)
1333                         continue;
1334
1335                 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1336
1337                         if (allow_ace_p->attr != ALLOW_ACE)
1338                                 continue;
1339
1340                         /* Store a pointer to the Everyone allow, if it exists. */
1341                         if (allow_ace_p->owner_type == WORLD_ACE)
1342                                 allow_everyone_p = allow_ace_p;
1343
1344                         /* We process UID_ACE entries only. */
1345
1346                         if (allow_ace_p->owner_type != UID_ACE)
1347                                 continue;
1348
1349                         /* Mask off the deny group perms. */
1350
1351                         if (uid_entry_in_group( allow_ace_p, curr_ace))
1352                                 allow_ace_p->perms &= ~curr_ace->perms;
1353                 }
1354
1355                 /*
1356                  * Convert the deny to an allow with the correct perms and
1357                  * push to the end of the list.
1358                  */
1359
1360                 curr_ace->attr = ALLOW_ACE;
1361                 if (allow_everyone_p)
1362                         curr_ace->perms = allow_everyone_p->perms & ~curr_ace->perms;
1363                 else
1364                         curr_ace->perms = (mode_t)0;
1365                 DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
1366
1367         }
1368
1369         /* Doing this fourth pass allows Windows semantics to be layered
1370          * on top of POSIX semantics. I'm not sure if this is desirable.
1371          * For example, in W2K ACLs there is no way to say, "Group X no
1372          * access, user Y full access" if user Y is a member of group X.
1373          * This seems completely broken semantics to me.... JRA.
1374          */
1375
1376 #if 0
1377         /* Pass 4 above - deal with allow entries. */
1378
1379         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1380                 canon_ace *allow_ace_p;
1381
1382                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1383
1384                 if (curr_ace->attr != ALLOW_ACE)
1385                         continue;
1386
1387                 if (curr_ace->owner_type != UID_ACE)
1388                         continue;
1389
1390                 for (allow_ace_p = ace_list; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1391
1392                         if (allow_ace_p->attr != ALLOW_ACE)
1393                                 continue;
1394
1395                         /* We process GID_ACE entries only. */
1396
1397                         if (allow_ace_p->owner_type != GID_ACE)
1398                                 continue;
1399
1400                         /* OR in the group perms. */
1401
1402                         if (uid_entry_in_group( curr_ace, allow_ace_p))
1403                                 curr_ace->perms |= allow_ace_p->perms;
1404                 }
1405         }
1406 #endif
1407
1408         *pp_ace_list = ace_list;
1409 }
1410
1411 /****************************************************************************
1412  Create a default mode that will be used if a security descriptor entry has
1413  no user/group/world entries.
1414 ****************************************************************************/
1415
1416 static mode_t create_default_mode(files_struct *fsp, BOOL interitable_mode)
1417 {
1418         int snum = SNUM(fsp->conn);
1419         mode_t and_bits = (mode_t)0;
1420         mode_t or_bits = (mode_t)0;
1421         mode_t mode = interitable_mode ? unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name) : S_IRUSR;
1422
1423         if (fsp->is_directory)
1424                 mode |= (S_IWUSR|S_IXUSR);
1425
1426         /*
1427          * Now AND with the create mode/directory mode bits then OR with the
1428          * force create mode/force directory mode bits.
1429          */
1430
1431         if (fsp->is_directory) {
1432                 and_bits = lp_dir_security_mask(snum);
1433                 or_bits = lp_force_dir_security_mode(snum);
1434         } else {
1435                 and_bits = lp_security_mask(snum);
1436                 or_bits = lp_force_security_mode(snum);
1437         }
1438
1439         return ((mode & and_bits)|or_bits);
1440 }
1441
1442 /****************************************************************************
1443  Unpack a SEC_DESC into two canonical ace lists. We don't depend on this
1444  succeeding.
1445 ****************************************************************************/
1446
1447 static BOOL unpack_canon_ace(files_struct *fsp, 
1448                                                         SMB_STRUCT_STAT *pst,
1449                                                         DOM_SID *pfile_owner_sid,
1450                                                         DOM_SID *pfile_grp_sid,
1451                                                         canon_ace **ppfile_ace, canon_ace **ppdir_ace,
1452                                                         uint32 security_info_sent, SEC_DESC *psd)
1453 {
1454         canon_ace *file_ace = NULL;
1455         canon_ace *dir_ace = NULL;
1456
1457         *ppfile_ace = NULL;
1458         *ppdir_ace = NULL;
1459
1460         if(security_info_sent == 0) {
1461                 DEBUG(0,("unpack_canon_ace: no security info sent !\n"));
1462                 return False;
1463         }
1464
1465         /*
1466          * If no DACL then this is a chown only security descriptor.
1467          */
1468
1469         if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !psd->dacl)
1470                 return True;
1471
1472         /*
1473          * Now go through the DACL and create the canon_ace lists.
1474          */
1475
1476         if (!create_canon_ace_lists( fsp, pfile_owner_sid, pfile_grp_sid,
1477                                                                 &file_ace, &dir_ace, psd->dacl))
1478                 return False;
1479
1480         if ((file_ace == NULL) && (dir_ace == NULL)) {
1481                 /* W2K traverse DACL set - ignore. */
1482                 return True;
1483         }
1484
1485         /*
1486          * Go through the canon_ace list and merge entries
1487          * belonging to identical users of identical allow or deny type.
1488          * We can do this as all deny entries come first, followed by
1489          * all allow entries (we have mandated this before accepting this acl).
1490          */
1491
1492         print_canon_ace_list( "file ace - before merge", file_ace);
1493         merge_aces( &file_ace );
1494
1495         print_canon_ace_list( "dir ace - before merge", dir_ace);
1496         merge_aces( &dir_ace );
1497
1498         /*
1499          * NT ACLs are order dependent. Go through the acl lists and
1500          * process DENY entries by masking the allow entries.
1501          */
1502
1503         print_canon_ace_list( "file ace - before deny", file_ace);
1504         process_deny_list( &file_ace);
1505
1506         print_canon_ace_list( "dir ace - before deny", dir_ace);
1507         process_deny_list( &dir_ace);
1508
1509         /*
1510          * A well formed POSIX file or default ACL has at least 3 entries, a 
1511          * SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ
1512          * and optionally a mask entry. Ensure this is the case.
1513          */
1514
1515         print_canon_ace_list( "file ace - before valid", file_ace);
1516
1517         /*
1518          * A default 3 element mode entry for a file should be r-- --- ---.
1519          * A default 3 element mode entry for a directory should be rwx --- ---.
1520          */
1521
1522         pst->st_mode = create_default_mode(fsp, False);
1523
1524         if (!ensure_canon_entry_valid(&file_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
1525                 free_canon_ace_list(file_ace);
1526                 free_canon_ace_list(dir_ace);
1527                 return False;
1528         }
1529
1530         print_canon_ace_list( "dir ace - before valid", dir_ace);
1531
1532         /*
1533          * A default inheritable 3 element mode entry for a directory should be the
1534          * mode Samba will use to create a file within. Ensure user rwx bits are set if
1535          * it's a directory.
1536          */
1537
1538         pst->st_mode = create_default_mode(fsp, True);
1539
1540         if (dir_ace && !ensure_canon_entry_valid(&dir_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
1541                 free_canon_ace_list(file_ace);
1542                 free_canon_ace_list(dir_ace);
1543                 return False;
1544         }
1545
1546         print_canon_ace_list( "file ace - return", file_ace);
1547         print_canon_ace_list( "dir ace - return", dir_ace);
1548
1549         *ppfile_ace = file_ace;
1550         *ppdir_ace = dir_ace;
1551         return True;
1552
1553 }
1554
1555 /******************************************************************************
1556  When returning permissions, try and fit NT display
1557  semantics if possible. Note the the canon_entries here must have been malloced.
1558  The list format should be - first entry = owner, followed by group and other user
1559  entries, last entry = other.
1560
1561  Note that this doesn't exactly match the NT semantics for an ACL. As POSIX entries
1562  are not ordered, and match on the most specific entry rather than walking a list,
1563  then a simple POSIX permission of rw-r--r-- should really map to 5 entries,
1564
1565  Entry 0: owner : deny all except read and write.
1566  Entry 1: group : deny all except read.
1567  Entry 2: owner : allow read and write.
1568  Entry 3: group : allow read.
1569  Entry 4: Everyone : allow read.
1570
1571  But NT cannot display this in their ACL editor !
1572 ********************************************************************************/
1573
1574 static void arrange_posix_perms( char *filename, canon_ace **pp_list_head)
1575 {
1576         canon_ace *list_head = *pp_list_head;
1577         canon_ace *owner_ace = NULL;
1578         canon_ace *other_ace = NULL;
1579         canon_ace *ace = NULL;
1580
1581         for (ace = list_head; ace; ace = ace->next) {
1582                 if (ace->type == SMB_ACL_USER_OBJ)
1583                         owner_ace = ace;
1584                 else if (ace->type == SMB_ACL_OTHER) {
1585                         /* Last ace - this is "other" */
1586                         other_ace = ace;
1587                 }
1588         }
1589                 
1590         if (!owner_ace || !other_ace) {
1591                 DEBUG(0,("arrange_posix_perms: Invalid POSIX permissions for file %s, missing owner or other.\n",
1592                         filename ));
1593                 return;
1594         }
1595
1596         /*
1597          * The POSIX algorithm applies to owner first, and other last,
1598          * so ensure they are arranged in this order.
1599          */
1600
1601         if (owner_ace) {
1602                 DLIST_PROMOTE(list_head, owner_ace);
1603         }
1604
1605         if (other_ace) {
1606                 DLIST_DEMOTE(list_head, other_ace, ace);
1607         }
1608
1609         /* We have probably changed the head of the list. */
1610
1611         *pp_list_head = list_head;
1612 }
1613                 
1614 /****************************************************************************
1615  Create a linked list of canonical ACE entries.
1616 ****************************************************************************/
1617
1618 static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf,
1619                                         DOM_SID *powner, DOM_SID *pgroup, SMB_ACL_TYPE_T the_acl_type)
1620 {
1621         extern DOM_SID global_sid_World;
1622         connection_struct *conn = fsp->conn;
1623         mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR);
1624         canon_ace *list_head = NULL;
1625         canon_ace *ace = NULL;
1626         canon_ace *next_ace = NULL;
1627         int entry_id = SMB_ACL_FIRST_ENTRY;
1628         SMB_ACL_ENTRY_T entry;
1629         size_t ace_count;
1630
1631         while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
1632                 SMB_ACL_TAG_T tagtype;
1633                 SMB_ACL_PERMSET_T permset;
1634                 DOM_SID sid;
1635                 posix_id unix_ug;
1636                 enum ace_owner owner_type;
1637
1638                 /* get_next... */
1639                 if (entry_id == SMB_ACL_FIRST_ENTRY)
1640                         entry_id = SMB_ACL_NEXT_ENTRY;
1641
1642                 /* Is this a MASK entry ? */
1643                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
1644                         continue;
1645
1646                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
1647                         continue;
1648
1649                 /* Decide which SID to use based on the ACL type. */
1650                 switch(tagtype) {
1651                         case SMB_ACL_USER_OBJ:
1652                                 /* Get the SID from the owner. */
1653                                 sid_copy(&sid, powner);
1654                                 unix_ug.uid = psbuf->st_uid;
1655                                 owner_type = UID_ACE;
1656                                 break;
1657                         case SMB_ACL_USER:
1658                                 {
1659                                         uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
1660                                         if (puid == NULL) {
1661                                                 DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
1662                                                 continue;
1663                                         }
1664                                         /*
1665                                          * A SMB_ACL_USER entry for the owner is shadowed by the
1666                                          * SMB_ACL_USER_OBJ entry and Windows also cannot represent
1667                                          * that entry, so we ignore it. We also don't create such
1668                                          * entries out of the blue when setting ACLs, so a get/set
1669                                          * cycle will drop them.
1670                                          */
1671                                         if (the_acl_type == SMB_ACL_TYPE_ACCESS && *puid == psbuf->st_uid)
1672                                                 continue;
1673                                         uid_to_sid( &sid, *puid);
1674                                         unix_ug.uid = *puid;
1675                                         owner_type = UID_ACE;
1676                                         SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
1677                                         break;
1678                                 }
1679                         case SMB_ACL_GROUP_OBJ:
1680                                 /* Get the SID from the owning group. */
1681                                 sid_copy(&sid, pgroup);
1682                                 unix_ug.gid = psbuf->st_gid;
1683                                 owner_type = GID_ACE;
1684                                 break;
1685                         case SMB_ACL_GROUP:
1686                                 {
1687                                         gid_t *pgid = (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
1688                                         if (pgid == NULL) {
1689                                                 DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
1690                                                 continue;
1691                                         }
1692                                         gid_to_sid( &sid, *pgid);
1693                                         unix_ug.gid = *pgid;
1694                                         owner_type = GID_ACE;
1695                                         SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)pgid,tagtype);
1696                                         break;
1697                                 }
1698                         case SMB_ACL_MASK:
1699                                 acl_mask = convert_permset_to_mode_t(conn, permset);
1700                                 continue; /* Don't count the mask as an entry. */
1701                         case SMB_ACL_OTHER:
1702                                 /* Use the Everyone SID */
1703                                 sid = global_sid_World;
1704                                 unix_ug.world = -1;
1705                                 owner_type = WORLD_ACE;
1706                                 break;
1707                         default:
1708                                 DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype));
1709                                 continue;
1710                 }
1711
1712                 /*
1713                  * Add this entry to the list.
1714                  */
1715
1716                 if ((ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
1717                         goto fail;
1718
1719                 ZERO_STRUCTP(ace);
1720                 ace->type = tagtype;
1721                 ace->perms = convert_permset_to_mode_t(conn, permset);
1722                 ace->attr = ALLOW_ACE;
1723                 ace->trustee = sid;
1724                 ace->unix_ug = unix_ug;
1725                 ace->owner_type = owner_type;
1726
1727                 DLIST_ADD(list_head, ace);
1728         }
1729
1730         /*
1731          * This next call will ensure we have at least a user/group/world set.
1732          */
1733
1734         if (!ensure_canon_entry_valid(&list_head, fsp, powner, pgroup, psbuf, False))
1735                 goto fail;
1736
1737         arrange_posix_perms(fsp->fsp_name,&list_head );
1738
1739         /*
1740          * Now go through the list, masking the permissions with the
1741          * acl_mask. Ensure all DENY Entries are at the start of the list.
1742          */
1743
1744         DEBUG(10,("canonicalise_acl: ace entries before arrange :\n"));
1745
1746         for ( ace_count = 0, ace = list_head; ace; ace = next_ace, ace_count++) {
1747                 next_ace = ace->next;
1748
1749                 /* Masks are only applied to entries other than USER_OBJ and OTHER. */
1750                 if (ace->type != SMB_ACL_OTHER && ace->type != SMB_ACL_USER_OBJ)
1751                         ace->perms &= acl_mask;
1752
1753                 if (ace->perms == 0) {
1754                         DLIST_PROMOTE(list_head, ace);
1755                 }
1756
1757                 if( DEBUGLVL( 10 ) ) {
1758                         print_canon_ace(ace, ace_count);
1759                 }
1760         }
1761
1762         print_canon_ace_list( "canonicalise_acl: ace entries after arrange", list_head );
1763
1764         return list_head;
1765
1766   fail:
1767
1768         free_canon_ace_list(list_head);
1769         return NULL;
1770 }
1771
1772 /****************************************************************************
1773  Attempt to apply an ACL to a file or directory.
1774 ****************************************************************************/
1775
1776 static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL default_ace, BOOL *pacl_set_support)
1777 {
1778         connection_struct *conn = fsp->conn;
1779         BOOL ret = False;
1780         SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, (int)count_canon_ace_list(the_ace) + 1);
1781         canon_ace *p_ace;
1782         int i;
1783         SMB_ACL_ENTRY_T mask_entry;
1784         BOOL got_mask_entry = False;
1785         SMB_ACL_PERMSET_T mask_permset;
1786         SMB_ACL_TYPE_T the_acl_type = (default_ace ? SMB_ACL_TYPE_DEFAULT : SMB_ACL_TYPE_ACCESS);
1787         BOOL needs_mask = False;
1788         mode_t mask_perms = 0;
1789
1790 #if defined(POSIX_ACL_NEEDS_MASK)
1791         /* HP-UX always wants to have a mask (called "class" there). */
1792         needs_mask = True;
1793 #endif
1794
1795         if (the_acl == NULL) {
1796
1797                 if (errno != ENOSYS) {
1798                         /*
1799                          * Only print this error message if we have some kind of ACL
1800                          * support that's not working. Otherwise we would always get this.
1801                          */
1802                         DEBUG(0,("set_canon_ace_list: Unable to init %s ACL. (%s)\n",
1803                                 default_ace ? "default" : "file", strerror(errno) ));
1804                 }
1805                 *pacl_set_support = False;
1806                 return False;
1807         }
1808
1809         if( DEBUGLVL( 10 )) {
1810                 dbgtext("set_canon_ace_list: setting ACL:\n");
1811                 for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
1812                         print_canon_ace( p_ace, i);
1813                 }
1814         }
1815
1816         for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
1817                 SMB_ACL_ENTRY_T the_entry;
1818                 SMB_ACL_PERMSET_T the_permset;
1819
1820                 /*
1821                  * ACLs only "need" an ACL_MASK entry if there are any named user or
1822                  * named group entries. But if there is an ACL_MASK entry, it applies
1823                  * to ACL_USER, ACL_GROUP, and ACL_GROUP_OBJ entries. Set the mask
1824                  * so that it doesn't deny (i.e., mask off) any permissions.
1825                  */
1826
1827                 if (p_ace->type == SMB_ACL_USER || p_ace->type == SMB_ACL_GROUP) {
1828                         needs_mask = True;
1829                         mask_perms |= p_ace->perms;
1830                 } else if (p_ace->type == SMB_ACL_GROUP_OBJ) {
1831                         mask_perms |= p_ace->perms;
1832                 }
1833
1834                 /*
1835                  * Get the entry for this ACE.
1836                  */
1837
1838                 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) {
1839                         DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n",
1840                                 i, strerror(errno) ));
1841                         goto done;
1842                 }
1843
1844                 if (p_ace->type == SMB_ACL_MASK) {
1845                         mask_entry = the_entry;
1846                         got_mask_entry = True;
1847                 }
1848
1849                 /*
1850                  * Ok - we now know the ACL calls should be working, don't
1851                  * allow fallback to chmod.
1852                  */
1853
1854                 *pacl_set_support = True;
1855
1856                 /*
1857                  * Initialise the entry from the canon_ace.
1858                  */
1859
1860                 /*
1861                  * First tell the entry what type of ACE this is.
1862                  */
1863
1864                 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, p_ace->type) == -1) {
1865                         DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n",
1866                                 i, strerror(errno) ));
1867                         goto done;
1868                 }
1869
1870                 /*
1871                  * Only set the qualifier (user or group id) if the entry is a user
1872                  * or group id ACE.
1873                  */
1874
1875                 if ((p_ace->type == SMB_ACL_USER) || (p_ace->type == SMB_ACL_GROUP)) {
1876                         if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&p_ace->unix_ug.uid) == -1) {
1877                                 DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n",
1878                                         i, strerror(errno) ));
1879                                 goto done;
1880                         }
1881                 }
1882
1883                 /*
1884                  * Convert the mode_t perms in the canon_ace to a POSIX permset.
1885                  */
1886
1887                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) {
1888                         DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n",
1889                                 i, strerror(errno) ));
1890                         goto done;
1891                 }
1892
1893                 if (map_acl_perms_to_permset(conn, p_ace->perms, &the_permset) == -1) {
1894                         DEBUG(0,("set_canon_ace_list: Failed to create permset for mode (%u) on entry %d. (%s)\n",
1895                                 (unsigned int)p_ace->perms, i, strerror(errno) ));
1896                         goto done;
1897                 }
1898
1899                 /*
1900                  * ..and apply them to the entry.
1901                  */
1902
1903                 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) {
1904                         DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n",
1905                                 i, strerror(errno) ));
1906                         goto done;
1907                 }
1908
1909                 if( DEBUGLVL( 10 ))
1910                         print_canon_ace( p_ace, i);
1911         }
1912
1913         if (needs_mask && !got_mask_entry) {
1914                 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &mask_entry) == -1) {
1915                         DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) ));
1916                         goto done;
1917                 }
1918
1919                 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, mask_entry, SMB_ACL_MASK) == -1) {
1920                         DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno) ));
1921                         goto done;
1922                 }
1923
1924                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, mask_entry, &mask_permset) == -1) {
1925                         DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) ));
1926                         goto done;
1927                 }
1928
1929                 if (map_acl_perms_to_permset(conn, S_IRUSR|S_IWUSR|S_IXUSR, &mask_permset) == -1) {
1930                         DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno) ));
1931                         goto done;
1932                 }
1933
1934                 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, mask_entry, mask_permset) == -1) {
1935                         DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) ));
1936                         goto done;
1937                 }
1938         }
1939
1940         /*
1941          * Check if the ACL is valid.
1942          */
1943
1944         if (SMB_VFS_SYS_ACL_VALID(conn, the_acl) == -1) {
1945                 DEBUG(0,("set_canon_ace_list: ACL type (%s) is invalid for set (%s).\n",
1946                                 the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
1947                                 strerror(errno) ));
1948                 goto done;
1949         }
1950
1951         /*
1952          * Finally apply it to the file or directory.
1953          */
1954
1955         if(default_ace || fsp->is_directory || fsp->fd == -1) {
1956                 if (SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name, the_acl_type, the_acl) == -1) {
1957                         /*
1958                          * Some systems allow all the above calls and only fail with no ACL support
1959                          * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
1960                          */
1961                         if (errno == ENOSYS)
1962                                 *pacl_set_support = False;
1963
1964 #ifdef ENOTSUP
1965                         if (errno == ENOTSUP)
1966                                 *pacl_set_support = False;
1967 #endif
1968
1969                         DEBUG(2,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n",
1970                                         the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
1971                                         fsp->fsp_name, strerror(errno) ));
1972                         goto done;
1973                 }
1974         } else {
1975                 if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fd, the_acl) == -1) {
1976                         /*
1977                          * Some systems allow all the above calls and only fail with no ACL support
1978                          * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
1979                          */
1980                         if (errno == ENOSYS)
1981                                 *pacl_set_support = False;
1982
1983 #ifdef ENOTSUP
1984                         if (errno == ENOTSUP)
1985                                 *pacl_set_support = False;
1986 #endif
1987
1988                         DEBUG(2,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n",
1989                                         fsp->fsp_name, strerror(errno) ));
1990                         goto done;
1991                 }
1992         }
1993
1994         ret = True;
1995
1996   done:
1997
1998         if (the_acl != NULL)
1999             SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
2000
2001         return ret;
2002 }
2003
2004 /****************************************************************************
2005  Find a particular canon_ace entry.
2006 ****************************************************************************/
2007
2008 static struct canon_ace *canon_ace_entry_for(struct canon_ace *list, SMB_ACL_TAG_T type, posix_id *id)
2009 {
2010         while (list) {
2011                 if (list->type == type && ((type != SMB_ACL_USER && type != SMB_ACL_GROUP) ||
2012                                 (type == SMB_ACL_USER  && id && id->uid == list->unix_ug.uid) ||
2013                                 (type == SMB_ACL_GROUP && id && id->gid == list->unix_ug.gid)))
2014                         break;
2015                 list = list->next;
2016         }
2017         return list;
2018 }
2019
2020 /****************************************************************************
2021  
2022 ****************************************************************************/
2023
2024 SMB_ACL_T free_empty_sys_acl(connection_struct *conn, SMB_ACL_T the_acl)
2025 {
2026         SMB_ACL_ENTRY_T entry;
2027
2028         if (!the_acl)
2029                 return NULL;
2030         if (SMB_VFS_SYS_ACL_GET_ENTRY(conn, the_acl, SMB_ACL_FIRST_ENTRY, &entry) != 1) {
2031                 SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
2032                 return NULL;
2033         }
2034         return the_acl;
2035 }
2036
2037 /****************************************************************************
2038  Convert a canon_ace to a generic 3 element permission - if possible.
2039 ****************************************************************************/
2040
2041 #define MAP_PERM(p,mask,result) (((p) & (mask)) ? (result) : 0 )
2042
2043 static BOOL convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file_ace_list, mode_t *posix_perms)
2044 {
2045         int snum = SNUM(fsp->conn);
2046         size_t ace_count = count_canon_ace_list(file_ace_list);
2047         canon_ace *ace_p;
2048         canon_ace *owner_ace = NULL;
2049         canon_ace *group_ace = NULL;
2050         canon_ace *other_ace = NULL;
2051         mode_t and_bits;
2052         mode_t or_bits;
2053
2054         if (ace_count != 3) {
2055                 DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE entries for file %s to convert to \
2056 posix perms.\n", fsp->fsp_name ));
2057                 return False;
2058         }
2059
2060         for (ace_p = file_ace_list; ace_p; ace_p = ace_p->next) {
2061                 if (ace_p->owner_type == UID_ACE)
2062                         owner_ace = ace_p;
2063                 else if (ace_p->owner_type == GID_ACE)
2064                         group_ace = ace_p;
2065                 else if (ace_p->owner_type == WORLD_ACE)
2066                         other_ace = ace_p;
2067         }
2068
2069         if (!owner_ace || !group_ace || !other_ace) {
2070                 DEBUG(3,("convert_canon_ace_to_posix_perms: Can't get standard entries for file %s.\n",
2071                                 fsp->fsp_name ));
2072                 return False;
2073         }
2074
2075         *posix_perms = (mode_t)0;
2076
2077         *posix_perms |= owner_ace->perms;
2078         *posix_perms |= MAP_PERM(group_ace->perms, S_IRUSR, S_IRGRP);
2079         *posix_perms |= MAP_PERM(group_ace->perms, S_IWUSR, S_IWGRP);
2080         *posix_perms |= MAP_PERM(group_ace->perms, S_IXUSR, S_IXGRP);
2081         *posix_perms |= MAP_PERM(other_ace->perms, S_IRUSR, S_IROTH);
2082         *posix_perms |= MAP_PERM(other_ace->perms, S_IWUSR, S_IWOTH);
2083         *posix_perms |= MAP_PERM(other_ace->perms, S_IXUSR, S_IXOTH);
2084
2085         /* The owner must have at least read access. */
2086
2087         *posix_perms |= S_IRUSR;
2088         if (fsp->is_directory)
2089                 *posix_perms |= (S_IWUSR|S_IXUSR);
2090
2091         /* If requested apply the masks. */
2092
2093         /* Get the initial bits to apply. */
2094
2095         if (fsp->is_directory) {
2096                 and_bits = lp_dir_security_mask(snum);
2097                 or_bits = lp_force_dir_security_mode(snum);
2098         } else {
2099                 and_bits = lp_security_mask(snum);
2100                 or_bits = lp_force_security_mode(snum);
2101         }
2102
2103         *posix_perms = (((*posix_perms) & and_bits)|or_bits);
2104
2105         DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o to perm=0%o for file %s.\n",
2106                 (int)owner_ace->perms, (int)group_ace->perms, (int)other_ace->perms, (int)*posix_perms,
2107                 fsp->fsp_name ));
2108
2109         return True;
2110 }
2111
2112 static int nt_ace_comp( SEC_ACE *a1, SEC_ACE *a2)
2113 {
2114         if (a1->type == a2->type)
2115                 return 0;
2116
2117         if (a1->type == SEC_ACE_TYPE_ACCESS_DENIED && a2->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
2118                 return -1;
2119         return 1;
2120 }
2121
2122 /****************************************************************************
2123   Incoming NT ACLs on a directory can be split into a default POSIX acl (CI|OI|IO) and
2124   a normal POSIX acl. Win2k needs these split acls re-merging into one ACL
2125   with CI|OI set so it is inherited and also applies to the directory.
2126   Based on code from "Jim McDonough" <jmcd@us.ibm.com>.
2127 ****************************************************************************/
2128
2129 static size_t merge_default_aces( SEC_ACE *nt_ace_list, size_t num_aces)
2130 {
2131         size_t i, j;
2132
2133         for (i = 0; i < num_aces; i++) {
2134                 for (j = i+1; j < num_aces; j++) {
2135                         /* We know the lower number ACE's are file entries. */
2136                         if ((nt_ace_list[i].type == nt_ace_list[j].type) &&
2137                                 (nt_ace_list[i].size == nt_ace_list[j].size) &&
2138                                 (nt_ace_list[i].info.mask == nt_ace_list[j].info.mask) &&
2139                                 sid_equal(&nt_ace_list[i].trustee, &nt_ace_list[j].trustee) &&
2140                                 (nt_ace_list[i].flags == 0) &&
2141                                 (nt_ace_list[j].flags == (SEC_ACE_FLAG_OBJECT_INHERIT|
2142                                                           SEC_ACE_FLAG_CONTAINER_INHERIT|
2143                                                           SEC_ACE_FLAG_INHERIT_ONLY))) {
2144                                 /*
2145                                  * These are identical except for the flags.
2146                                  * Merge the inherited ACE onto the non-inherited ACE.
2147                                  */
2148
2149                                 nt_ace_list[i].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT;
2150                                 if (num_aces - j - 1 > 0)
2151                                         memmove(&nt_ace_list[j], &nt_ace_list[j+1], (num_aces-j-1) *
2152                                                         sizeof(SEC_ACE));
2153                                 num_aces--;
2154                                 break;
2155                         }
2156                 }
2157         }
2158
2159         return num_aces;
2160 }
2161 /****************************************************************************
2162  Reply to query a security descriptor from an fsp. If it succeeds it allocates
2163  the space for the return elements and returns the size needed to return the
2164  security descriptor. This should be the only external function needed for
2165  the UNIX style get ACL.
2166 ****************************************************************************/
2167
2168 size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc)
2169 {
2170         extern DOM_SID global_sid_Builtin_Administrators;
2171         extern DOM_SID global_sid_Builtin_Users;
2172         extern DOM_SID global_sid_Creator_Owner;
2173         extern DOM_SID global_sid_Creator_Group;
2174         connection_struct *conn = fsp->conn;
2175         SMB_STRUCT_STAT sbuf;
2176         SEC_ACE *nt_ace_list = NULL;
2177         DOM_SID owner_sid;
2178         DOM_SID group_sid;
2179         size_t sd_size = 0;
2180         SEC_ACL *psa = NULL;
2181         size_t num_acls = 0;
2182         size_t num_dir_acls = 0;
2183         size_t num_aces = 0;
2184         SMB_ACL_T posix_acl = NULL;
2185         SMB_ACL_T dir_acl = NULL;
2186         canon_ace *file_ace = NULL;
2187         canon_ace *dir_ace = NULL;
2188         size_t num_profile_acls = 0;
2189  
2190         *ppdesc = NULL;
2191
2192         DEBUG(10,("get_nt_acl: called for file %s\n", fsp->fsp_name ));
2193
2194         if(fsp->is_directory || fsp->fd == -1) {
2195
2196                 /* Get the stat struct for the owner info. */
2197                 if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) {
2198                         return 0;
2199                 }
2200                 /*
2201                  * Get the ACL from the path.
2202                  */
2203
2204                 posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_ACCESS);
2205
2206                 /*
2207                  * If it's a directory get the default POSIX ACL.
2208                  */
2209
2210                 if(fsp->is_directory) {
2211                         dir_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_DEFAULT);
2212                         dir_acl = free_empty_sys_acl(conn, dir_acl);
2213                 }
2214
2215         } else {
2216
2217                 /* Get the stat struct for the owner info. */
2218                 if(SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0) {
2219                         return 0;
2220                 }
2221                 /*
2222                  * Get the ACL from the fd.
2223                  */
2224                 posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fd);
2225         }
2226
2227         DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n",
2228                         posix_acl ? "present" :  "absent",
2229                         dir_acl ? "present" :  "absent" ));
2230
2231         /*
2232          * Get the owner, group and world SIDs.
2233          */
2234
2235         if (lp_profile_acls(SNUM(fsp->conn))) {
2236                 /* For WXP SP1 the owner must be administrators. */
2237                 sid_copy(&owner_sid, &global_sid_Builtin_Administrators);
2238                 sid_copy(&group_sid, &global_sid_Builtin_Users);
2239                 num_profile_acls = 2;
2240         } else {
2241                 create_file_sids(&sbuf, &owner_sid, &group_sid);
2242         }
2243
2244         if (security_info & DACL_SECURITY_INFORMATION) {
2245
2246                 /*
2247                  * In the optimum case Creator Owner and Creator Group would be used for
2248                  * the ACL_USER_OBJ and ACL_GROUP_OBJ entries, respectively, but this
2249                  * would lead to usability problems under Windows: The Creator entries
2250                  * are only available in browse lists of directories and not for files;
2251                  * additionally the identity of the owning group couldn't be determined.
2252                  * We therefore use those identities only for Default ACLs. 
2253                  */
2254
2255                 /* Create the canon_ace lists. */
2256                 file_ace = canonicalise_acl( fsp, posix_acl, &sbuf, &owner_sid, &group_sid, SMB_ACL_TYPE_ACCESS );
2257
2258                 /* We must have *some* ACLS. */
2259         
2260                 if (count_canon_ace_list(file_ace) == 0) {
2261                         DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", fsp->fsp_name ));
2262                         return 0;
2263                 }
2264
2265                 if (fsp->is_directory && dir_acl) {
2266                         dir_ace = canonicalise_acl(fsp, dir_acl, &sbuf,
2267                                         &global_sid_Creator_Owner,
2268                                         &global_sid_Creator_Group, SMB_ACL_TYPE_DEFAULT );
2269                 }
2270
2271                 /*
2272                  * Create the NT ACE list from the canonical ace lists.
2273                  */
2274
2275                 {
2276                         canon_ace *ace;
2277                         int nt_acl_type;
2278                         int i;
2279
2280                         if (nt4_compatible_acls() && dir_ace) {
2281                                 /*
2282                                  * NT 4 chokes if an ACL contains an INHERIT_ONLY entry
2283                                  * but no non-INHERIT_ONLY entry for one SID. So we only
2284                                  * remove entries from the Access ACL if the
2285                                  * corresponding Default ACL entries have also been
2286                                  * removed. ACEs for CREATOR-OWNER and CREATOR-GROUP
2287                                  * are exceptions. We can do nothing
2288                                  * intelligent if the Default ACL contains entries that
2289                                  * are not also contained in the Access ACL, so this
2290                                  * case will still fail under NT 4.
2291                                  */
2292
2293                                 ace = canon_ace_entry_for(dir_ace, SMB_ACL_OTHER, NULL);
2294                                 if (ace && !ace->perms) {
2295                                         DLIST_REMOVE(dir_ace, ace);
2296                                         SAFE_FREE(ace);
2297
2298                                         ace = canon_ace_entry_for(file_ace, SMB_ACL_OTHER, NULL);
2299                                         if (ace && !ace->perms) {
2300                                                 DLIST_REMOVE(file_ace, ace);
2301                                                 SAFE_FREE(ace);
2302                                         }
2303                                 }
2304
2305                                 /*
2306                                  * WinNT doesn't usually have Creator Group
2307                                  * in browse lists, so we send this entry to
2308                                  * WinNT even if it contains no relevant
2309                                  * permissions. Once we can add
2310                                  * Creator Group to browse lists we can
2311                                  * re-enable this.
2312                                  */
2313
2314 #if 0
2315                                 ace = canon_ace_entry_for(dir_ace, SMB_ACL_GROUP_OBJ, NULL);
2316                                 if (ace && !ace->perms) {
2317                                         DLIST_REMOVE(dir_ace, ace);
2318                                         SAFE_FREE(ace);
2319                                 }
2320 #endif
2321
2322                                 ace = canon_ace_entry_for(file_ace, SMB_ACL_GROUP_OBJ, NULL);
2323                                 if (ace && !ace->perms) {
2324                                         DLIST_REMOVE(file_ace, ace);
2325                                         SAFE_FREE(ace);
2326                                 }
2327                         }
2328
2329                         num_acls = count_canon_ace_list(file_ace);
2330                         num_dir_acls = count_canon_ace_list(dir_ace);
2331
2332                         /* Allocate the ace list. */
2333                         if ((nt_ace_list = (SEC_ACE *)malloc((num_acls + num_profile_acls + num_dir_acls)* sizeof(SEC_ACE))) == NULL) {
2334                                 DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
2335                                 goto done;
2336                         }
2337
2338                         memset(nt_ace_list, '\0', (num_acls + num_dir_acls) * sizeof(SEC_ACE) );
2339                                                                                                         
2340                         /*
2341                          * Create the NT ACE list from the canonical ace lists.
2342                          */
2343         
2344                         ace = file_ace;
2345
2346                         for (i = 0; i < num_acls; i++, ace = ace->next) {
2347                                 SEC_ACCESS acc;
2348
2349                                 acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
2350                                 init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc, 0);
2351                         }
2352
2353                         /* The User must have access to a profile share - even if we can't map the SID. */
2354                         if (lp_profile_acls(SNUM(fsp->conn))) {
2355                                 SEC_ACCESS acc;
2356
2357                                 init_sec_access(&acc,FILE_GENERIC_ALL);
2358                                 init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, acc, 0);
2359                         }
2360
2361                         ace = dir_ace;
2362
2363                         for (i = 0; i < num_dir_acls; i++, ace = ace->next) {
2364                                 SEC_ACCESS acc;
2365         
2366                                 acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
2367                                 init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc,
2368                                                 SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY);
2369                         }
2370
2371                         /* The User must have access to a profile share - even if we can't map the SID. */
2372                         if (lp_profile_acls(SNUM(fsp->conn))) {
2373                                 SEC_ACCESS acc;
2374                         
2375                                 init_sec_access(&acc,FILE_GENERIC_ALL);
2376                                 init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, acc,
2377                                                 SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2378                                                 SEC_ACE_FLAG_INHERIT_ONLY);
2379                         }
2380
2381                         /*
2382                          * Merge POSIX default ACLs and normal ACLs into one NT ACE.
2383                          * Win2K needs this to get the inheritance correct when replacing ACLs
2384                          * on a directory tree. Based on work by Jim @ IBM.
2385                          */
2386
2387                         num_aces = merge_default_aces(nt_ace_list, num_aces);
2388
2389                         /*
2390                          * Sort to force deny entries to the front.
2391                          */
2392         
2393                         if (num_aces)
2394                                 qsort( nt_ace_list, num_aces, sizeof(nt_ace_list[0]), QSORT_CAST nt_ace_comp);
2395                 }
2396
2397                 if (num_aces) {
2398                         if((psa = make_sec_acl( main_loop_talloc_get(), ACL_REVISION, num_aces, nt_ace_list)) == NULL) {
2399                                 DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
2400                                 goto done;
2401                         }
2402                 }
2403         } /* security_info & DACL_SECURITY_INFORMATION */
2404
2405         *ppdesc = make_standard_sec_desc( main_loop_talloc_get(),
2406                         (security_info & OWNER_SECURITY_INFORMATION) ? &owner_sid : NULL,
2407                         (security_info & GROUP_SECURITY_INFORMATION) ? &group_sid : NULL,
2408                         psa,
2409                         &sd_size);
2410
2411         if(!*ppdesc) {
2412                 DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
2413                 sd_size = 0;
2414         } else {
2415 #if 1
2416                 /*
2417                  * JRA. Setting this flag causes W2K clients not to
2418                  * propagate ACL sets down a directory tree correctly.
2419                  */
2420                 /*
2421                  * Windows 2000: The DACL_PROTECTED flag in the security
2422                  * descriptor marks the ACL as non-inheriting, i.e., no
2423                  * ACEs from higher level directories propagate to this
2424                  * ACL. In the POSIX ACL model permissions are only
2425                  * inherited at file create time, so ACLs never contain
2426                  * any ACEs that are inherited dynamically. The DACL_PROTECTED
2427                  * flag doesn't seem to bother Windows NT.
2428                  */
2429                 (*ppdesc)->type |= SE_DESC_DACL_PROTECTED;
2430 #endif
2431         }
2432
2433  done:
2434
2435         if (posix_acl)
2436                 SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
2437         if (dir_acl)
2438                 SMB_VFS_SYS_ACL_FREE_ACL(conn, dir_acl);
2439         free_canon_ace_list(file_ace);
2440         free_canon_ace_list(dir_ace);
2441         SAFE_FREE(nt_ace_list);
2442
2443         return sd_size;
2444 }
2445
2446 /****************************************************************************
2447  Try to chown a file. We will be able to chown it under the following conditions.
2448
2449   1) If we have root privileges, then it will just work.
2450   2) If we have write permission to the file and dos_filemodes is set
2451      then allow chown to the currently authenticated user.
2452 ****************************************************************************/
2453
2454 static int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid)
2455 {
2456         int ret;
2457         extern struct current_user current_user;
2458         files_struct *fsp;
2459         SMB_STRUCT_STAT st;
2460
2461         /* try the direct way first */
2462         ret = SMB_VFS_CHOWN(conn, fname, uid, gid);
2463         if (ret == 0)
2464                 return 0;
2465
2466         if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
2467                 return -1;
2468
2469         if (SMB_VFS_STAT(conn,fname,&st))
2470                 return -1;
2471
2472         fsp = open_file_fchmod(conn,fname,&st);
2473         if (!fsp)
2474                 return -1;
2475
2476         /* only allow chown to the current user. This is more secure,
2477            and also copes with the case where the SID in a take ownership ACL is
2478            a local SID on the users workstation 
2479         */
2480         uid = current_user.uid;
2481
2482         become_root();
2483         /* Keep the current file gid the same. */
2484         ret = SMB_VFS_FCHOWN(fsp, fsp->fd, uid, (gid_t)-1);
2485         unbecome_root();
2486
2487         close_file_fchmod(fsp);
2488
2489         return ret;
2490 }
2491
2492 /****************************************************************************
2493  Reply to set a security descriptor on an fsp. security_info_sent is the
2494  description of the following NT ACL.
2495  This should be the only external function needed for the UNIX style set ACL.
2496 ****************************************************************************/
2497
2498 BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
2499 {
2500         connection_struct *conn = fsp->conn;
2501         uid_t user = (uid_t)-1;
2502         gid_t grp = (gid_t)-1;
2503         SMB_STRUCT_STAT sbuf;  
2504         DOM_SID file_owner_sid;
2505         DOM_SID file_grp_sid;
2506         canon_ace *file_ace_list = NULL;
2507         canon_ace *dir_ace_list = NULL;
2508         BOOL acl_perms = False;
2509         mode_t orig_mode = (mode_t)0;
2510         uid_t orig_uid;
2511         gid_t orig_gid;
2512         BOOL need_chown = False;
2513         extern struct current_user current_user;
2514
2515         DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name ));
2516
2517         if (!CAN_WRITE(conn)) {
2518                 DEBUG(10,("set acl rejected on read-only share\n"));
2519                 return False;
2520         }
2521
2522         /*
2523          * Get the current state of the file.
2524          */
2525
2526         if(fsp->is_directory || fsp->fd == -1) {
2527                 if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0)
2528                         return False;
2529         } else {
2530                 if(SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0)
2531                         return False;
2532         }
2533
2534         /* Save the original elements we check against. */
2535         orig_mode = sbuf.st_mode;
2536         orig_uid = sbuf.st_uid;
2537         orig_gid = sbuf.st_gid;
2538
2539         /*
2540          * Unpack the user/group/world id's.
2541          */
2542
2543         if (!unpack_nt_owners( &sbuf, &user, &grp, security_info_sent, psd))
2544                 return False;
2545
2546         /*
2547          * Do we need to chown ?
2548          */
2549
2550         if (((user != (uid_t)-1) && (orig_uid != user)) || (( grp != (gid_t)-1) && (orig_gid != grp)))
2551                 need_chown = True;
2552
2553         /*
2554          * Chown before setting ACL only if we don't change the user, or
2555          * if we change to the current user, but not if we want to give away
2556          * the file.
2557          */
2558
2559         if (need_chown && (user == (uid_t)-1 || user == current_user.uid)) {
2560
2561                 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
2562                                 fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
2563
2564                 if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
2565                         DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
2566                                 fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
2567                         return False;
2568                 }
2569
2570                 /*
2571                  * Recheck the current state of the file, which may have changed.
2572                  * (suid/sgid bits, for instance)
2573                  */
2574
2575                 if(fsp->is_directory) {
2576                         if(SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf) != 0) {
2577                                 return False;
2578                         }
2579                 } else {
2580
2581                         int ret;
2582     
2583                         if(fsp->fd == -1)
2584                                 ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf);
2585                         else
2586                                 ret = SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf);
2587   
2588                         if(ret != 0)
2589                                 return False;
2590                 }
2591
2592                 /* Save the original elements we check against. */
2593                 orig_mode = sbuf.st_mode;
2594                 orig_uid = sbuf.st_uid;
2595                 orig_gid = sbuf.st_gid;
2596
2597                 /* We did it, don't try again */
2598                 need_chown = False;
2599         }
2600
2601         create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid);
2602
2603         acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid,
2604                                                                         &file_ace_list, &dir_ace_list, security_info_sent, psd);
2605
2606         /* Ignore W2K traverse DACL set. */
2607         if (file_ace_list || dir_ace_list) {
2608
2609                 if (!acl_perms) {
2610                         DEBUG(3,("set_nt_acl: cannot set permissions\n"));
2611                         free_canon_ace_list(file_ace_list);
2612                         free_canon_ace_list(dir_ace_list); 
2613                         return False;
2614                 }
2615
2616                 /*
2617                  * Only change security if we got a DACL.
2618                  */
2619
2620                 if((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl != NULL)) {
2621
2622                         BOOL acl_set_support = False;
2623                         BOOL ret = False;
2624
2625                         /*
2626                          * Try using the POSIX ACL set first. Fall back to chmod if
2627                          * we have no ACL support on this filesystem.
2628                          */
2629
2630                         if (acl_perms && file_ace_list) {
2631                                 ret = set_canon_ace_list(fsp, file_ace_list, False, &acl_set_support);
2632                                 if (acl_set_support && ret == False) {
2633                                         DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) ));
2634                                         free_canon_ace_list(file_ace_list);
2635                                         free_canon_ace_list(dir_ace_list); 
2636                                         return False;
2637                                 }
2638                         }
2639
2640                         if (acl_perms && acl_set_support && fsp->is_directory) {
2641                                 if (dir_ace_list) {
2642                                         if (!set_canon_ace_list(fsp, dir_ace_list, True, &acl_set_support)) {
2643                                                 DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) ));
2644                                                 free_canon_ace_list(file_ace_list);
2645                                                 free_canon_ace_list(dir_ace_list); 
2646                                                 return False;
2647                                         }
2648                                 } else {
2649
2650                                         /*
2651                                          * No default ACL - delete one if it exists.
2652                                          */
2653
2654                                         if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name) == -1) {
2655                                                 DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno)));
2656                                                 free_canon_ace_list(file_ace_list);
2657                                                 free_canon_ace_list(dir_ace_list);
2658                                                 return False;
2659                                         }
2660                                 }
2661                         }
2662
2663                         /*
2664                          * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
2665                          */
2666
2667                         if(!acl_set_support && acl_perms) {
2668                                 mode_t posix_perms;
2669
2670                                 if (!convert_canon_ace_to_posix_perms( fsp, file_ace_list, &posix_perms)) {
2671                                         free_canon_ace_list(file_ace_list);
2672                                         free_canon_ace_list(dir_ace_list);
2673                                         DEBUG(3,("set_nt_acl: failed to convert file acl to posix permissions for file %s.\n",
2674                                                 fsp->fsp_name ));
2675                                         return False;
2676                                 }
2677
2678                                 if (orig_mode != posix_perms) {
2679
2680                                         DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
2681                                                 fsp->fsp_name, (unsigned int)posix_perms ));
2682
2683                                         if(SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms) == -1) {
2684                                                 DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n",
2685                                                                 fsp->fsp_name, (unsigned int)posix_perms, strerror(errno) ));
2686                                                 free_canon_ace_list(file_ace_list);
2687                                                 free_canon_ace_list(dir_ace_list);
2688                                                 return False;
2689                                         }
2690                                 }
2691                         }
2692                 }
2693
2694                 free_canon_ace_list(file_ace_list);
2695                 free_canon_ace_list(dir_ace_list); 
2696         }
2697
2698         /* Any chown pending? */
2699         if (need_chown) {
2700
2701                 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
2702                         fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
2703
2704                 if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
2705                         DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
2706                                 fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
2707                         return False;
2708                 }
2709         }
2710
2711         return True;
2712 }
2713
2714 /****************************************************************************
2715  Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
2716  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
2717 ****************************************************************************/
2718
2719 static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mode_t mode)
2720 {
2721         int entry_id = SMB_ACL_FIRST_ENTRY;
2722         SMB_ACL_ENTRY_T entry;
2723         int num_entries = 0;
2724
2725         while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
2726                 SMB_ACL_TAG_T tagtype;
2727                 SMB_ACL_PERMSET_T permset;
2728                 mode_t perms;
2729
2730                 /* get_next... */
2731                 if (entry_id == SMB_ACL_FIRST_ENTRY)
2732                         entry_id = SMB_ACL_NEXT_ENTRY;
2733
2734                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
2735                         return -1;
2736
2737                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
2738                         return -1;
2739
2740                 num_entries++;
2741
2742                 switch(tagtype) {
2743                         case SMB_ACL_USER_OBJ:
2744                                 perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
2745                                 break;
2746                         case SMB_ACL_GROUP_OBJ:
2747                                 perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
2748                                 break;
2749                         case SMB_ACL_MASK:
2750                                 /*
2751                                  * FIXME: The ACL_MASK entry permissions should really be set to
2752                                  * the union of the permissions of all ACL_USER,
2753                                  * ACL_GROUP_OBJ, and ACL_GROUP entries. That's what
2754                                  * acl_calc_mask() does, but Samba ACLs doesn't provide it.
2755                                  */
2756                                 perms = S_IRUSR|S_IWUSR|S_IXUSR;
2757                                 break;
2758                         case SMB_ACL_OTHER:
2759                                 perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
2760                                 break;
2761                         default:
2762                                 continue;
2763                 }
2764
2765                 if (map_acl_perms_to_permset(conn, perms, &permset) == -1)
2766                         return -1;
2767
2768                 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, entry, permset) == -1)
2769                         return -1;
2770         }
2771
2772         /*
2773          * If this is a simple 3 element ACL or no elements then it's a standard
2774          * UNIX permission set. Just use chmod...       
2775          */
2776
2777         if ((num_entries == 3) || (num_entries == 0))
2778                 return -1;
2779
2780         return 0;
2781 }
2782
2783 /****************************************************************************
2784  Get the access ACL of FROM, do a chmod by setting the ACL USER_OBJ,
2785  GROUP_OBJ and OTHER bits in an ACL and set the mask to rwx. Set the
2786  resulting ACL on TO.  Note that name is in UNIX character set.
2787 ****************************************************************************/
2788
2789 static int copy_access_acl(connection_struct *conn, const char *from, const char *to, mode_t mode)
2790 {
2791         SMB_ACL_T posix_acl = NULL;
2792         int ret = -1;
2793
2794         if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, from, SMB_ACL_TYPE_ACCESS)) == NULL)
2795                 return -1;
2796
2797         if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
2798                 goto done;
2799
2800         ret = SMB_VFS_SYS_ACL_SET_FILE(conn, to, SMB_ACL_TYPE_ACCESS, posix_acl);
2801
2802  done:
2803
2804         SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
2805         return ret;
2806 }
2807
2808 /****************************************************************************
2809  Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
2810  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
2811  Note that name is in UNIX character set.
2812 ****************************************************************************/
2813
2814 int chmod_acl(connection_struct *conn, const char *name, mode_t mode)
2815 {
2816         return copy_access_acl(conn, name, name, mode);
2817 }
2818
2819 /****************************************************************************
2820  If "inherit permissions" is set and the parent directory has no default
2821  ACL but it does have an Access ACL, inherit this Access ACL to file name.
2822 ****************************************************************************/
2823
2824 int inherit_access_acl(connection_struct *conn, const char *name, mode_t mode)
2825 {
2826         pstring dirname;
2827         pstrcpy(dirname, parent_dirname(name));
2828
2829         if (!lp_inherit_perms(SNUM(conn)) || directory_has_default_acl(conn, dirname))
2830                 return 0;
2831
2832         return copy_access_acl(conn, dirname, name, mode);
2833 }
2834
2835 /****************************************************************************
2836  Do an fchmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
2837  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
2838 ****************************************************************************/
2839
2840 int fchmod_acl(files_struct *fsp, int fd, mode_t mode)
2841 {
2842         connection_struct *conn = fsp->conn;
2843         SMB_ACL_T posix_acl = NULL;
2844         int ret = -1;
2845
2846         if ((posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fd)) == NULL)
2847                 return -1;
2848
2849         if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
2850                 goto done;
2851
2852         ret = SMB_VFS_SYS_ACL_SET_FD(fsp, fd, posix_acl);
2853
2854   done:
2855
2856         SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
2857         return ret;
2858 }
2859
2860 /****************************************************************************
2861  Check for an existing default POSIX ACL on a directory.
2862 ****************************************************************************/
2863
2864 BOOL directory_has_default_acl(connection_struct *conn, const char *fname)
2865 {
2866         SMB_ACL_T dir_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_DEFAULT);
2867         BOOL has_acl = False;
2868         SMB_ACL_ENTRY_T entry;
2869
2870         if (dir_acl != NULL && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, dir_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1))
2871                 has_acl = True;
2872
2873         if (dir_acl)
2874                 SMB_VFS_SYS_ACL_FREE_ACL(conn, dir_acl);
2875         return has_acl;
2876 }