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