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