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