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