Split the one sys_acl_free call into sys_acl_free_TYPE calls, to allow
[samba.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 typedef struct canon_ace {
26         struct canon_ace *next, *prev;
27         SMB_ACL_TAG_T type;
28         mode_t perms;
29         DOM_SID sid;
30 } canon_ace;
31
32 /****************************************************************************
33  Function to create owner and group SIDs from a SMB_STRUCT_STAT.
34 ****************************************************************************/
35
36 static void create_file_sids(SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SID *pgroup_sid)
37 {
38         uid_to_sid( powner_sid, psbuf->st_uid );
39         gid_to_sid( pgroup_sid, psbuf->st_gid );
40 }
41
42 /****************************************************************************
43  Map canon_ace perms to NT.
44 ****************************************************************************/
45
46 static SEC_ACCESS map_canon_ace_perms(int *pacl_type, DOM_SID *powner_sid, canon_ace *ace)
47 {
48         SEC_ACCESS sa;
49         uint32 nt_mask = 0;
50
51         *pacl_type = SEC_ACE_TYPE_ACCESS_ALLOWED;
52
53         if((ace->perms & (S_IRWXU|S_IWUSR|S_IXUSR)) == (S_IRWXU|S_IWUSR|S_IXUSR)) {
54                         nt_mask = UNIX_ACCESS_RWX;
55         } else if((ace->perms & (S_IRWXU|S_IWUSR|S_IXUSR)) == 0) {
56                 /*
57                  * Here we differentiate between the owner and any other user.
58                  */
59                 if (sid_equal(powner_sid, &ace->sid)) {
60                         nt_mask = UNIX_ACCESS_NONE;
61                 } else {
62                         /* Not owner, no access. */
63                         nt_mask = 0;
64                 }
65         } else {
66                 nt_mask |= ((ace->perms & S_IRWXU) ? UNIX_ACCESS_R : 0 );
67                 nt_mask |= ((ace->perms & S_IWUSR) ? UNIX_ACCESS_W : 0 );
68                 nt_mask |= ((ace->perms & S_IXUSR) ? UNIX_ACCESS_X : 0 );
69         }
70
71         DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n",
72                         (unsigned int)ace->perms, (unsigned int)nt_mask ));
73
74         init_sec_access(&sa,nt_mask);
75         return sa;
76 }
77
78 /****************************************************************************
79  Map NT perms to UNIX.
80 ****************************************************************************/
81
82 #define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES)
83 #define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA|FILE_WRITE_ATTRIBUTES)
84 #define FILE_SPECIFIC_EXECUTE_BITS (FILE_EXECUTE)
85
86 static mode_t map_nt_perms( SEC_ACCESS sec_access, int type)
87 {
88   mode_t mode = 0;
89
90   switch(type) {
91   case S_IRUSR:
92     if(sec_access.mask & GENERIC_ALL_ACCESS)
93       mode = S_IRUSR|S_IWUSR|S_IXUSR;
94     else {
95       mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRUSR : 0;
96       mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWUSR : 0;
97       mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXUSR : 0;
98     }
99     break;
100   case S_IRGRP:
101     if(sec_access.mask & GENERIC_ALL_ACCESS)
102       mode = S_IRGRP|S_IWGRP|S_IXGRP;
103     else {
104       mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRGRP : 0;
105       mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWGRP : 0;
106       mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXGRP : 0;
107     }
108     break;
109   case S_IROTH:
110     if(sec_access.mask & GENERIC_ALL_ACCESS)
111       mode = S_IROTH|S_IWOTH|S_IXOTH;
112     else {
113       mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IROTH : 0;
114       mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWOTH : 0;
115       mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXOTH : 0;
116     }
117     break;
118   }
119
120   return mode;
121 }
122
123 /****************************************************************************
124  Unpack a SEC_DESC into a owner, group and set of UNIX permissions.
125 ****************************************************************************/
126
127 static BOOL unpack_nt_permissions(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, mode_t *pmode,
128                                   uint32 security_info_sent, SEC_DESC *psd, BOOL is_directory)
129 {
130   extern DOM_SID global_sid_World;
131   DOM_SID owner_sid;
132   DOM_SID grp_sid;
133   DOM_SID file_owner_sid;
134   DOM_SID file_grp_sid;
135   SEC_ACL *dacl = psd->dacl;
136   BOOL all_aces_are_inherit_only = (is_directory ? True : False);
137   int i;
138   enum SID_NAME_USE sid_type;
139
140   *pmode = 0;
141   *puser = (uid_t)-1;
142   *pgrp = (gid_t)-1;
143
144   if(security_info_sent == 0) {
145     DEBUG(0,("unpack_nt_permissions: no security info sent !\n"));
146     return False;
147   }
148
149   /*
150    * Windows 2000 sends the owner and group SIDs as the logged in
151    * user, not the connected user. But it still sends the file
152    * owner SIDs on an ACL set. So we need to check for the file
153    * owner and group SIDs as well as the owner SIDs. JRA.
154    */
155  
156   create_file_sids(psbuf, &file_owner_sid, &file_grp_sid);
157
158   /*
159    * Validate the owner and group SID's.
160    */
161
162   memset(&owner_sid, '\0', sizeof(owner_sid));
163   memset(&grp_sid, '\0', sizeof(grp_sid));
164
165   DEBUG(5,("unpack_nt_permissions: validating owner_sid.\n"));
166
167   /*
168    * Don't immediately fail if the owner sid cannot be validated.
169    * This may be a group chown only set.
170    */
171
172   if (security_info_sent & OWNER_SECURITY_INFORMATION) {
173         sid_copy(&owner_sid, psd->owner_sid);
174     if (!sid_to_uid( &owner_sid, puser, &sid_type))
175       DEBUG(3,("unpack_nt_permissions: unable to validate owner sid.\n"));
176   }
177
178   /*
179    * Don't immediately fail if the group sid cannot be validated.
180    * This may be an owner chown only set.
181    */
182
183   if (security_info_sent & GROUP_SECURITY_INFORMATION) {
184         sid_copy(&grp_sid, psd->grp_sid);
185     if (!sid_to_gid( &grp_sid, pgrp, &sid_type))
186       DEBUG(3,("unpack_nt_permissions: unable to validate group sid.\n"));
187   }
188
189   /*
190    * If no DACL then this is a chown only security descriptor.
191    */
192
193   if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !dacl) {
194     *pmode = 0;
195     return True;
196   }
197
198   /*
199    * Now go through the DACL and ensure that
200    * any owner/group sids match.
201    */
202
203   for(i = 0; i < dacl->num_aces; i++) {
204     DOM_SID ace_sid;
205     SEC_ACE *psa = &dacl->ace[i];
206
207     if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) &&
208        (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
209       DEBUG(3,("unpack_nt_permissions: unable to set anything but an ALLOW or DENY ACE.\n"));
210       return False;
211     }
212
213     /*
214      * Ignore or remove bits we don't care about on a directory ACE.
215      */
216
217     if(is_directory) {
218       if(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
219         DEBUG(3,("unpack_nt_permissions: ignoring inherit only ACE.\n"));
220         continue;
221       }
222
223       /*
224        * At least one of the ACE entries wasn't inherit only.
225        * Flag this so we know the returned mode is valid.
226        */
227
228       all_aces_are_inherit_only = False;
229     }
230
231     /*
232      * Windows 2000 sets these flags even on *file* ACE's. This is wrong
233      * but we can ignore them for now. Revisit this when we go to POSIX
234      * ACLs on directories.
235      */
236
237     psa->flags &= ~(SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT);
238
239     if(psa->flags != 0) {
240       DEBUG(1,("unpack_nt_permissions: unable to set ACE flags (%x).\n", 
241             (unsigned int)psa->flags));
242       return False;
243     }
244
245     /*
246      * The security mask may be UNIX_ACCESS_NONE which should map into
247      * no permissions (we overload the WRITE_OWNER bit for this) or it
248      * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
249      * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
250      */
251
252     psa->info.mask &= (GENERIC_ALL_ACCESS|GENERIC_EXECUTE_ACCESS|GENERIC_WRITE_ACCESS|
253                      GENERIC_READ_ACCESS|UNIX_ACCESS_NONE|FILE_ALL_ATTRIBUTES);
254
255     if(psa->info.mask != UNIX_ACCESS_NONE)
256       psa->info.mask &= ~UNIX_ACCESS_NONE;
257
258     sid_copy(&ace_sid, &psa->sid);
259
260     if(sid_equal(&ace_sid, &file_owner_sid)) {
261       /*
262        * Map the desired permissions into owner perms.
263        */
264
265       if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
266         *pmode |= map_nt_perms( psa->info, S_IRUSR);
267       else
268         *pmode &= ~(map_nt_perms( psa->info, S_IRUSR));
269
270     } else if( sid_equal(&ace_sid, &file_grp_sid)) {
271       /*
272        * Map the desired permissions into group perms.
273        */
274
275       if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
276         *pmode |= map_nt_perms( psa->info, S_IRGRP);
277       else
278         *pmode &= ~(map_nt_perms( psa->info, S_IRGRP));
279
280     } else if( sid_equal(&ace_sid, &global_sid_World)) {
281       /*
282        * Map the desired permissions into other perms.
283        */
284
285       if(psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
286         *pmode |= map_nt_perms( psa->info, S_IROTH);
287       else
288         *pmode &= ~(map_nt_perms( psa->info, S_IROTH));
289
290     } else {
291       DEBUG(0,("unpack_nt_permissions: unknown SID used in ACL.\n"));
292       return False;
293     }
294   }
295
296   if (is_directory && all_aces_are_inherit_only) {
297     /*
298      * Windows 2000 is doing one of these weird 'inherit acl'
299      * traverses to conserve NTFS ACL resources. Just pretend
300      * there was no DACL sent. JRA.
301      */
302
303     DEBUG(10,("unpack_nt_permissions: Win2k inherit acl traverse. Ignoring DACL.\n"));
304     free_sec_acl(&psd->dacl);
305   }
306
307   return True;
308 }
309
310 /****************************************************************************
311  Map generic UNIX permissions to POSIX ACL perms.
312 ****************************************************************************/
313
314 static mode_t convert_permset_to_mode_t(SMB_ACL_PERMSET_T permset)
315 {
316         mode_t ret = 0;
317
318         ret |= (sys_acl_get_perm(permset, SMB_ACL_READ) ? S_IRUSR : 0);
319         ret |= (sys_acl_get_perm(permset, SMB_ACL_WRITE) ? S_IWUSR : 0);
320         ret |= (sys_acl_get_perm(permset, SMB_ACL_EXECUTE) ? S_IXUSR : 0);
321
322         return ret;
323 }
324
325 /****************************************************************************
326  Map generic UNIX permissions to POSIX ACL perms.
327 ****************************************************************************/
328
329 static mode_t unix_perms_to_acl_perms(mode_t mode, int r_mask, int w_mask, int x_mask)
330 {
331         mode_t ret = 0;
332
333         if (mode & r_mask)
334                 ret |= S_IRUSR;
335         if (mode & w_mask)
336                 ret |= S_IWUSR;
337         if (mode & x_mask)
338                 ret |= S_IXUSR;
339
340         return ret;
341 }
342
343 /****************************************************************************
344  Count a linked list of canonical ACE entries.
345 ****************************************************************************/
346
347 static size_t count_canon_ace_list( canon_ace *list_head )
348 {
349         size_t count = 0;
350         canon_ace *ace;
351
352         for (ace = list_head; ace; ace = ace->next)
353                 count++;
354
355         return count;
356 }
357
358 /****************************************************************************
359  Free a linked list of canonical ACE entries.
360 ****************************************************************************/
361
362 static void free_canon_ace_list( canon_ace *list_head )
363 {
364         while (list_head) {
365                 canon_ace *old_head = list_head;
366                 DLIST_REMOVE(list_head, list_head);
367                 free(old_head);
368         }
369 }
370
371 /******************************************************************************
372  Fall back to the generic 3 element UNIX permissions.
373 ********************************************************************************/
374
375 static canon_ace *unix_canonicalise_acl(files_struct *fsp, SMB_STRUCT_STAT *psbuf,
376                                                                                 DOM_SID *powner, DOM_SID *pgroup)
377 {
378         extern DOM_SID global_sid_World;
379         canon_ace *list_head = NULL;
380         canon_ace *owner_ace = NULL;
381         canon_ace *group_ace = NULL;
382         canon_ace *other_ace = NULL;
383
384         /*
385          * Create 3 linked list entries.
386          */
387
388         if ((owner_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
389                 goto fail;
390
391         if ((group_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
392                 goto fail;
393
394         if ((other_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
395                 goto fail;
396
397         ZERO_STRUCTP(owner_ace);
398         ZERO_STRUCTP(group_ace);
399         ZERO_STRUCTP(other_ace);
400
401         owner_ace->type = SMB_ACL_USER_OBJ;
402         owner_ace->sid = *powner;
403
404         group_ace->type = SMB_ACL_GROUP_OBJ;
405         group_ace->sid = *pgroup;
406
407         other_ace->type = SMB_ACL_OTHER;
408         other_ace->sid = global_sid_World;
409
410         if (!fsp->is_directory) {
411                 owner_ace->perms = unix_perms_to_acl_perms(psbuf->st_mode, S_IRUSR, S_IWUSR, S_IXUSR);
412                 group_ace->perms = unix_perms_to_acl_perms(psbuf->st_mode, S_IRGRP, S_IWGRP, S_IXGRP);
413                 other_ace->perms = unix_perms_to_acl_perms(psbuf->st_mode, S_IROTH, S_IWOTH, S_IXOTH);
414         } else {
415                 mode_t mode = unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name);
416
417                 owner_ace->perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
418                 group_ace->perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
419                 other_ace->perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
420         }
421
422         DLIST_ADD(list_head, other_ace);
423         DLIST_ADD(list_head, group_ace);
424         DLIST_ADD(list_head, owner_ace);
425
426         return list_head;
427
428   fail:
429
430         safe_free(owner_ace);
431         safe_free(group_ace);
432         safe_free(other_ace);
433
434         return NULL;
435 }
436
437 /****************************************************************************
438  Create a linked list of canonical ACE entries. This is sorted so that DENY
439  entries are at the front of the list, as NT requires.
440 ****************************************************************************/
441
442 static canon_ace *canonicalise_acl( SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf)
443 {
444         extern DOM_SID global_sid_World;
445         mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR);
446         canon_ace *list_head = NULL;
447         canon_ace *ace = NULL;
448         canon_ace *next_ace = NULL;
449         int entry_id = SMB_ACL_FIRST_ENTRY;
450         SMB_ACL_ENTRY_T entry;
451
452         while ( sys_acl_get_entry(posix_acl, entry_id, &entry) == 1) {
453                 SMB_ACL_TAG_T tagtype;
454                 SMB_ACL_PERMSET_T permset;
455                 DOM_SID sid;
456
457                 /* get_next... */
458                 if (entry_id == SMB_ACL_FIRST_ENTRY)
459                         entry_id = SMB_ACL_NEXT_ENTRY;
460
461                 /* Is this a MASK entry ? */
462                 if (sys_acl_get_tag_type(entry, &tagtype) == -1)
463                         continue;
464
465                 if (sys_acl_get_permset(entry, &permset) == -1)
466                         continue;
467
468                 /* Decide which SID to use based on the ACL type. */
469                 switch(tagtype) {
470                         case SMB_ACL_USER_OBJ:
471                                 /* Get the SID from the owner. */
472                                 uid_to_sid( &sid, psbuf->st_uid );
473                                 break;
474                         case SMB_ACL_USER:
475                                 {
476                                         uid_t *puid = (uid_t *)sys_acl_get_qualifier(entry);
477                                         if (puid == NULL) {
478                                                 DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
479                                                 continue;
480                                         }
481                                         uid_to_sid( &sid, *puid);
482                                         break;
483                                 }
484                         case SMB_ACL_GROUP_OBJ:
485                                 /* Get the SID from the owning group. */
486                                 gid_to_sid( &sid, psbuf->st_gid );
487                                 break;
488                         case SMB_ACL_GROUP:
489                                 {
490                                         gid_t *pgid = (gid_t *)sys_acl_get_qualifier(entry);
491                                         if (pgid == NULL) {
492                                                 DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
493                                                 continue;
494                                         }
495                                         gid_to_sid( &sid, *pgid);
496                                         break;
497                                 }
498                         case SMB_ACL_MASK:
499                                 acl_mask = convert_permset_to_mode_t(permset);
500                                 continue; /* Don't count the mask as an entry. */
501                         case SMB_ACL_OTHER:
502                                 /* Use the Everyone SID */
503                                 sid = global_sid_World;
504                                 break;
505                         default:
506                                 DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype));
507                                 continue;
508                 }
509
510                 /*
511                  * Add this entry to the list.
512                  */
513
514                 if ((ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
515                         goto fail;
516
517                 ZERO_STRUCTP(ace);
518                 ace->type = tagtype;
519                 ace->perms = convert_permset_to_mode_t(permset);
520                 ace->sid = sid;
521                  
522                 DLIST_ADD(list_head, ace);
523         }
524
525         /*
526          * Now go through the list, masking the permissions with the
527          * acl_mask. If the permissions are 0 it should be listed
528          * first.
529          */
530
531         for ( ace = list_head; ace; ace = next_ace) {
532                 next_ace = ace->next;
533
534                 /* Masks are only applied to entries other than USER_OBJ and OTHER. */
535                 if (ace->type != SMB_ACL_OTHER && ace->type != SMB_ACL_USER_OBJ)
536                         ace->perms &= acl_mask;
537
538                 if (ace->perms == 0)
539                         DLIST_PROMOTE(list_head, ace);
540         }
541
542         if( DEBUGLVL( 10 ) ) {
543                 char *acl_text = sys_acl_to_text( posix_acl, NULL);
544
545                 dbgtext("canonicalize_acl: processed acl %s\n", acl_text == NULL ? "NULL" : acl_text );
546                 if (acl_text)
547                         sys_acl_free_text(acl_text);
548         }
549
550         return list_head;
551
552   fail:
553
554         free_canon_ace_list(list_head);
555         return NULL;
556 }
557
558 /****************************************************************************
559  Reply to query a security descriptor from an fsp. If it succeeds it allocates
560  the space for the return elements and returns the size needed to return the
561  security descriptor. This should be the only external function needed for
562  the UNIX style get ACL.
563 ****************************************************************************/
564
565 size_t get_nt_acl(files_struct *fsp, SEC_DESC **ppdesc)
566 {
567         SMB_STRUCT_STAT sbuf;
568         SEC_ACE *nt_ace_list;
569         DOM_SID owner_sid;
570         DOM_SID group_sid;
571         size_t sd_size = 0;
572         SEC_ACL *psa = NULL;
573         size_t num_acls = 0;
574         size_t num_dir_acls = 0;
575         size_t num_aces = 0;
576         SMB_ACL_T posix_acl = NULL;
577         SMB_ACL_T dir_acl = NULL;
578         canon_ace *file_ace = NULL;
579         canon_ace *dir_ace = NULL;
580  
581         *ppdesc = NULL;
582
583         if(fsp->is_directory || fsp->fd == -1) {
584
585                 /* Get the stat struct for the owner info. */
586                 if(vfs_stat(fsp->conn,fsp->fsp_name, &sbuf) != 0) {
587                         return 0;
588                 }
589                 /*
590                  * Get the ACL from the path.
591                  */
592
593                 posix_acl = sys_acl_get_file( dos_to_unix(fsp->fsp_name, False), SMB_ACL_TYPE_ACCESS);
594
595                 /*
596                  * If it's a directory get the default POSIX ACL.
597                  */
598
599                 if(fsp->is_directory)
600                         dir_acl = sys_acl_get_file( dos_to_unix(fsp->fsp_name, False), SMB_ACL_TYPE_DEFAULT);
601
602         } else {
603
604                 /* Get the stat struct for the owner info. */
605                 if(vfs_fstat(fsp,fsp->fd,&sbuf) != 0) {
606                         return 0;
607                 }
608                 /*
609                  * Get the ACL from the fd.
610                  */
611                 posix_acl = sys_acl_get_fd(fsp->fd);
612         }
613
614         DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n",
615                         posix_acl ? "present" :  "absent",
616                         dir_acl ? "present" :  "absent" ));
617
618         /*
619          * Get the owner, group and world SIDs.
620          */
621
622         create_file_sids(&sbuf, &owner_sid, &group_sid);
623
624         /* Create the canon_ace lists. */
625         if (posix_acl)
626                 file_ace = canonicalise_acl( posix_acl, &sbuf);
627         else
628                 file_ace = unix_canonicalise_acl(fsp, &sbuf, &owner_sid, &group_sid);
629
630         num_acls = count_canon_ace_list(file_ace);
631
632         if (fsp->is_directory) { 
633                 if (dir_ace)
634                         dir_ace = canonicalise_acl( dir_acl, &sbuf);
635                 else
636                         dir_ace = unix_canonicalise_acl(fsp, &sbuf, &owner_sid, &group_sid);
637
638                 num_dir_acls = count_canon_ace_list(dir_ace);
639         }
640
641         /* Allocate the ace list. */
642         if ((nt_ace_list = (SEC_ACE *)malloc((num_acls + num_dir_acls)* sizeof(SEC_ACE))) == NULL) {
643                 DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
644                 goto done;
645         }
646
647         memset(nt_ace_list, '\0', (num_acls + num_dir_acls) * sizeof(SEC_ACE) );
648
649         /*
650          * Create the NT ACE list from the canonical ace lists.
651          */
652
653         {
654                 canon_ace *ace;
655                 int nt_acl_type;
656                 int i;
657
658                 ace = file_ace;
659
660                 for (i = 0; i < num_acls; i++, ace = ace->next) {
661                         SEC_ACCESS acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
662                         init_sec_ace(&nt_ace_list[num_aces++], &ace->sid, nt_acl_type, acc, 0);
663                 }
664
665                 ace = dir_ace;
666
667                 for (i = 0; i < num_dir_acls; i++, ace = ace->next) {
668                         SEC_ACCESS acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
669                         init_sec_ace(&nt_ace_list[num_aces++], &ace->sid, nt_acl_type, acc, 
670                                         SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_INHERIT_ONLY);
671                 }
672         }
673
674         if (num_acls) {
675                 if((psa = make_sec_acl( ACL_REVISION, num_aces, nt_ace_list)) == NULL) {
676                         DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
677                         goto done;
678                 }
679         }
680
681         *ppdesc = make_standard_sec_desc( &owner_sid, &group_sid, psa, &sd_size);
682
683         if(!*ppdesc) {
684                 DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
685                 sd_size = 0;
686         }
687
688   done:
689
690         if (posix_acl)  
691                 sys_acl_free_acl(posix_acl);
692         if (dir_acl)
693                 sys_acl_free_acl(dir_acl);
694         if (file_ace)
695                 free_canon_ace_list(file_ace);
696         if (dir_ace)
697                 free_canon_ace_list(dir_ace);
698         if (nt_ace_list)
699                 free(nt_ace_list);
700         if (psa)
701                 free_sec_acl(&psa);
702
703         return sd_size;
704 }
705
706 /****************************************************************************
707  Reply to set a security descriptor on an fsp. security_info_sent is the
708  description of the following NT ACL.
709  This should be the only external function needed for the UNIX style set ACL.
710 ****************************************************************************/
711
712 BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
713 {
714   connection_struct *conn = fsp->conn;
715   uid_t user = (uid_t)-1;
716   gid_t grp = (gid_t)-1;
717   mode_t perms = 0;
718   SMB_STRUCT_STAT sbuf;  
719   BOOL got_dacl = False;
720
721   /*
722    * Get the current state of the file.
723    */
724
725   if(fsp->is_directory || fsp->fd == -1) {
726     if(vfs_stat(fsp->conn,fsp->fsp_name, &sbuf) != 0)
727       return False;
728   } else {
729     if(conn->vfs_ops.fstat(fsp,fsp->fd,&sbuf) != 0)
730       return False;
731   }
732
733   /*
734    * Unpack the user/group/world id's and permissions.
735    */
736
737   if (!unpack_nt_permissions( &sbuf, &user, &grp, &perms, security_info_sent, psd, fsp->is_directory))
738     return False;
739
740   if (psd->dacl != NULL)
741     got_dacl = True;
742
743   /*
744    * Do we need to chown ?
745    */
746
747   if((user != (uid_t)-1 || grp != (uid_t)-1) && (sbuf.st_uid != user || sbuf.st_gid != grp)) {
748
749     DEBUG(3,("call_nt_transact_set_security_desc: chown %s. uid = %u, gid = %u.\n",
750           fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
751
752     if(vfs_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
753       DEBUG(3,("call_nt_transact_set_security_desc: chown %s, %u, %u failed. Error = %s.\n",
754             fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
755       return False;
756     }
757
758     /*
759      * Recheck the current state of the file, which may have changed.
760      * (suid/sgid bits, for instance)
761      */
762
763     if(fsp->is_directory) {
764       if(vfs_stat(fsp->conn, fsp->fsp_name, &sbuf) != 0) {
765         return False;
766       }
767     } else {
768
769       int ret;
770     
771       if(fsp->fd == -1)
772         ret = vfs_stat(fsp->conn, fsp->fsp_name, &sbuf);
773       else
774         ret = conn->vfs_ops.fstat(fsp,fsp->fd,&sbuf);
775   
776       if(ret != 0)
777         return False;
778     }
779   }
780
781   /*
782    * Only change security if we got a DACL.
783    */
784
785   if((security_info_sent & DACL_SECURITY_INFORMATION) && got_dacl) {
786
787     /*
788      * Check to see if we need to change anything.
789      * Enforce limits on modified bits *only*. Don't enforce masks
790          * on bits not changed by the user.
791      */
792
793     if(fsp->is_directory) {
794
795       perms &= (lp_dir_security_mask(SNUM(conn)) | sbuf.st_mode);
796       perms |= (lp_force_dir_security_mode(SNUM(conn)) & ( perms ^ sbuf.st_mode ));
797
798     } else {
799
800       perms &= (lp_security_mask(SNUM(conn)) | sbuf.st_mode); 
801       perms |= (lp_force_security_mode(SNUM(conn)) & ( perms ^ sbuf.st_mode ));
802
803     }
804
805     /*
806      * Preserve special bits.
807      */
808
809     perms |= (sbuf.st_mode & ~0777);
810
811     /*
812      * Do we need to chmod ?
813      */
814
815     if(sbuf.st_mode != perms) {
816
817       DEBUG(3,("call_nt_transact_set_security_desc: chmod %s. perms = 0%o.\n",
818             fsp->fsp_name, (unsigned int)perms ));
819
820       if(conn->vfs_ops.chmod(conn,dos_to_unix(fsp->fsp_name, False), perms) == -1) {
821         DEBUG(3,("call_nt_transact_set_security_desc: chmod %s, 0%o failed. Error = %s.\n",
822               fsp->fsp_name, (unsigned int)perms, strerror(errno) ));
823         return False;
824       }
825     }
826   }
827
828   return True;
829 }
830 #undef OLD_NTDOMAIN
831
832
833
834
835