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