Updated from 2.2.
[ira/wip.git] / source / smbd / posix_acls.c
1 #define OLD_NTDOMAIN 1
2 /*
3    Unix SMB/Netbios implementation.
4    Version 1.9.
5    SMB NT Security Descriptor / Unix permission conversion.
6    Copyright (C) Jeremy Allison 1994-2000
7
8    This program is free software; you can redistribute it and/or modify
9    it under the terms of the GNU General Public License as published by
10    the Free Software Foundation; either version 2 of the License, or
11    (at your option) any later version.
12
13    This program is distributed in the hope that it will be useful,
14    but WITHOUT ANY WARRANTY; without even the implied warranty of
15    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16    GNU General Public License for more details.
17
18    You should have received a copy of the GNU General Public License
19    along with this program; if not, write to the Free Software
20    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
21 */
22
23 #include "includes.h"
24
25 enum ace_owner {UID_ACE, GID_ACE, WORLD_ACE};
26
27 typedef union posix_id {
28                 uid_t uid;
29                 gid_t gid;
30                 int world;
31 } posix_id;
32
33 typedef struct canon_ace {
34         struct canon_ace *next, *prev;
35         SMB_ACL_TAG_T type;
36         mode_t perms; /* Only use S_I(R|W|X)USR mode bits here. */
37         DOM_SID sid;
38         enum ace_owner owner_type;
39         posix_id unix_ug; 
40 } canon_ace;
41
42 static void free_canon_ace_list( canon_ace *list_head );
43
44 #if 0
45 /****************************************************************************
46  Function to duplicate a canon_ace struct.
47 ****************************************************************************/
48
49 static canon_ace *dup_canon_ace( canon_ace *c_ace)
50 {
51         canon_ace *new_ace = (canon_ace *)malloc(sizeof(canon_ace));
52
53         if (new_ace == NULL)
54                 return NULL;
55
56         *new_ace = *c_ace;
57
58         return new_ace;
59 }
60 #endif
61
62 /****************************************************************************
63  Function to create owner and group SIDs from a SMB_STRUCT_STAT.
64 ****************************************************************************/
65
66 static void create_file_sids(SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SID *pgroup_sid)
67 {
68         uid_to_sid( powner_sid, psbuf->st_uid );
69         gid_to_sid( pgroup_sid, psbuf->st_gid );
70 }
71
72 /****************************************************************************
73  Map canon_ace perms to permission bits NT.
74 ****************************************************************************/
75
76 static SEC_ACCESS map_canon_ace_perms(int *pacl_type, DOM_SID *powner_sid, canon_ace *ace)
77 {
78         SEC_ACCESS sa;
79         uint32 nt_mask = 0;
80
81         *pacl_type = SEC_ACE_TYPE_ACCESS_ALLOWED;
82
83         if((ace->perms & (S_IRWXU|S_IWUSR|S_IXUSR)) == (S_IRWXU|S_IWUSR|S_IXUSR)) {
84                         nt_mask = UNIX_ACCESS_RWX;
85         } else if((ace->perms & (S_IRWXU|S_IWUSR|S_IXUSR)) == 0) {
86                 /*
87                  * Here we differentiate between the owner and any other user.
88                  */
89                 if (sid_equal(powner_sid, &ace->sid)) {
90                         nt_mask = UNIX_ACCESS_NONE;
91                 } else {
92                         /* Not owner, no access. */
93                         nt_mask = 0;
94                 }
95         } else {
96                 nt_mask |= ((ace->perms & S_IRWXU) ? UNIX_ACCESS_R : 0 );
97                 nt_mask |= ((ace->perms & S_IWUSR) ? UNIX_ACCESS_W : 0 );
98                 nt_mask |= ((ace->perms & S_IXUSR) ? UNIX_ACCESS_X : 0 );
99         }
100
101         DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n",
102                         (unsigned int)ace->perms, (unsigned int)nt_mask ));
103
104         init_sec_access(&sa,nt_mask);
105         return sa;
106 }
107
108 /****************************************************************************
109  Map NT perms to a UNIX mode_t.
110 ****************************************************************************/
111
112 #define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES)
113 #define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA|FILE_WRITE_ATTRIBUTES)
114 #define FILE_SPECIFIC_EXECUTE_BITS (FILE_EXECUTE)
115
116 static mode_t map_nt_perms( SEC_ACCESS sec_access, int type)
117 {
118         mode_t mode = 0;
119
120         switch(type) {
121         case S_IRUSR:
122                 if(sec_access.mask & GENERIC_ALL_ACCESS)
123                         mode = S_IRUSR|S_IWUSR|S_IXUSR;
124                 else {
125                         mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRUSR : 0;
126                         mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWUSR : 0;
127                         mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXUSR : 0;
128                 }
129                 break;
130         case S_IRGRP:
131                 if(sec_access.mask & GENERIC_ALL_ACCESS)
132                         mode = S_IRGRP|S_IWGRP|S_IXGRP;
133                 else {
134                         mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRGRP : 0;
135                         mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWGRP : 0;
136                         mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXGRP : 0;
137                 }
138                 break;
139         case S_IROTH:
140                 if(sec_access.mask & GENERIC_ALL_ACCESS)
141                         mode = S_IROTH|S_IWOTH|S_IXOTH;
142                 else {
143                         mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IROTH : 0;
144                         mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWOTH : 0;
145                         mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXOTH : 0;
146                 }
147                 break;
148         }
149
150         return mode;
151 }
152
153 /****************************************************************************
154  Unpack a SEC_DESC into a UNIX owner and group.
155 ****************************************************************************/
156
157 static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, SEC_DESC *psd)
158 {
159         DOM_SID owner_sid;
160         DOM_SID grp_sid;
161         enum SID_NAME_USE sid_type;
162
163         *puser = (uid_t)-1;
164         *pgrp = (gid_t)-1;
165
166         if(security_info_sent == 0) {
167                 DEBUG(0,("unpack_nt_owners: no security info sent !\n"));
168                 return False;
169         }
170
171         /*
172          * Validate the owner and group SID's.
173          */
174
175         memset(&owner_sid, '\0', sizeof(owner_sid));
176         memset(&grp_sid, '\0', sizeof(grp_sid));
177
178         DEBUG(5,("unpack_nt_owners: validating owner_sids.\n"));
179
180         /*
181          * Don't immediately fail if the owner sid cannot be validated.
182          * This may be a group chown only set.
183          */
184
185         if (security_info_sent & OWNER_SECURITY_INFORMATION) {
186                 sid_copy(&owner_sid, psd->owner_sid);
187                 if (!sid_to_uid( &owner_sid, puser, &sid_type))
188                         DEBUG(3,("unpack_nt_owners: unable to validate owner sid.\n"));
189         }
190
191         /*
192          * Don't immediately fail if the group sid cannot be validated.
193          * This may be an owner chown only set.
194          */
195
196         if (security_info_sent & GROUP_SECURITY_INFORMATION) {
197                 sid_copy(&grp_sid, psd->grp_sid);
198                 if (!sid_to_gid( &grp_sid, pgrp, &sid_type))
199                         DEBUG(3,("unpack_nt_owners: unable to validate group sid.\n"));
200         }
201
202         return True;
203 }
204
205 /****************************************************************************
206  Unpack a SEC_DESC into two canonical ace lists. We don't depend on this
207  succeeding.
208 ****************************************************************************/
209
210 static BOOL unpack_canon_ace(files_struct *fsp, 
211                                                         DOM_SID *pfile_owner_sid,
212                                                         DOM_SID *pfile_grp_sid,
213                                                         canon_ace **ppfile_ace, canon_ace **ppdir_ace,
214                                                         uint32 security_info_sent, SEC_DESC *psd)
215 {
216         extern DOM_SID global_sid_World;
217         SEC_ACL *dacl = psd->dacl;
218         BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False);
219         canon_ace *file_ace = NULL;
220         canon_ace *dir_ace = NULL;
221         enum SID_NAME_USE sid_type;
222         int i;
223
224         *ppfile_ace = NULL;
225         *ppdir_ace = NULL;
226
227         if(security_info_sent == 0) {
228                 DEBUG(0,("unpack_canon_ace: no security info sent !\n"));
229                 return False;
230         }
231
232         /*
233          * If no DACL then this is a chown only security descriptor.
234          */
235
236         if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !dacl)
237                 return True;
238
239         /*
240          * Now go through the DACL and create the canon_ace lists.
241          */
242
243         for(i = 0; i < dacl->num_aces; i++) {
244                 SEC_ACE *psa = &dacl->ace[i];
245                 canon_ace *current_ace = NULL;
246
247                 if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) && (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
248                         DEBUG(3,("unpack_canon_ace: unable to set anything but an ALLOW or DENY ACE.\n"));
249                         return False;
250                 }
251
252                 /*
253                  * The security mask may be UNIX_ACCESS_NONE which should map into
254                  * no permissions (we overload the WRITE_OWNER bit for this) or it
255                  * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
256                  * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
257                  */
258
259                 psa->info.mask &= (GENERIC_ALL_ACCESS|GENERIC_EXECUTE_ACCESS|GENERIC_WRITE_ACCESS|
260                                                         GENERIC_READ_ACCESS|UNIX_ACCESS_NONE|FILE_ALL_ATTRIBUTES);
261
262                 if(psa->info.mask != UNIX_ACCESS_NONE)
263                         psa->info.mask &= ~UNIX_ACCESS_NONE;
264
265                 /*
266                  * Create a cannon_ace entry representing this NT DACL ACE.
267                  */
268
269                 if ((current_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
270                         free_canon_ace_list(file_ace);
271                         free_canon_ace_list(dir_ace);
272                         DEBUG(0,("unpack_canon_ace: malloc fail.\n"));
273                         return False;
274                 }
275
276                 ZERO_STRUCTP(current_ace);
277
278                 sid_copy(&current_ace->sid, &psa->sid);
279
280                 /*
281                  * Try and work out if the SID is a user or group
282                  * as we need to flag these differently for POSIX.
283                  */
284
285                 if( sid_equal(&current_ace->sid, &global_sid_World)) {
286                         current_ace->owner_type = WORLD_ACE;
287                         current_ace->unix_ug.world = -1;
288                 } else if (sid_to_uid( &current_ace->sid, &current_ace->unix_ug.uid, &sid_type)) {
289                         current_ace->owner_type = UID_ACE;
290                 } else if (sid_to_gid( &current_ace->sid, &current_ace->unix_ug.gid, &sid_type)) {
291                         current_ace->owner_type = GID_ACE;
292                 } else {
293                         fstring str;
294
295                         free_canon_ace_list(file_ace);
296                         free_canon_ace_list(dir_ace);
297                         free(current_ace);
298                         DEBUG(0,("unpack_canon_ace: unable to map SID %s to uid or gid.\n",
299                                 sid_to_string(str, &current_ace->sid) ));
300                         return False;
301                 }
302
303                 /*
304                  * Map the given NT permissions into a UNIX mode_t containing only
305                  * S_I(R|W|X)USR bits.
306                  */
307
308                 if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
309                         current_ace->perms |= map_nt_perms( psa->info, S_IRUSR);
310                 else
311                         current_ace->perms &= ~(map_nt_perms( psa->info, S_IRUSR));
312
313                 /*
314                  * Now note what kind of a POSIX ACL this should map to.
315                  */
316
317                 if(sid_equal(&current_ace->sid, pfile_owner_sid)) {
318                         /* Note we should apply the default mode/mask here.... FIXME ! JRA */
319                         current_ace->type = SMB_ACL_USER_OBJ;
320                 } else if( sid_equal(&current_ace->sid, pfile_grp_sid)) {
321                         /* Note we should apply the default mode/mask here.... FIXME ! JRA */
322                         current_ace->type = SMB_ACL_GROUP_OBJ;
323                 } else if( sid_equal(&current_ace->sid, &global_sid_World)) {
324                         /* Note we should apply the default mode/mask here.... FIXME ! JRA */
325                         current_ace->type = SMB_ACL_OTHER;
326                 } else {
327                         /*
328                          * Could be a SMB_ACL_USER or SMB_ACL_GROUP. Check by
329                          * looking at owner_type.
330                          */
331
332                         current_ace->type = (current_ace->owner_type == UID_ACE) ? SMB_ACL_USER : SMB_ACL_GROUP;
333                 }
334
335                 if (fsp->is_directory && (psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
336                         /*
337                          * We can only add to the default POSIX ACE list if the ACE is
338                          * designed to be inherited by both files and directories.
339                          */
340                         if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) ==
341                                 (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) {
342                                 DLIST_ADD(dir_ace, current_ace);
343                         } else {
344                                 DEBUG(0,("unpack_canon_ace: unable to use a non-generic default ACE.\n"));
345                                 free(current_ace);
346                         }
347                 } else {
348                         DLIST_ADD(file_ace, current_ace);
349                         all_aces_are_inherit_only = False;
350                 }
351         }
352
353         if (fsp->is_directory && all_aces_are_inherit_only) {
354                 /*
355                  * Windows 2000 is doing one of these weird 'inherit acl'
356                  * traverses to conserve NTFS ACL resources. Just pretend
357                  * there was no DACL sent. JRA.
358                  */
359
360                 DEBUG(10,("unpack_posix_permissions: Win2k inherit acl traverse. Ignoring DACL.\n"));
361                 free_sec_acl(&psd->dacl);
362         }
363
364         *ppfile_ace = file_ace;
365         *ppdir_ace = dir_ace;
366         return True;
367 }
368
369 /****************************************************************************
370  Unpack a SEC_DESC into a set of standard POSIX permissions.
371 ****************************************************************************/
372
373 static BOOL unpack_posix_permissions(files_struct *fsp, SMB_STRUCT_STAT *psbuf, mode_t *pmode,
374                                                                 uint32 security_info_sent, SEC_DESC *psd)
375 {
376   extern DOM_SID global_sid_World;
377   connection_struct *conn = fsp->conn;
378   DOM_SID file_owner_sid;
379   DOM_SID file_grp_sid;
380   SEC_ACL *dacl = psd->dacl;
381   BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False);
382   int i;
383
384   *pmode = 0;
385
386   if(security_info_sent == 0) {
387     DEBUG(0,("unpack_posix_permissions: no security info sent !\n"));
388     return False;
389   }
390
391   /*
392    * Windows 2000 sends the owner and group SIDs as the logged in
393    * user, not the connected user. But it still sends the file
394    * owner SIDs on an ACL set. So we need to check for the file
395    * owner and group SIDs as well as the owner SIDs. JRA.
396    */
397  
398   create_file_sids(psbuf, &file_owner_sid, &file_grp_sid);
399
400   /*
401    * If no DACL then this is a chown only security descriptor.
402    */
403
404   if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !dacl) {
405     *pmode = 0;
406     return True;
407   }
408
409   /*
410    * Now go through the DACL and ensure that
411    * any owner/group sids match.
412    */
413
414   for(i = 0; i < dacl->num_aces; i++) {
415     DOM_SID ace_sid;
416     SEC_ACE *psa = &dacl->ace[i];
417
418     if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) &&
419        (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
420       DEBUG(3,("unpack_posix_permissions: unable to set anything but an ALLOW or DENY ACE.\n"));
421       return False;
422     }
423
424     /*
425      * Ignore or remove bits we don't care about on a directory ACE.
426      */
427
428     if(fsp->is_directory) {
429       if(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
430         DEBUG(3,("unpack_posix_permissions: ignoring inherit only ACE.\n"));
431         continue;
432       }
433
434       /*
435        * At least one of the ACE entries wasn't inherit only.
436        * Flag this so we know the returned mode is valid.
437        */
438
439       all_aces_are_inherit_only = False;
440     }
441
442     /*
443      * Windows 2000 sets these flags even on *file* ACE's. This is wrong
444      * but we can ignore them for now. Revisit this when we go to POSIX
445      * ACLs on directories.
446      */
447
448     psa->flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT);
449
450     if(psa->flags != 0) {
451       DEBUG(1,("unpack_posix_permissions: unable to set ACE flags (%x).\n", 
452             (unsigned int)psa->flags));
453       return False;
454     }
455
456     /*
457      * The security mask may be UNIX_ACCESS_NONE which should map into
458      * no permissions (we overload the WRITE_OWNER bit for this) or it
459      * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
460      * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
461      */
462
463     psa->info.mask &= (GENERIC_ALL_ACCESS|GENERIC_EXECUTE_ACCESS|GENERIC_WRITE_ACCESS|
464                      GENERIC_READ_ACCESS|UNIX_ACCESS_NONE|FILE_ALL_ATTRIBUTES);
465
466     if(psa->info.mask != UNIX_ACCESS_NONE)
467       psa->info.mask &= ~UNIX_ACCESS_NONE;
468
469     sid_copy(&ace_sid, &psa->sid);
470
471     if(sid_equal(&ace_sid, &file_owner_sid)) {
472       /*
473        * Map the desired permissions into owner perms.
474        */
475
476       if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
477         *pmode |= map_nt_perms( psa->info, S_IRUSR);
478       else
479         *pmode &= ~(map_nt_perms( psa->info, S_IRUSR));
480
481     } else if( sid_equal(&ace_sid, &file_grp_sid)) {
482       /*
483        * Map the desired permissions into group perms.
484        */
485
486       if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
487         *pmode |= map_nt_perms( psa->info, S_IRGRP);
488       else
489         *pmode &= ~(map_nt_perms( psa->info, S_IRGRP));
490
491     } else if( sid_equal(&ace_sid, &global_sid_World)) {
492       /*
493        * Map the desired permissions into other perms.
494        */
495
496       if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
497         *pmode |= map_nt_perms( psa->info, S_IROTH);
498       else
499         *pmode &= ~(map_nt_perms( psa->info, S_IROTH));
500
501     } else {
502       DEBUG(0,("unpack_posix_permissions: unknown SID used in ACL.\n"));
503       return False;
504     }
505   }
506
507   if (fsp->is_directory && all_aces_are_inherit_only) {
508     /*
509      * Windows 2000 is doing one of these weird 'inherit acl'
510      * traverses to conserve NTFS ACL resources. Just pretend
511      * there was no DACL sent. JRA.
512      */
513
514     DEBUG(10,("unpack_posix_permissions: Win2k inherit acl traverse. Ignoring DACL.\n"));
515     free_sec_acl(&psd->dacl);
516   }
517
518   /*
519    * Check to see if we need to change anything.
520    * Enforce limits on modified bits *only*. Don't enforce masks
521    * on bits not changed by the user.
522    */
523
524   if(fsp->is_directory) {
525
526     *pmode &= (lp_dir_security_mask(SNUM(conn)) | psbuf->st_mode);
527     *pmode |= (lp_force_dir_security_mode(SNUM(conn)) & ( *pmode ^ psbuf->st_mode ));
528
529   } else {
530
531     *pmode &= (lp_security_mask(SNUM(conn)) | psbuf->st_mode); 
532     *pmode |= (lp_force_security_mode(SNUM(conn)) & ( *pmode ^ psbuf->st_mode ));
533
534   }
535
536   /*
537    * Preserve special bits.
538    */
539
540   *pmode |= (psbuf->st_mode & ~0777);
541
542   return True;
543 }
544
545 /****************************************************************************
546  Map POSIX ACL perms to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
547 ****************************************************************************/
548
549 static mode_t convert_permset_to_mode_t(SMB_ACL_PERMSET_T permset)
550 {
551         mode_t ret = 0;
552
553         ret |= (sys_acl_get_perm(permset, SMB_ACL_READ) ? S_IRUSR : 0);
554         ret |= (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? S_IWUSR : 0);
555         ret |= (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? S_IXUSR : 0);
556
557         return ret;
558 }
559
560 /****************************************************************************
561  Map generic UNIX permissions to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
562 ****************************************************************************/
563
564 static mode_t unix_perms_to_acl_perms(mode_t mode, int r_mask, int w_mask, int x_mask)
565 {
566         mode_t ret = 0;
567
568         if (mode & r_mask)
569                 ret |= S_IRUSR;
570         if (mode & w_mask)
571                 ret |= S_IWUSR;
572         if (mode & x_mask)
573                 ret |= S_IXUSR;
574
575         return ret;
576 }
577
578 /****************************************************************************
579  Map canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits) to
580  an SMB_ACL_PERMSET_T.
581 ****************************************************************************/
582
583 static int map_acl_perms_to_permset(mode_t mode, SMB_ACL_PERMSET_T *p_permset)
584 {
585         if (sys_acl_clear_perms(*p_permset) ==  -1)
586                 return -1;
587         if (mode & S_IRUSR) {
588                 if (sys_acl_add_perm(*p_permset, SMB_ACL_READ) == -1)
589                         return -1;
590         }
591         if (mode & S_IWUSR) {
592                 if (sys_acl_add_perm(*p_permset, SMB_ACL_WRITE) == -1)
593                         return -1;
594         }
595         if (mode & S_IXUSR) {
596                 if (sys_acl_add_perm(*p_permset, SMB_ACL_EXECUTE) == -1)
597                         return -1;
598         }
599         return 0;
600 }
601
602 /****************************************************************************
603  Count a linked list of canonical ACE entries.
604 ****************************************************************************/
605
606 static size_t count_canon_ace_list( canon_ace *list_head )
607 {
608         size_t count = 0;
609         canon_ace *ace;
610
611         for (ace = list_head; ace; ace = ace->next)
612                 count++;
613
614         return count;
615 }
616
617 /****************************************************************************
618  Free a linked list of canonical ACE entries.
619 ****************************************************************************/
620
621 static void free_canon_ace_list( canon_ace *list_head )
622 {
623         while (list_head) {
624                 canon_ace *old_head = list_head;
625                 DLIST_REMOVE(list_head, list_head);
626                 free(old_head);
627         }
628 }
629
630 /******************************************************************************
631  Fall back to the generic 3 element UNIX permissions.
632 ********************************************************************************/
633
634 static canon_ace *unix_canonicalise_acl(files_struct *fsp, SMB_STRUCT_STAT *psbuf,
635                                                                                 DOM_SID *powner, DOM_SID *pgroup)
636 {
637         extern DOM_SID global_sid_World;
638         canon_ace *list_head = NULL;
639         canon_ace *owner_ace = NULL;
640         canon_ace *group_ace = NULL;
641         canon_ace *other_ace = NULL;
642
643         /*
644          * Create 3 linked list entries.
645          */
646
647         if ((owner_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
648                 goto fail;
649
650         if ((group_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
651                 goto fail;
652
653         if ((other_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
654                 goto fail;
655
656         ZERO_STRUCTP(owner_ace);
657         ZERO_STRUCTP(group_ace);
658         ZERO_STRUCTP(other_ace);
659
660         owner_ace->type = SMB_ACL_USER_OBJ;
661         owner_ace->sid = *powner;
662         owner_ace->unix_ug.uid = psbuf->st_uid;
663         owner_ace->owner_type = UID_ACE;
664
665         group_ace->type = SMB_ACL_GROUP_OBJ;
666         group_ace->sid = *pgroup;
667         owner_ace->unix_ug.gid = psbuf->st_gid;
668         owner_ace->owner_type = GID_ACE;
669
670         other_ace->type = SMB_ACL_OTHER;
671         other_ace->sid = global_sid_World;
672         owner_ace->unix_ug.world = -1;
673         owner_ace->owner_type = WORLD_ACE;
674
675         if (!fsp->is_directory) {
676                 owner_ace->perms = unix_perms_to_acl_perms(psbuf->st_mode, S_IRUSR, S_IWUSR, S_IXUSR);
677                 group_ace->perms = unix_perms_to_acl_perms(psbuf->st_mode, S_IRGRP, S_IWGRP, S_IXGRP);
678                 other_ace->perms = unix_perms_to_acl_perms(psbuf->st_mode, S_IROTH, S_IWOTH, S_IXOTH);
679         } else {
680                 mode_t mode = unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name);
681
682                 owner_ace->perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
683                 group_ace->perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
684                 other_ace->perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
685         }
686
687         DLIST_ADD(list_head, other_ace);
688         DLIST_ADD(list_head, group_ace);
689         DLIST_ADD(list_head, owner_ace);
690
691         return list_head;
692
693   fail:
694
695         safe_free(owner_ace);
696         safe_free(group_ace);
697         safe_free(other_ace);
698
699         return NULL;
700 }
701
702 /****************************************************************************
703  Create a linked list of canonical ACE entries. This is sorted so that DENY
704  entries are at the front of the list, as NT requires.
705 ****************************************************************************/
706
707 static canon_ace *canonicalise_acl( SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf)
708 {
709         extern DOM_SID global_sid_World;
710         mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR);
711         canon_ace *list_head = NULL;
712         canon_ace *ace = NULL;
713         canon_ace *next_ace = NULL;
714         int entry_id = SMB_ACL_FIRST_ENTRY;
715         SMB_ACL_ENTRY_T entry;
716
717         while ( sys_acl_get_entry(posix_acl, entry_id, &entry) == 1) {
718                 SMB_ACL_TAG_T tagtype;
719                 SMB_ACL_PERMSET_T permset;
720                 DOM_SID sid;
721                 posix_id unix_ug;
722                 enum ace_owner owner_type;
723
724                 /* get_next... */
725                 if (entry_id == SMB_ACL_FIRST_ENTRY)
726                         entry_id = SMB_ACL_NEXT_ENTRY;
727
728                 /* Is this a MASK entry ? */
729                 if (sys_acl_get_tag_type(entry, &tagtype) == -1)
730                         continue;
731
732                 if (sys_acl_get_permset(entry, &permset) == -1)
733                         continue;
734
735                 /* Decide which SID to use based on the ACL type. */
736                 switch(tagtype) {
737                         case SMB_ACL_USER_OBJ:
738                                 /* Get the SID from the owner. */
739                                 uid_to_sid( &sid, psbuf->st_uid );
740                                 unix_ug.uid = psbuf->st_uid;
741                                 owner_type = UID_ACE;
742                                 break;
743                         case SMB_ACL_USER:
744                                 {
745                                         uid_t *puid = (uid_t *)sys_acl_get_qualifier(entry);
746                                         if (puid == NULL) {
747                                                 DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
748                                                 continue;
749                                         }
750                                         uid_to_sid( &sid, *puid);
751                                         unix_ug.uid = *puid;
752                                         owner_type = UID_ACE;
753                                         break;
754                                 }
755                         case SMB_ACL_GROUP_OBJ:
756                                 /* Get the SID from the owning group. */
757                                 gid_to_sid( &sid, psbuf->st_gid );
758                                 unix_ug.gid = psbuf->st_gid;
759                                 owner_type = GID_ACE;
760                                 break;
761                         case SMB_ACL_GROUP:
762                                 {
763                                         gid_t *pgid = (gid_t *)sys_acl_get_qualifier(entry);
764                                         if (pgid == NULL) {
765                                                 DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
766                                                 continue;
767                                         }
768                                         gid_to_sid( &sid, *pgid);
769                                         unix_ug.gid = *pgid;
770                                         owner_type = GID_ACE;
771                                         break;
772                                 }
773                         case SMB_ACL_MASK:
774                                 acl_mask = convert_permset_to_mode_t(permset);
775                                 continue; /* Don't count the mask as an entry. */
776                         case SMB_ACL_OTHER:
777                                 /* Use the Everyone SID */
778                                 sid = global_sid_World;
779                                 unix_ug.world = -1;
780                                 owner_type = WORLD_ACE;
781                                 break;
782                         default:
783                                 DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype));
784                                 continue;
785                 }
786
787                 /*
788                  * Add this entry to the list.
789                  */
790
791                 if ((ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
792                         goto fail;
793
794                 ZERO_STRUCTP(ace);
795                 ace->type = tagtype;
796                 ace->perms = convert_permset_to_mode_t(permset);
797                 ace->sid = sid;
798                 ace->unix_ug = unix_ug;
799                 ace->owner_type = owner_type;
800
801                 DLIST_ADD(list_head, ace);
802         }
803
804         /*
805          * Now go through the list, masking the permissions with the
806          * acl_mask. If the permissions are 0 it should be listed
807          * first.
808          */
809
810         for ( ace = list_head; ace; ace = next_ace) {
811                 next_ace = ace->next;
812
813                 /* Masks are only applied to entries other than USER_OBJ and OTHER. */
814                 if (ace->type != SMB_ACL_OTHER && ace->type != SMB_ACL_USER_OBJ)
815                         ace->perms &= acl_mask;
816
817                 if (ace->perms == 0)
818                         DLIST_PROMOTE(list_head, ace);
819         }
820
821         if( DEBUGLVL( 10 ) ) {
822                 char *acl_text = sys_acl_to_text( posix_acl, NULL);
823
824                 dbgtext("canonicalize_acl: processed acl %s\n", acl_text == NULL ? "NULL" : acl_text );
825                 if (acl_text)
826                         sys_acl_free_text(acl_text);
827         }
828
829         return list_head;
830
831   fail:
832
833         free_canon_ace_list(list_head);
834         return NULL;
835 }
836
837 /****************************************************************************
838  Attempt to apply an ACL to a file or directory.
839 ****************************************************************************/
840
841 static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL default_ace)
842 {
843         BOOL ret = False;
844         SMB_ACL_T the_acl = sys_acl_init((int)count_canon_ace_list(the_ace) + 1);
845         canon_ace *p_ace;
846         int i;
847         SMB_ACL_ENTRY_T mask_entry;
848         SMB_ACL_PERMSET_T mask_permset;
849         SMB_ACL_TYPE_T the_acl_type = (default_ace ? SMB_ACL_TYPE_DEFAULT : SMB_ACL_TYPE_ACCESS);
850
851         if (the_acl == NULL) {
852 #if !defined(HAVE_NO_ACLS)
853                 /*
854                  * Only print this error message if we have some kind of ACL
855                  * support that's not working. Otherwise we would always get this.
856                  */
857                 DEBUG(0,("set_canon_ace_list: Unable to init %s ACL. (%s)\n",
858                         default_ace ? "default" : "file", strerror(errno) ));
859 #endif
860                 return False;
861         }
862
863         for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
864                 SMB_ACL_ENTRY_T the_entry;
865                 SMB_ACL_PERMSET_T the_permset;
866
867                 /*
868                  * Get the entry for this ACE.
869                  */
870
871                 if (sys_acl_create_entry( &the_acl, &the_entry) == -1) {
872                         DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n",
873                                 i, strerror(errno) ));
874                         goto done;
875                 }
876
877                 /*
878                  * Initialise the entry from the canon_ace.
879                  */
880
881                 /*
882                  * First tell the entry what type of ACE this is.
883                  */
884
885                 if (sys_acl_set_tag_type(the_entry, p_ace->type) == -1) {
886                         DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n",
887                                 i, strerror(errno) ));
888                         goto done;
889                 }
890
891                 /*
892                  * Only set the qualifier (user or group id) if the entry is a user
893                  * or group id ACE.
894                  */
895
896                 if ((p_ace->type == SMB_ACL_USER) || (p_ace->type == SMB_ACL_GROUP)) {
897                         if (sys_acl_set_qualifier(the_entry,(void *)&p_ace->unix_ug.uid) == -1) {
898                                 DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n",
899                                         i, strerror(errno) ));
900                                 goto done;
901                         }
902                 }
903
904                 /*
905                  * Convert the mode_t perms in the canon_ace to a POSIX permset.
906                  */
907
908                 if (sys_acl_get_permset(the_entry, &the_permset) == -1) {
909                         DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n",
910                                 i, strerror(errno) ));
911                         goto done;
912                 }
913
914                 if (map_acl_perms_to_permset(p_ace->perms, &the_permset) == -1) {
915                         DEBUG(0,("set_canon_ace_list: Failed to create permset for mode (%u) on entry %d. (%s)\n",
916                                 p_ace->perms, i, strerror(errno) ));
917                         goto done;
918                 }
919
920                 /*
921                  * ..and apply them to the entry.
922                  */
923
924                 if (sys_acl_set_permset(the_entry, the_permset) == -1) {
925                         DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n",
926                                 i, strerror(errno) ));
927                         goto done;
928                 }
929         }
930
931         /*
932          * Add in a mask of rwx.
933          */
934
935         if (sys_acl_create_entry( &the_acl, &mask_entry) == -1) {
936                 DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) ));
937                 goto done;
938         }
939
940         if (sys_acl_set_tag_type(mask_entry, SMB_ACL_MASK) == -1) {
941                 DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno) ));
942                 goto done;
943         }
944
945         if (sys_acl_get_permset(mask_entry, &mask_permset) == -1) {
946                 DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) ));
947                 goto done;
948         }
949
950         if (map_acl_perms_to_permset(S_IRUSR|S_IWUSR|S_IXUSR, &mask_permset) == -1) {
951                 DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno) ));
952                 goto done;
953         }
954
955         if (sys_acl_set_permset(mask_entry, mask_permset) == -1) {
956                 DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) ));
957                 goto done;
958         }
959
960         /*
961          * Check if the ACL is valid.
962          */
963
964         if (sys_acl_valid(the_acl) == -1) {
965                 DEBUG(0,("set_canon_ace_list: ACL is invalid for set (%s).\n", strerror(errno) ));
966                 goto done;
967         }
968
969         /*
970          * Finally apply it to the file or directory.
971          */
972
973         if(default_ace || fsp->is_directory || fsp->fd == -1) {
974                 if (sys_acl_set_file(fsp->fsp_name, the_acl_type, the_acl) == -1) {
975                         DEBUG(0,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n",
976                                         fsp->fsp_name, strerror(errno) ));
977                         goto done;
978                 }
979         } else {
980                 if (sys_acl_set_fd(fsp->fd, the_acl) == -1) {
981                         DEBUG(0,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n",
982                                         fsp->fsp_name, strerror(errno) ));
983                         goto done;
984                 }
985         }
986
987         ret = True;
988
989   done:
990
991         if (the_acl != NULL)
992             sys_acl_free_acl(the_acl);
993
994         return ret;
995 }
996
997 /****************************************************************************
998  Reply to query a security descriptor from an fsp. If it succeeds it allocates
999  the space for the return elements and returns the size needed to return the
1000  security descriptor. This should be the only external function needed for
1001  the UNIX style get ACL.
1002 ****************************************************************************/
1003
1004 size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc)
1005 {
1006         SMB_STRUCT_STAT sbuf;
1007         SEC_ACE *nt_ace_list;
1008         DOM_SID owner_sid;
1009         DOM_SID group_sid;
1010         size_t sd_size = 0;
1011         SEC_ACL *psa = NULL;
1012         size_t num_acls = 0;
1013         size_t num_dir_acls = 0;
1014         size_t num_aces = 0;
1015         SMB_ACL_T posix_acl = NULL;
1016         SMB_ACL_T dir_acl = NULL;
1017         canon_ace *file_ace = NULL;
1018         canon_ace *dir_ace = NULL;
1019  
1020         *ppdesc = NULL;
1021
1022         if(fsp->is_directory || fsp->fd == -1) {
1023
1024                 /* Get the stat struct for the owner info. */
1025                 if(vfs_stat(fsp->conn,fsp->fsp_name, &sbuf) != 0) {
1026                         return 0;
1027                 }
1028                 /*
1029                  * Get the ACL from the path.
1030                  */
1031
1032                 posix_acl = sys_acl_get_file( dos_to_unix(fsp->fsp_name, False), SMB_ACL_TYPE_ACCESS);
1033
1034                 /*
1035                  * If it's a directory get the default POSIX ACL.
1036                  */
1037
1038                 if(fsp->is_directory)
1039                         dir_acl = sys_acl_get_file( dos_to_unix(fsp->fsp_name, False), SMB_ACL_TYPE_DEFAULT);
1040
1041         } else {
1042
1043                 /* Get the stat struct for the owner info. */
1044                 if(vfs_fstat(fsp,fsp->fd,&sbuf) != 0) {
1045                         return 0;
1046                 }
1047                 /*
1048                  * Get the ACL from the fd.
1049                  */
1050                 posix_acl = sys_acl_get_fd(fsp->fd);
1051         }
1052
1053         DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n",
1054                         posix_acl ? "present" :  "absent",
1055                         dir_acl ? "present" :  "absent" ));
1056
1057         /*
1058          * Get the owner, group and world SIDs.
1059          */
1060
1061         create_file_sids(&sbuf, &owner_sid, &group_sid);
1062
1063         /* Create the canon_ace lists. */
1064         if (posix_acl)
1065                 file_ace = canonicalise_acl( posix_acl, &sbuf);
1066         else
1067                 file_ace = unix_canonicalise_acl(fsp, &sbuf, &owner_sid, &group_sid);
1068
1069         num_acls = count_canon_ace_list(file_ace);
1070
1071         if (fsp->is_directory) { 
1072                 if (dir_ace)
1073                         dir_ace = canonicalise_acl( dir_acl, &sbuf);
1074                 else
1075                         dir_ace = unix_canonicalise_acl(fsp, &sbuf, &owner_sid, &group_sid);
1076
1077                 num_dir_acls = count_canon_ace_list(dir_ace);
1078         }
1079
1080         /* Allocate the ace list. */
1081         if ((nt_ace_list = (SEC_ACE *)malloc((num_acls + num_dir_acls)* sizeof(SEC_ACE))) == NULL) {
1082                 DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
1083                 goto done;
1084         }
1085
1086         memset(nt_ace_list, '\0', (num_acls + num_dir_acls) * sizeof(SEC_ACE) );
1087
1088         /*
1089          * Create the NT ACE list from the canonical ace lists.
1090          */
1091
1092         {
1093                 canon_ace *ace;
1094                 int nt_acl_type;
1095                 int i;
1096
1097                 ace = file_ace;
1098
1099                 for (i = 0; i < num_acls; i++, ace = ace->next) {
1100                         SEC_ACCESS acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
1101                         init_sec_ace(&nt_ace_list[num_aces++], &ace->sid, nt_acl_type, acc, 0);
1102                 }
1103
1104                 ace = dir_ace;
1105
1106                 for (i = 0; i < num_dir_acls; i++, ace = ace->next) {
1107                         SEC_ACCESS acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
1108                         init_sec_ace(&nt_ace_list[num_aces++], &ace->sid, nt_acl_type, acc, 
1109                                         SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY);
1110                 }
1111         }
1112
1113         if (num_acls) {
1114                 if((psa = make_sec_acl( ACL_REVISION, num_aces, nt_ace_list)) == NULL) {
1115                         DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
1116                         goto done;
1117                 }
1118         }
1119
1120         *ppdesc = make_standard_sec_desc( &owner_sid, &group_sid, psa, &sd_size);
1121
1122         if(!*ppdesc) {
1123                 DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
1124                 sd_size = 0;
1125         }
1126
1127   done:
1128
1129         if (posix_acl)  
1130                 sys_acl_free_acl(posix_acl);
1131         if (dir_acl)
1132                 sys_acl_free_acl(dir_acl);
1133         free_canon_ace_list(file_ace);
1134         free_canon_ace_list(dir_ace);
1135         if (nt_ace_list)
1136                 free(nt_ace_list);
1137         if (psa)
1138                 free_sec_acl(&psa);
1139
1140         return sd_size;
1141 }
1142
1143 /****************************************************************************
1144  Reply to set a security descriptor on an fsp. security_info_sent is the
1145  description of the following NT ACL.
1146  This should be the only external function needed for the UNIX style set ACL.
1147 ****************************************************************************/
1148
1149 BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
1150 {
1151         connection_struct *conn = fsp->conn;
1152         uid_t user = (uid_t)-1;
1153         gid_t grp = (gid_t)-1;
1154         mode_t perms = 0;
1155         SMB_STRUCT_STAT sbuf;  
1156         DOM_SID file_owner_sid;
1157         DOM_SID file_grp_sid;
1158         canon_ace *file_ace_list = NULL;
1159         canon_ace *dir_ace_list = NULL;
1160         BOOL posix_perms;
1161         BOOL acl_perms;
1162
1163         /*
1164          * Get the current state of the file.
1165          */
1166
1167         if(fsp->is_directory || fsp->fd == -1) {
1168                 if(vfs_stat(fsp->conn,fsp->fsp_name, &sbuf) != 0)
1169                         return False;
1170         } else {
1171                 if(vfs_fstat(fsp,fsp->fd,&sbuf) != 0)
1172                         return False;
1173         }
1174
1175         /*
1176          * Unpack the user/group/world id's.
1177          */
1178
1179         if (!unpack_nt_owners( &sbuf, &user, &grp, security_info_sent, psd))
1180                 return False;
1181
1182         /*
1183          * Do we need to chown ?
1184          */
1185
1186         if((user != (uid_t)-1 || grp != (uid_t)-1) && (sbuf.st_uid != user || sbuf.st_gid != grp)) {
1187
1188                 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
1189                                 fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
1190
1191                 if(vfs_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
1192                         DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
1193                                 fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
1194                         return False;
1195                 }
1196
1197                 /*
1198                  * Recheck the current state of the file, which may have changed.
1199                  * (suid/sgid bits, for instance)
1200                  */
1201
1202                 if(fsp->is_directory) {
1203                         if(vfs_stat(fsp->conn, fsp->fsp_name, &sbuf) != 0) {
1204                                 return False;
1205                         }
1206                 } else {
1207
1208                         int ret;
1209     
1210                         if(fsp->fd == -1)
1211                                 ret = vfs_stat(fsp->conn, fsp->fsp_name, &sbuf);
1212                         else
1213                                 ret = vfs_fstat(fsp,fsp->fd,&sbuf);
1214   
1215                         if(ret != 0)
1216                                 return False;
1217                 }
1218         }
1219
1220         create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid);
1221
1222         posix_perms = unpack_posix_permissions( fsp, &sbuf, &perms, security_info_sent, psd);
1223         acl_perms = unpack_canon_ace( fsp, &file_owner_sid, &file_grp_sid,
1224                                                                         &file_ace_list, &dir_ace_list, security_info_sent, psd);
1225
1226         if (!posix_perms && !acl_perms) {
1227                 /*
1228                  * Neither method of setting permissions can work. Fail here.
1229                  */
1230
1231                 DEBUG(3,("set_nt_acl: cannot set normal POSIX permissions or POSIX ACL permissions\n"));
1232                 free_canon_ace_list(file_ace_list);
1233                 free_canon_ace_list(dir_ace_list); 
1234                 return False;
1235         }
1236
1237         /*
1238          * Only change security if we got a DACL.
1239          */
1240
1241         if((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl != NULL)) {
1242
1243                 BOOL acl_set_support = False;
1244
1245                 /*
1246                  * Try using the POSIX ACL set first. All back to chmod if
1247                  * we have no ACL support on this filesystem.
1248                  */
1249
1250                 if (acl_perms && file_ace_list && set_canon_ace_list(fsp, file_ace_list, False))
1251                         acl_set_support = True;
1252
1253                 if (acl_perms && acl_set_support && fsp->is_directory && dir_ace_list)
1254                         set_canon_ace_list(fsp, dir_ace_list, True);
1255
1256                 /*
1257                  * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
1258                  */
1259
1260                 if(!acl_set_support && (sbuf.st_mode != perms)) {
1261
1262                         free_canon_ace_list(file_ace_list);
1263                         free_canon_ace_list(dir_ace_list); 
1264                         file_ace_list = NULL;
1265                         dir_ace_list = NULL;
1266
1267                         DEBUG(3,("call_nt_transact_set_security_desc: chmod %s. perms = 0%o.\n",
1268                                 fsp->fsp_name, (unsigned int)perms ));
1269
1270                         if(conn->vfs_ops.chmod(conn,dos_to_unix(fsp->fsp_name, False), perms) == -1) {
1271                                 DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n",
1272                                                 fsp->fsp_name, (unsigned int)perms, strerror(errno) ));
1273                                 return False;
1274                         }
1275                 }
1276         }
1277
1278         free_canon_ace_list(file_ace_list);
1279         free_canon_ace_list(dir_ace_list); 
1280
1281         return True;
1282 }
1283 #undef OLD_NTDOMAIN