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