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