Fixed the merge_default_aces() code to work correctly with inheritance.
[vlendec/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    Copyright (C) Andreas Gruenbacher 2002.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 /****************************************************************************
25  Data structures representing the internal ACE format.
26 ****************************************************************************/
27
28 enum ace_owner {UID_ACE, GID_ACE, WORLD_ACE};
29 enum ace_attribute {ALLOW_ACE, DENY_ACE}; /* Used for incoming NT ACLS. */
30
31 typedef union posix_id {
32                 uid_t uid;
33                 gid_t gid;
34                 int world;
35 } posix_id;
36
37 typedef struct canon_ace {
38         struct canon_ace *next, *prev;
39         SMB_ACL_TAG_T type;
40         mode_t perms; /* Only use S_I(R|W|X)USR mode bits here. */
41         DOM_SID trustee;
42         enum ace_owner owner_type;
43         enum ace_attribute attr;
44         posix_id unix_ug; 
45         BOOL inherited;
46 } canon_ace;
47
48 #define ALL_ACE_PERMS (S_IRUSR|S_IWUSR|S_IXUSR)
49
50 /*
51  * EA format of user.SAMBA_PAI (Samba_Posix_Acl_Interitance)
52  * attribute on disk.
53  *
54  * |  1   |  1   |   2         |         2           |  .... 
55  * +------+------+-------------+---------------------+-------------+--------------------+
56  * | vers | flag | num_entries | num_default_entries | ..entries.. | default_entries... |
57  * +------+------+-------------+---------------------+-------------+--------------------+
58  */
59
60 #define SAMBA_POSIX_INHERITANCE_EA_NAME "user.SAMBA_PAI"
61
62 #define PAI_VERSION_OFFSET      0
63 #define PAI_FLAG_OFFSET         1
64 #define PAI_NUM_ENTRIES_OFFSET  2
65 #define PAI_NUM_DEFAULT_ENTRIES_OFFSET  4
66 #define PAI_ENTRIES_BASE        6
67
68 #define PAI_VERSION             1
69 #define PAI_ACL_FLAG_PROTECTED  0x1
70 #define PAI_ENTRY_LENGTH        5
71
72 /*
73  * In memory format of user.SAMBA_PAI attribute.
74  */
75
76 struct pai_entry {
77         struct pai_entry *next, *prev;
78         enum ace_owner owner_type;
79         posix_id unix_ug; 
80 };
81         
82 struct pai_val {
83         BOOL protected;
84         unsigned int num_entries;
85         struct pai_entry *entry_list;
86         unsigned int num_def_entries;
87         struct pai_entry *def_entry_list;
88 };
89
90 /************************************************************************
91  Return a uint32 of the pai_entry principal.
92 ************************************************************************/
93
94 static uint32 get_pai_entry_val(struct pai_entry *paie)
95 {
96         switch (paie->owner_type) {
97                 case UID_ACE:
98                         DEBUG(10,("get_pai_entry_val: uid = %u\n", (unsigned int)paie->unix_ug.uid ));
99                         return (uint32)paie->unix_ug.uid;
100                 case GID_ACE:
101                         DEBUG(10,("get_pai_entry_val: gid = %u\n", (unsigned int)paie->unix_ug.gid ));
102                         return (uint32)paie->unix_ug.gid;
103                 case WORLD_ACE:
104                 default:
105                         DEBUG(10,("get_pai_entry_val: world ace\n"));
106                         return (uint32)-1;
107         }
108 }
109
110 /************************************************************************
111  Return a uint32 of the entry principal.
112 ************************************************************************/
113
114 static uint32 get_entry_val(canon_ace *ace_entry)
115 {
116         switch (ace_entry->owner_type) {
117                 case UID_ACE:
118                         DEBUG(10,("get_entry_val: uid = %u\n", (unsigned int)ace_entry->unix_ug.uid ));
119                         return (uint32)ace_entry->unix_ug.uid;
120                 case GID_ACE:
121                         DEBUG(10,("get_entry_val: gid = %u\n", (unsigned int)ace_entry->unix_ug.gid ));
122                         return (uint32)ace_entry->unix_ug.gid;
123                 case WORLD_ACE:
124                 default:
125                         DEBUG(10,("get_entry_val: world ace\n"));
126                         return (uint32)-1;
127         }
128 }
129
130 /************************************************************************
131  Count the inherited entries.
132 ************************************************************************/
133
134 static unsigned int num_inherited_entries(canon_ace *ace_list)
135 {
136         unsigned int num_entries = 0;
137
138         for (; ace_list; ace_list = ace_list->next)
139                 if (ace_list->inherited)
140                         num_entries++;
141         return num_entries;
142 }
143
144 /************************************************************************
145  Create the on-disk format. Caller must free.
146 ************************************************************************/
147
148 static char *create_pai_buf(canon_ace *file_ace_list, canon_ace *dir_ace_list, BOOL protected, size_t *store_size)
149 {
150         char *pai_buf = NULL;
151         canon_ace *ace_list = NULL;
152         char *entry_offset = NULL;
153         unsigned int num_entries = 0;
154         unsigned int num_def_entries = 0;
155
156         for (ace_list = file_ace_list; ace_list; ace_list = ace_list->next)
157                 if (ace_list->inherited)
158                         num_entries++;
159
160         for (ace_list = dir_ace_list; ace_list; ace_list = ace_list->next)
161                 if (ace_list->inherited)
162                         num_def_entries++;
163
164         *store_size = PAI_ENTRIES_BASE + ((num_entries + num_def_entries)*PAI_ENTRY_LENGTH);
165
166         pai_buf = malloc(*store_size);
167         if (!pai_buf) {
168                 return NULL;
169         }
170
171         /* Set up the header. */
172         memset(pai_buf, '\0', PAI_ENTRIES_BASE);
173         SCVAL(pai_buf,PAI_VERSION_OFFSET,PAI_VERSION);
174         SCVAL(pai_buf,PAI_FLAG_OFFSET,(protected ? PAI_ACL_FLAG_PROTECTED : 0));
175         SSVAL(pai_buf,PAI_NUM_ENTRIES_OFFSET,num_entries);
176         SSVAL(pai_buf,PAI_NUM_DEFAULT_ENTRIES_OFFSET,num_def_entries);
177
178         entry_offset = pai_buf + PAI_ENTRIES_BASE;
179
180         for (ace_list = dir_ace_list; ace_list; ace_list = ace_list->next) {
181                 if (ace_list->inherited) {
182                         uint8 type_val = (unsigned char)ace_list->owner_type;
183                         uint32 entry_val = get_entry_val(ace_list);
184
185                         SCVAL(entry_offset,0,type_val);
186                         SIVAL(entry_offset,1,entry_val);
187                         entry_offset += PAI_ENTRY_LENGTH;
188                 }
189         }
190
191         for (ace_list = file_ace_list; ace_list; ace_list = ace_list->next) {
192                 if (ace_list->inherited) {
193                         uint8 type_val = (unsigned char)ace_list->owner_type;
194                         uint32 entry_val = get_entry_val(ace_list);
195
196                         SCVAL(entry_offset,0,type_val);
197                         SIVAL(entry_offset,1,entry_val);
198                         entry_offset += PAI_ENTRY_LENGTH;
199                 }
200         }
201
202         return pai_buf;
203 }
204
205 /************************************************************************
206  Store the user.SAMBA_PAI attribute on disk.
207 ************************************************************************/
208
209 static void store_inheritance_attributes(files_struct *fsp, canon_ace *file_ace_list,
210                                         canon_ace *dir_ace_list, BOOL protected)
211 {
212         int ret;
213         size_t store_size;
214         char *pai_buf;
215
216         if (!lp_map_acl_inherit(SNUM(fsp->conn)))
217                 return;
218
219         /*
220          * Don't store if this ACL isn't protected and
221          * none of the entries in it are marked as inherited.
222          */
223
224         if (!protected && num_inherited_entries(file_ace_list) == 0 && num_inherited_entries(dir_ace_list) == 0) {
225                 /* Instead just remove the attribute if it exists. */
226                 if (fsp->fd != -1)
227                         SMB_VFS_FREMOVEXATTR(fsp, fsp->fd, SAMBA_POSIX_INHERITANCE_EA_NAME);
228                 else
229                         SMB_VFS_REMOVEXATTR(fsp->conn, fsp->fsp_name, SAMBA_POSIX_INHERITANCE_EA_NAME);
230                 return;
231         }
232
233         pai_buf = create_pai_buf(file_ace_list, dir_ace_list, protected, &store_size);
234
235         if (fsp->fd != -1)
236                 ret = SMB_VFS_FSETXATTR(fsp, fsp->fd, SAMBA_POSIX_INHERITANCE_EA_NAME,
237                                 pai_buf, store_size, 0);
238         else
239                 ret = SMB_VFS_SETXATTR(fsp->conn,fsp->fsp_name, SAMBA_POSIX_INHERITANCE_EA_NAME,
240                                 pai_buf, store_size, 0);
241
242         SAFE_FREE(pai_buf);
243
244         DEBUG(10,("store_inheritance_attribute:%s for file %s\n", protected ? " (protected)" : "", fsp->fsp_name));
245         if (ret == -1 && errno != ENOSYS)
246                 DEBUG(1,("store_inheritance_attribute: Error %s\n", strerror(errno) ));
247 }
248
249 /************************************************************************
250  Delete the in memory inheritance info.
251 ************************************************************************/
252
253 static void free_inherited_info(struct pai_val *pal)
254 {
255         if (pal) {
256                 struct pai_entry *paie, *paie_next;
257                 for (paie = pal->entry_list; paie; paie = paie_next) {
258                         paie_next = paie->next;
259                         SAFE_FREE(paie);
260                 }
261                 for (paie = pal->def_entry_list; paie; paie = paie_next) {
262                         paie_next = paie->next;
263                         SAFE_FREE(paie);
264                 }
265                 SAFE_FREE(pal);
266         }
267 }
268
269 /************************************************************************
270  Was this ACL protected ?
271 ************************************************************************/
272
273 static BOOL get_protected_flag(struct pai_val *pal)
274 {
275         if (!pal)
276                 return False;
277         return pal->protected;
278 }
279
280 /************************************************************************
281  Was this ACE inherited ?
282 ************************************************************************/
283
284 static BOOL get_inherited_flag(struct pai_val *pal, canon_ace *ace_entry, BOOL default_ace)
285 {
286         struct pai_entry *paie;
287
288         if (!pal)
289                 return False;
290
291         /* If the entry exists it is inherited. */
292         for (paie = (default_ace ? pal->def_entry_list : pal->entry_list); paie; paie = paie->next) {
293                 if (ace_entry->owner_type == paie->owner_type &&
294                                 get_entry_val(ace_entry) == get_pai_entry_val(paie))
295                         return True;
296         }
297         return False;
298 }
299
300 /************************************************************************
301  Ensure an attribute just read is valid.
302 ************************************************************************/
303
304 static BOOL check_pai_ok(char *pai_buf, size_t pai_buf_data_size)
305 {
306         uint16 num_entries;
307         uint16 num_def_entries;
308
309         if (pai_buf_data_size < PAI_ENTRIES_BASE) {
310                 /* Corrupted - too small. */
311                 return False;
312         }
313
314         if (CVAL(pai_buf,PAI_VERSION_OFFSET) != PAI_VERSION)
315                 return False;
316
317         num_entries = SVAL(pai_buf,PAI_NUM_ENTRIES_OFFSET);
318         num_def_entries = SVAL(pai_buf,PAI_NUM_DEFAULT_ENTRIES_OFFSET);
319
320         /* Check the entry lists match. */
321         /* Each entry is 5 bytes (type plus 4 bytes of uid or gid). */
322
323         if (((num_entries + num_def_entries)*PAI_ENTRY_LENGTH) + PAI_ENTRIES_BASE != pai_buf_data_size)
324                 return False;
325
326         return True;
327 }
328
329
330 /************************************************************************
331  Convert to in-memory format.
332 ************************************************************************/
333
334 static struct pai_val *create_pai_val(char *buf, size_t size)
335 {
336         char *entry_offset;
337         struct pai_val *paiv = NULL;
338         int i;
339
340         if (!check_pai_ok(buf, size))
341                 return NULL;
342
343         paiv = malloc(sizeof(struct pai_val));
344         if (!paiv)
345                 return NULL;
346
347         memset(paiv, '\0', sizeof(struct pai_val));
348
349         paiv->protected = (CVAL(buf,PAI_FLAG_OFFSET) == PAI_ACL_FLAG_PROTECTED);
350
351         paiv->num_entries = SVAL(buf,PAI_NUM_ENTRIES_OFFSET);
352         paiv->num_def_entries = SVAL(buf,PAI_NUM_DEFAULT_ENTRIES_OFFSET);
353
354         entry_offset = buf + PAI_ENTRIES_BASE;
355
356         DEBUG(10,("create_pai_val:%s num_entries = %u, num_def_entries = %u\n",
357                         paiv->protected ? " (protected)" : "", paiv->num_entries, paiv->num_def_entries ));
358
359         for (i = 0; i < paiv->num_entries; i++) {
360                 struct pai_entry *paie;
361
362                 paie = malloc(sizeof(struct pai_entry));
363                 if (!paie) {
364                         free_inherited_info(paiv);
365                         return NULL;
366                 }
367
368                 paie->owner_type = (enum ace_owner)CVAL(entry_offset,0);
369                 switch( paie->owner_type) {
370                         case UID_ACE:
371                                 paie->unix_ug.uid = (uid_t)IVAL(entry_offset,1);
372                                 DEBUG(10,("create_pai_val: uid = %u\n", (unsigned int)paie->unix_ug.uid ));
373                                 break;
374                         case GID_ACE:
375                                 paie->unix_ug.gid = (gid_t)IVAL(entry_offset,1);
376                                 DEBUG(10,("create_pai_val: gid = %u\n", (unsigned int)paie->unix_ug.gid ));
377                                 break;
378                         case WORLD_ACE:
379                                 paie->unix_ug.world = -1;
380                                 DEBUG(10,("create_pai_val: world ace\n"));
381                                 break;
382                         default:
383                                 free_inherited_info(paiv);
384                                 return NULL;
385                 }
386                 entry_offset += PAI_ENTRY_LENGTH;
387                 DLIST_ADD(paiv->entry_list, paie);
388         }
389
390         for (i = 0; i < paiv->num_def_entries; i++) {
391                 struct pai_entry *paie;
392
393                 paie = malloc(sizeof(struct pai_entry));
394                 if (!paie) {
395                         free_inherited_info(paiv);
396                         return NULL;
397                 }
398
399                 paie->owner_type = (enum ace_owner)CVAL(entry_offset,0);
400                 switch( paie->owner_type) {
401                         case UID_ACE:
402                                 paie->unix_ug.uid = (uid_t)IVAL(entry_offset,1);
403                                 DEBUG(10,("create_pai_val: (def) uid = %u\n", (unsigned int)paie->unix_ug.uid ));
404                                 break;
405                         case GID_ACE:
406                                 paie->unix_ug.gid = (gid_t)IVAL(entry_offset,1);
407                                 DEBUG(10,("create_pai_val: (def) gid = %u\n", (unsigned int)paie->unix_ug.gid ));
408                                 break;
409                         case WORLD_ACE:
410                                 paie->unix_ug.world = -1;
411                                 DEBUG(10,("create_pai_val: (def) world ace\n"));
412                                 break;
413                         default:
414                                 free_inherited_info(paiv);
415                                 return NULL;
416                 }
417                 entry_offset += PAI_ENTRY_LENGTH;
418                 DLIST_ADD(paiv->def_entry_list, paie);
419         }
420
421         return paiv;
422 }
423
424 /************************************************************************
425  Load the user.SAMBA_PAI attribute.
426 ************************************************************************/
427
428 static struct pai_val *load_inherited_info(files_struct *fsp)
429 {
430         char *pai_buf;
431         size_t pai_buf_size = 1024;
432         struct pai_val *paiv = NULL;
433         ssize_t ret;
434
435         if (!lp_map_acl_inherit(SNUM(fsp->conn)))
436                 return NULL;
437
438         if ((pai_buf = malloc(pai_buf_size)) == NULL)
439                 return NULL;
440
441         do {
442                 if (fsp->fd != -1)
443                         ret = SMB_VFS_FGETXATTR(fsp, fsp->fd, SAMBA_POSIX_INHERITANCE_EA_NAME,
444                                         pai_buf, pai_buf_size);
445                 else
446                         ret = SMB_VFS_GETXATTR(fsp->conn,fsp->fsp_name,SAMBA_POSIX_INHERITANCE_EA_NAME,
447                                         pai_buf, pai_buf_size);
448
449                 if (ret == -1) {
450                         if (errno != ERANGE) {
451                                 break;
452                         }
453                         /* Buffer too small - enlarge it. */
454                         pai_buf_size *= 2;
455                         SAFE_FREE(pai_buf);
456                         if ((pai_buf = malloc(pai_buf_size)) == NULL)
457                                 return NULL;
458                 }
459         } while (ret == -1);
460
461         DEBUG(10,("load_inherited_info: ret = %d for file %s\n", ret, fsp->fsp_name));
462
463         if (ret == -1) {
464                 /* No attribute or not supported. */
465 #if defined(ENOATTR)
466                 if (errno != ENOATTR)
467                         DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) ));
468 #else
469                 if (errno != ENOSYS)
470                         DEBUG(10,("load_inherited_info: Error %s\n", strerror(errno) ));
471 #endif
472                 SAFE_FREE(pai_buf);
473                 return NULL;
474         }
475
476         paiv = create_pai_val(pai_buf, ret);
477
478         if (paiv && paiv->protected)
479                 DEBUG(10,("load_inherited_info: ACL is protected for file %s\n", fsp->fsp_name));
480
481         SAFE_FREE(pai_buf);
482         return paiv;
483 }
484
485 /****************************************************************************
486  Functions to manipulate the internal ACE format.
487 ****************************************************************************/
488
489 /****************************************************************************
490  Count a linked list of canonical ACE entries.
491 ****************************************************************************/
492
493 static size_t count_canon_ace_list( canon_ace *list_head )
494 {
495         size_t count = 0;
496         canon_ace *ace;
497
498         for (ace = list_head; ace; ace = ace->next)
499                 count++;
500
501         return count;
502 }
503
504 /****************************************************************************
505  Free a linked list of canonical ACE entries.
506 ****************************************************************************/
507
508 static void free_canon_ace_list( canon_ace *list_head )
509 {
510         while (list_head) {
511                 canon_ace *old_head = list_head;
512                 DLIST_REMOVE(list_head, list_head);
513                 SAFE_FREE(old_head);
514         }
515 }
516
517 /****************************************************************************
518  Function to duplicate a canon_ace entry.
519 ****************************************************************************/
520
521 static canon_ace *dup_canon_ace( canon_ace *src_ace)
522 {
523         canon_ace *dst_ace = (canon_ace *)malloc(sizeof(canon_ace));
524
525         if (dst_ace == NULL)
526                 return NULL;
527
528         *dst_ace = *src_ace;
529         dst_ace->prev = dst_ace->next = NULL;
530         return dst_ace;
531 }
532
533 /****************************************************************************
534  Print out a canon ace.
535 ****************************************************************************/
536
537 static void print_canon_ace(canon_ace *pace, int num)
538 {
539         fstring str;
540
541         dbgtext( "canon_ace index %d. Type = %s ", num, pace->attr == ALLOW_ACE ? "allow" : "deny" );
542         dbgtext( "SID = %s ", sid_to_string( str, &pace->trustee));
543         if (pace->owner_type == UID_ACE) {
544                 const char *u_name = uidtoname(pace->unix_ug.uid);
545                 dbgtext( "uid %u (%s) %s", (unsigned int)pace->unix_ug.uid, u_name, pace->inherited ? "(inherited) " : "");
546         } else if (pace->owner_type == GID_ACE) {
547                 char *g_name = gidtoname(pace->unix_ug.gid);
548                 dbgtext( "gid %u (%s) ", (unsigned int)pace->unix_ug.gid, g_name);
549         } else
550                 dbgtext( "other ");
551         switch (pace->type) {
552                 case SMB_ACL_USER:
553                         dbgtext( "SMB_ACL_USER ");
554                         break;
555                 case SMB_ACL_USER_OBJ:
556                         dbgtext( "SMB_ACL_USER_OBJ ");
557                         break;
558                 case SMB_ACL_GROUP:
559                         dbgtext( "SMB_ACL_GROUP ");
560                         break;
561                 case SMB_ACL_GROUP_OBJ:
562                         dbgtext( "SMB_ACL_GROUP_OBJ ");
563                         break;
564                 case SMB_ACL_OTHER:
565                         dbgtext( "SMB_ACL_OTHER ");
566                         break;
567         }
568         dbgtext( "perms ");
569         dbgtext( "%c", pace->perms & S_IRUSR ? 'r' : '-');
570         dbgtext( "%c", pace->perms & S_IWUSR ? 'w' : '-');
571         dbgtext( "%c\n", pace->perms & S_IXUSR ? 'x' : '-');
572 }
573
574 /****************************************************************************
575  Print out a canon ace list.
576 ****************************************************************************/
577
578 static void print_canon_ace_list(const char *name, canon_ace *ace_list)
579 {
580         int count = 0;
581
582         if( DEBUGLVL( 10 )) {
583                 dbgtext( "print_canon_ace_list: %s\n", name );
584                 for (;ace_list; ace_list = ace_list->next, count++)
585                         print_canon_ace(ace_list, count );
586         }
587 }
588
589 /****************************************************************************
590  Map POSIX ACL perms to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
591 ****************************************************************************/
592
593 static mode_t convert_permset_to_mode_t(connection_struct *conn, SMB_ACL_PERMSET_T permset)
594 {
595         mode_t ret = 0;
596
597         ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRUSR : 0);
598         ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWUSR : 0);
599         ret |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXUSR : 0);
600
601         return ret;
602 }
603
604 /****************************************************************************
605  Map generic UNIX permissions to canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits).
606 ****************************************************************************/
607
608 static mode_t unix_perms_to_acl_perms(mode_t mode, int r_mask, int w_mask, int x_mask)
609 {
610         mode_t ret = 0;
611
612         if (mode & r_mask)
613                 ret |= S_IRUSR;
614         if (mode & w_mask)
615                 ret |= S_IWUSR;
616         if (mode & x_mask)
617                 ret |= S_IXUSR;
618
619         return ret;
620 }
621
622 /****************************************************************************
623  Map canon_ace permissions (a mode_t containing only S_(R|W|X)USR bits) to
624  an SMB_ACL_PERMSET_T.
625 ****************************************************************************/
626
627 static int map_acl_perms_to_permset(connection_struct *conn, mode_t mode, SMB_ACL_PERMSET_T *p_permset)
628 {
629         if (SMB_VFS_SYS_ACL_CLEAR_PERMS(conn, *p_permset) ==  -1)
630                 return -1;
631         if (mode & S_IRUSR) {
632                 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_READ) == -1)
633                         return -1;
634         }
635         if (mode & S_IWUSR) {
636                 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_WRITE) == -1)
637                         return -1;
638         }
639         if (mode & S_IXUSR) {
640                 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_EXECUTE) == -1)
641                         return -1;
642         }
643         return 0;
644 }
645 /****************************************************************************
646  Function to create owner and group SIDs from a SMB_STRUCT_STAT.
647 ****************************************************************************/
648
649 static void create_file_sids(SMB_STRUCT_STAT *psbuf, DOM_SID *powner_sid, DOM_SID *pgroup_sid)
650 {
651         uid_to_sid( powner_sid, psbuf->st_uid );
652         gid_to_sid( pgroup_sid, psbuf->st_gid );
653 }
654
655 /****************************************************************************
656  Merge aces with a common sid - if both are allow or deny, OR the permissions together and
657  delete the second one. If the first is deny, mask the permissions off and delete the allow
658  if the permissions become zero, delete the deny if the permissions are non zero.
659 ****************************************************************************/
660
661 static void merge_aces( canon_ace **pp_list_head )
662 {
663         canon_ace *list_head = *pp_list_head;
664         canon_ace *curr_ace_outer;
665         canon_ace *curr_ace_outer_next;
666
667         /*
668          * First, merge allow entries with identical SIDs, and deny entries
669          * with identical SIDs.
670          */
671
672         for (curr_ace_outer = list_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
673                 canon_ace *curr_ace;
674                 canon_ace *curr_ace_next;
675
676                 curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
677
678                 for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
679
680                         curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
681
682                         if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
683                                 (curr_ace->attr == curr_ace_outer->attr)) {
684
685                                 if( DEBUGLVL( 10 )) {
686                                         dbgtext("merge_aces: Merging ACE's\n");
687                                         print_canon_ace( curr_ace_outer, 0);
688                                         print_canon_ace( curr_ace, 0);
689                                 }
690
691                                 /* Merge two allow or two deny ACE's. */
692
693                                 curr_ace_outer->perms |= curr_ace->perms;
694                                 DLIST_REMOVE(list_head, curr_ace);
695                                 SAFE_FREE(curr_ace);
696                                 curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
697                         }
698                 }
699         }
700
701         /*
702          * Now go through and mask off allow permissions with deny permissions.
703          * We can delete either the allow or deny here as we know that each SID
704          * appears only once in the list.
705          */
706
707         for (curr_ace_outer = list_head; curr_ace_outer; curr_ace_outer = curr_ace_outer_next) {
708                 canon_ace *curr_ace;
709                 canon_ace *curr_ace_next;
710
711                 curr_ace_outer_next = curr_ace_outer->next; /* Save the link in case we delete. */
712
713                 for (curr_ace = curr_ace_outer->next; curr_ace; curr_ace = curr_ace_next) {
714
715                         curr_ace_next = curr_ace->next; /* Save the link in case of delete. */
716
717                         /*
718                          * Subtract ACE's with different entries. Due to the ordering constraints
719                          * we've put on the ACL, we know the deny must be the first one.
720                          */
721
722                         if (sid_equal(&curr_ace->trustee, &curr_ace_outer->trustee) &&
723                                 (curr_ace_outer->attr == DENY_ACE) && (curr_ace->attr == ALLOW_ACE)) {
724
725                                 if( DEBUGLVL( 10 )) {
726                                         dbgtext("merge_aces: Masking ACE's\n");
727                                         print_canon_ace( curr_ace_outer, 0);
728                                         print_canon_ace( curr_ace, 0);
729                                 }
730
731                                 curr_ace->perms &= ~curr_ace_outer->perms;
732
733                                 if (curr_ace->perms == 0) {
734
735                                         /*
736                                          * The deny overrides the allow. Remove the allow.
737                                          */
738
739                                         DLIST_REMOVE(list_head, curr_ace);
740                                         SAFE_FREE(curr_ace);
741                                         curr_ace_outer_next = curr_ace_outer->next; /* We may have deleted the link. */
742
743                                 } else {
744
745                                         /*
746                                          * Even after removing permissions, there
747                                          * are still allow permissions - delete the deny.
748                                          * It is safe to delete the deny here,
749                                          * as we are guarenteed by the deny first
750                                          * ordering that all the deny entries for
751                                          * this SID have already been merged into one
752                                          * before we can get to an allow ace.
753                                          */
754
755                                         DLIST_REMOVE(list_head, curr_ace_outer);
756                                         SAFE_FREE(curr_ace_outer);
757                                         break;
758                                 }
759                         }
760
761                 } /* end for curr_ace */
762         } /* end for curr_ace_outer */
763
764         /* We may have modified the list. */
765
766         *pp_list_head = list_head;
767 }
768
769 /****************************************************************************
770  Check if we need to return NT4.x compatible ACL entries.
771 ****************************************************************************/
772
773 static BOOL nt4_compatible_acls(void)
774 {
775         const char *compat = lp_acl_compatibility();
776
777         if (*compat == '\0') {
778                 enum remote_arch_types ra_type = get_remote_arch();
779
780                 /* Automatically adapt to client */
781                 return (ra_type <= RA_WINNT);
782         } else
783                 return (strequal(compat, "winnt"));
784 }
785
786
787 /****************************************************************************
788  Map canon_ace perms to permission bits NT.
789  The attr element is not used here - we only process deny entries on set,
790  not get. Deny entries are implicit on get with ace->perms = 0.
791 ****************************************************************************/
792
793 static SEC_ACCESS map_canon_ace_perms(int *pacl_type, DOM_SID *powner_sid, canon_ace *ace)
794 {
795         SEC_ACCESS sa;
796         uint32 nt_mask = 0;
797
798         *pacl_type = SEC_ACE_TYPE_ACCESS_ALLOWED;
799
800         if ((ace->perms & ALL_ACE_PERMS) == ALL_ACE_PERMS) {
801                         nt_mask = UNIX_ACCESS_RWX;
802         } else if ((ace->perms & ALL_ACE_PERMS) == (mode_t)0) {
803                 /*
804                  * Windows NT refuses to display ACEs with no permissions in them (but
805                  * they are perfectly legal with Windows 2000). If the ACE has empty
806                  * permissions we cannot use 0, so we use the otherwise unused
807                  * WRITE_OWNER permission, which we ignore when we set an ACL.
808                  * We abstract this into a #define of UNIX_ACCESS_NONE to allow this
809                  * to be changed in the future.
810                  */
811
812                 if (nt4_compatible_acls())
813                         nt_mask = UNIX_ACCESS_NONE;
814                 else
815                         nt_mask = 0;
816         } else {
817                 nt_mask |= ((ace->perms & S_IRUSR) ? UNIX_ACCESS_R : 0 );
818                 nt_mask |= ((ace->perms & S_IWUSR) ? UNIX_ACCESS_W : 0 );
819                 nt_mask |= ((ace->perms & S_IXUSR) ? UNIX_ACCESS_X : 0 );
820         }
821
822         DEBUG(10,("map_canon_ace_perms: Mapped (UNIX) %x to (NT) %x\n",
823                         (unsigned int)ace->perms, (unsigned int)nt_mask ));
824
825         init_sec_access(&sa,nt_mask);
826         return sa;
827 }
828
829 /****************************************************************************
830  Map NT perms to a UNIX mode_t.
831 ****************************************************************************/
832
833 #define FILE_SPECIFIC_READ_BITS (FILE_READ_DATA|FILE_READ_EA|FILE_READ_ATTRIBUTES)
834 #define FILE_SPECIFIC_WRITE_BITS (FILE_WRITE_DATA|FILE_APPEND_DATA|FILE_WRITE_EA|FILE_WRITE_ATTRIBUTES)
835 #define FILE_SPECIFIC_EXECUTE_BITS (FILE_EXECUTE)
836
837 static mode_t map_nt_perms( SEC_ACCESS sec_access, int type)
838 {
839         mode_t mode = 0;
840
841         switch(type) {
842         case S_IRUSR:
843                 if(sec_access.mask & GENERIC_ALL_ACCESS)
844                         mode = S_IRUSR|S_IWUSR|S_IXUSR;
845                 else {
846                         mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRUSR : 0;
847                         mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWUSR : 0;
848                         mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXUSR : 0;
849                 }
850                 break;
851         case S_IRGRP:
852                 if(sec_access.mask & GENERIC_ALL_ACCESS)
853                         mode = S_IRGRP|S_IWGRP|S_IXGRP;
854                 else {
855                         mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IRGRP : 0;
856                         mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWGRP : 0;
857                         mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXGRP : 0;
858                 }
859                 break;
860         case S_IROTH:
861                 if(sec_access.mask & GENERIC_ALL_ACCESS)
862                         mode = S_IROTH|S_IWOTH|S_IXOTH;
863                 else {
864                         mode |= (sec_access.mask & (GENERIC_READ_ACCESS|FILE_SPECIFIC_READ_BITS)) ? S_IROTH : 0;
865                         mode |= (sec_access.mask & (GENERIC_WRITE_ACCESS|FILE_SPECIFIC_WRITE_BITS)) ? S_IWOTH : 0;
866                         mode |= (sec_access.mask & (GENERIC_EXECUTE_ACCESS|FILE_SPECIFIC_EXECUTE_BITS)) ? S_IXOTH : 0;
867                 }
868                 break;
869         }
870
871         return mode;
872 }
873
874 /****************************************************************************
875  Unpack a SEC_DESC into a UNIX owner and group.
876 ****************************************************************************/
877
878 static BOOL unpack_nt_owners(SMB_STRUCT_STAT *psbuf, uid_t *puser, gid_t *pgrp, uint32 security_info_sent, SEC_DESC *psd)
879 {
880         DOM_SID owner_sid;
881         DOM_SID grp_sid;
882
883         *puser = (uid_t)-1;
884         *pgrp = (gid_t)-1;
885
886         if(security_info_sent == 0) {
887                 DEBUG(0,("unpack_nt_owners: no security info sent !\n"));
888                 return True;
889         }
890
891         /*
892          * Validate the owner and group SID's.
893          */
894
895         memset(&owner_sid, '\0', sizeof(owner_sid));
896         memset(&grp_sid, '\0', sizeof(grp_sid));
897
898         DEBUG(5,("unpack_nt_owners: validating owner_sids.\n"));
899
900         /*
901          * Don't immediately fail if the owner sid cannot be validated.
902          * This may be a group chown only set.
903          */
904
905         if (security_info_sent & OWNER_SECURITY_INFORMATION) {
906                 sid_copy(&owner_sid, psd->owner_sid);
907                 if (!NT_STATUS_IS_OK(sid_to_uid(&owner_sid, puser))) {
908 #if ACL_FORCE_UNMAPPABLE
909                         /* this allows take ownership to work reasonably */
910                         extern struct current_user current_user;
911                         *puser = current_user.uid;
912 #else
913                         DEBUG(3,("unpack_nt_owners: unable to validate owner sid for %s\n",
914                                  sid_string_static(&owner_sid)));
915                         return False;
916 #endif
917                 }
918         }
919
920         /*
921          * Don't immediately fail if the group sid cannot be validated.
922          * This may be an owner chown only set.
923          */
924
925         if (security_info_sent & GROUP_SECURITY_INFORMATION) {
926                 sid_copy(&grp_sid, psd->grp_sid);
927                 if (!NT_STATUS_IS_OK(sid_to_gid( &grp_sid, pgrp))) {
928 #if ACL_FORCE_UNMAPPABLE
929                         /* this allows take group ownership to work reasonably */
930                         extern struct current_user current_user;
931                         *pgrp = current_user.gid;
932 #else
933                         DEBUG(3,("unpack_nt_owners: unable to validate group sid.\n"));
934                         return False;
935 #endif
936                 }
937         }
938
939         DEBUG(5,("unpack_nt_owners: owner_sids validated.\n"));
940
941         return True;
942 }
943
944 /****************************************************************************
945  Ensure the enforced permissions for this share apply.
946 ****************************************************************************/
947
948 static void apply_default_perms(files_struct *fsp, canon_ace *pace, mode_t type)
949 {
950         int snum = SNUM(fsp->conn);
951         mode_t and_bits = (mode_t)0;
952         mode_t or_bits = (mode_t)0;
953
954         /* Get the initial bits to apply. */
955
956         if (fsp->is_directory) {
957                 and_bits = lp_dir_security_mask(snum);
958                 or_bits = lp_force_dir_security_mode(snum);
959         } else {
960                 and_bits = lp_security_mask(snum);
961                 or_bits = lp_force_security_mode(snum);
962         }
963
964         /* Now bounce them into the S_USR space. */     
965         switch(type) {
966         case S_IRUSR:
967                 /* Ensure owner has read access. */
968                 pace->perms |= S_IRUSR;
969                 if (fsp->is_directory)
970                         pace->perms |= (S_IWUSR|S_IXUSR);
971                 and_bits = unix_perms_to_acl_perms(and_bits, S_IRUSR, S_IWUSR, S_IXUSR);
972                 or_bits = unix_perms_to_acl_perms(or_bits, S_IRUSR, S_IWUSR, S_IXUSR);
973                 break;
974         case S_IRGRP:
975                 and_bits = unix_perms_to_acl_perms(and_bits, S_IRGRP, S_IWGRP, S_IXGRP);
976                 or_bits = unix_perms_to_acl_perms(or_bits, S_IRGRP, S_IWGRP, S_IXGRP);
977                 break;
978         case S_IROTH:
979                 and_bits = unix_perms_to_acl_perms(and_bits, S_IROTH, S_IWOTH, S_IXOTH);
980                 or_bits = unix_perms_to_acl_perms(or_bits, S_IROTH, S_IWOTH, S_IXOTH);
981                 break;
982         }
983
984         pace->perms = ((pace->perms & and_bits)|or_bits);
985 }
986
987 /****************************************************************************
988  Check if a given uid/SID is in a group gid/SID. This is probably very
989  expensive and will need optimisation. A *lot* of optimisation :-). JRA.
990 ****************************************************************************/
991
992 static BOOL uid_entry_in_group( canon_ace *uid_ace, canon_ace *group_ace )
993 {
994         extern DOM_SID global_sid_World;
995         fstring u_name;
996         fstring g_name;
997         extern struct current_user current_user;
998
999         /* "Everyone" always matches every uid. */
1000
1001         if (sid_equal(&group_ace->trustee, &global_sid_World))
1002                 return True;
1003
1004         /* Assume that the current user is in the current group (force group) */
1005
1006         if (uid_ace->unix_ug.uid == current_user.uid && group_ace->unix_ug.gid == current_user.gid)
1007                 return True;
1008
1009         fstrcpy(u_name, uidtoname(uid_ace->unix_ug.uid));
1010         fstrcpy(g_name, gidtoname(group_ace->unix_ug.gid));
1011
1012         /*
1013          * Due to the winbind interfaces we need to do this via names,
1014          * not uids/gids.
1015          */
1016
1017         return user_in_group_list(u_name, g_name, NULL, 0);
1018 }
1019
1020 /****************************************************************************
1021  A well formed POSIX file or default ACL has at least 3 entries, a 
1022  SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ.
1023  In addition, the owner must always have at least read access.
1024  When using this call on get_acl, the pst struct is valid and contains
1025  the mode of the file. When using this call on set_acl, the pst struct has
1026  been modified to have a mode containing the default for this file or directory
1027  type.
1028 ****************************************************************************/
1029
1030 static BOOL ensure_canon_entry_valid(canon_ace **pp_ace,
1031                                                         files_struct *fsp,
1032                                                         DOM_SID *pfile_owner_sid,
1033                                                         DOM_SID *pfile_grp_sid,
1034                                                         SMB_STRUCT_STAT *pst,
1035                                                         BOOL setting_acl)
1036 {
1037         extern DOM_SID global_sid_World;
1038         canon_ace *pace;
1039         BOOL got_user = False;
1040         BOOL got_grp = False;
1041         BOOL got_other = False;
1042         canon_ace *pace_other = NULL;
1043         canon_ace *pace_group = NULL;
1044
1045         for (pace = *pp_ace; pace; pace = pace->next) {
1046                 if (pace->type == SMB_ACL_USER_OBJ) {
1047
1048                         if (setting_acl)
1049                                 apply_default_perms(fsp, pace, S_IRUSR);
1050                         got_user = True;
1051
1052                 } else if (pace->type == SMB_ACL_GROUP_OBJ) {
1053
1054                         /*
1055                          * Ensure create mask/force create mode is respected on set.
1056                          */
1057
1058                         if (setting_acl)
1059                                 apply_default_perms(fsp, pace, S_IRGRP);
1060                         got_grp = True;
1061                         pace_group = pace;
1062
1063                 } else if (pace->type == SMB_ACL_OTHER) {
1064
1065                         /*
1066                          * Ensure create mask/force create mode is respected on set.
1067                          */
1068
1069                         if (setting_acl)
1070                                 apply_default_perms(fsp, pace, S_IROTH);
1071                         got_other = True;
1072                         pace_other = pace;
1073                 }
1074         }
1075
1076         if (!got_user) {
1077                 if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
1078                         DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
1079                         return False;
1080                 }
1081
1082                 ZERO_STRUCTP(pace);
1083                 pace->type = SMB_ACL_USER_OBJ;
1084                 pace->owner_type = UID_ACE;
1085                 pace->unix_ug.uid = pst->st_uid;
1086                 pace->trustee = *pfile_owner_sid;
1087                 pace->attr = ALLOW_ACE;
1088
1089                 if (setting_acl) {
1090                         /* If we only got an "everyone" perm, just use that. */
1091                         if (!got_grp && got_other)
1092                                 pace->perms = pace_other->perms;
1093                         else if (got_grp && uid_entry_in_group(pace, pace_group))
1094                                 pace->perms = pace_group->perms;
1095                         else
1096                                 pace->perms = 0;
1097
1098                         apply_default_perms(fsp, pace, S_IRUSR);
1099                 } else {
1100                         pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR);
1101                 }
1102
1103                 DLIST_ADD(*pp_ace, pace);
1104         }
1105
1106         if (!got_grp) {
1107                 if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
1108                         DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
1109                         return False;
1110                 }
1111
1112                 ZERO_STRUCTP(pace);
1113                 pace->type = SMB_ACL_GROUP_OBJ;
1114                 pace->owner_type = GID_ACE;
1115                 pace->unix_ug.uid = pst->st_gid;
1116                 pace->trustee = *pfile_grp_sid;
1117                 pace->attr = ALLOW_ACE;
1118                 if (setting_acl) {
1119                         /* If we only got an "everyone" perm, just use that. */
1120                         if (got_other)
1121                                 pace->perms = pace_other->perms;
1122                         else
1123                                 pace->perms = 0;
1124                         apply_default_perms(fsp, pace, S_IRGRP);
1125                 } else {
1126                         pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP);
1127                 }
1128
1129                 DLIST_ADD(*pp_ace, pace);
1130         }
1131
1132         if (!got_other) {
1133                 if ((pace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
1134                         DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
1135                         return False;
1136                 }
1137
1138                 ZERO_STRUCTP(pace);
1139                 pace->type = SMB_ACL_OTHER;
1140                 pace->owner_type = WORLD_ACE;
1141                 pace->unix_ug.world = -1;
1142                 pace->trustee = global_sid_World;
1143                 pace->attr = ALLOW_ACE;
1144                 if (setting_acl) {
1145                         pace->perms = 0;
1146                         apply_default_perms(fsp, pace, S_IROTH);
1147                 } else
1148                         pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IROTH, S_IWOTH, S_IXOTH);
1149
1150                 DLIST_ADD(*pp_ace, pace);
1151         }
1152
1153         return True;
1154 }
1155
1156 /****************************************************************************
1157  Check if a POSIX ACL has the required SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries.
1158  If it does not have them, check if there are any entries where the trustee is the
1159  file owner or the owning group, and map these to SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ.
1160 ****************************************************************************/
1161
1162 static void check_owning_objs(canon_ace *ace, DOM_SID *pfile_owner_sid, DOM_SID *pfile_grp_sid)
1163 {
1164         BOOL got_user_obj, got_group_obj;
1165         canon_ace *current_ace;
1166         int i, entries;
1167
1168         entries = count_canon_ace_list(ace);
1169         got_user_obj = False;
1170         got_group_obj = False;
1171
1172         for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
1173                 if (current_ace->type == SMB_ACL_USER_OBJ)
1174                         got_user_obj = True;
1175                 else if (current_ace->type == SMB_ACL_GROUP_OBJ)
1176                         got_group_obj = True;
1177         }
1178         if (got_user_obj && got_group_obj) {
1179                 DEBUG(10,("check_owning_objs: ACL had owning user/group entries.\n"));
1180                 return;
1181         }
1182
1183         for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
1184                 if (!got_user_obj && current_ace->owner_type == UID_ACE &&
1185                                 sid_equal(&current_ace->trustee, pfile_owner_sid)) {
1186                         current_ace->type = SMB_ACL_USER_OBJ;
1187                         got_user_obj = True;
1188                 }
1189                 if (!got_group_obj && current_ace->owner_type == GID_ACE &&
1190                                 sid_equal(&current_ace->trustee, pfile_grp_sid)) {
1191                         current_ace->type = SMB_ACL_GROUP_OBJ;
1192                         got_group_obj = True;
1193                 }
1194         }
1195         if (!got_user_obj)
1196                 DEBUG(10,("check_owning_objs: ACL is missing an owner entry.\n"));
1197         if (!got_group_obj)
1198                 DEBUG(10,("check_owning_objs: ACL is missing an owning group entry.\n"));
1199 }
1200
1201 /****************************************************************************
1202  Unpack a SEC_DESC into two canonical ace lists.
1203 ****************************************************************************/
1204
1205 static BOOL create_canon_ace_lists(files_struct *fsp, 
1206                                                         DOM_SID *pfile_owner_sid,
1207                                                         DOM_SID *pfile_grp_sid,
1208                                                         canon_ace **ppfile_ace, canon_ace **ppdir_ace,
1209                                                         SEC_ACL *dacl)
1210 {
1211         extern DOM_SID global_sid_Creator_Owner;
1212         extern DOM_SID global_sid_Creator_Group;
1213         extern DOM_SID global_sid_World;
1214         extern struct generic_mapping file_generic_mapping;
1215         BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False);
1216         canon_ace *file_ace = NULL;
1217         canon_ace *dir_ace = NULL;
1218         canon_ace *tmp_ace = NULL;
1219         canon_ace *current_ace = NULL;
1220         BOOL got_dir_allow = False;
1221         BOOL got_file_allow = False;
1222         int i, j;
1223
1224         *ppfile_ace = NULL;
1225         *ppdir_ace = NULL;
1226
1227         /*
1228          * Convert the incoming ACL into a more regular form.
1229          */
1230
1231         for(i = 0; i < dacl->num_aces; i++) {
1232                 SEC_ACE *psa = &dacl->ace[i];
1233
1234                 if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) && (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
1235                         DEBUG(3,("create_canon_ace_lists: unable to set anything but an ALLOW or DENY ACE.\n"));
1236                         return False;
1237                 }
1238
1239                 if (nt4_compatible_acls()) {
1240                         /*
1241                          * The security mask may be UNIX_ACCESS_NONE which should map into
1242                          * no permissions (we overload the WRITE_OWNER bit for this) or it
1243                          * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
1244                          * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
1245                          */
1246
1247                         /*
1248                          * Convert GENERIC bits to specific bits.
1249                          */
1250  
1251                         se_map_generic(&psa->info.mask, &file_generic_mapping);
1252
1253                         psa->info.mask &= (UNIX_ACCESS_NONE|FILE_ALL_ACCESS);
1254
1255                         if(psa->info.mask != UNIX_ACCESS_NONE)
1256                                 psa->info.mask &= ~UNIX_ACCESS_NONE;
1257                 }
1258         }
1259
1260         /*
1261          * Deal with the fact that NT 4.x re-writes the canonical format
1262          * that we return for default ACLs. If a directory ACE is identical
1263          * to a inherited directory ACE then NT changes the bits so that the
1264          * first ACE is set to OI|IO and the second ACE for this SID is set
1265          * to CI. We need to repair this. JRA.
1266          */
1267
1268         for(i = 0; i < dacl->num_aces; i++) {
1269                 SEC_ACE *psa1 = &dacl->ace[i];
1270
1271                 for (j = i + 1; j < dacl->num_aces; j++) {
1272                         SEC_ACE *psa2 = &dacl->ace[j];
1273
1274                         if (psa1->info.mask != psa2->info.mask)
1275                                 continue;
1276
1277                         if (!sid_equal(&psa1->trustee, &psa2->trustee))
1278                                 continue;
1279
1280                         /*
1281                          * Ok - permission bits and SIDs are equal.
1282                          * Check if flags were re-written.
1283                          */
1284
1285                         if (psa1->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
1286
1287                                 psa1->flags |= (psa2->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
1288                                 psa2->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
1289                                 
1290                         } else if (psa2->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
1291
1292                                 psa2->flags |= (psa1->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
1293                                 psa1->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
1294                                 
1295                         }
1296                 }
1297         }
1298
1299         for(i = 0; i < dacl->num_aces; i++) {
1300                 SEC_ACE *psa = &dacl->ace[i];
1301
1302                 /*
1303                  * Ignore non-mappable SIDs (NT Authority, BUILTIN etc).
1304                  */
1305
1306                 if (non_mappable_sid(&psa->trustee)) {
1307                         fstring str;
1308                         DEBUG(10,("create_canon_ace_lists: ignoring non-mappable SID %s\n",
1309                                 sid_to_string(str, &psa->trustee) ));
1310                         continue;
1311                 }
1312
1313                 /*
1314                  * Create a cannon_ace entry representing this NT DACL ACE.
1315                  */
1316
1317                 if ((current_ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL) {
1318                         free_canon_ace_list(file_ace);
1319                         free_canon_ace_list(dir_ace);
1320                         DEBUG(0,("create_canon_ace_lists: malloc fail.\n"));
1321                         return False;
1322                 }
1323
1324                 ZERO_STRUCTP(current_ace);
1325
1326                 sid_copy(&current_ace->trustee, &psa->trustee);
1327
1328                 /*
1329                  * Try and work out if the SID is a user or group
1330                  * as we need to flag these differently for POSIX.
1331                  * Note what kind of a POSIX ACL this should map to.
1332                  */
1333
1334                 if( sid_equal(&current_ace->trustee, &global_sid_World)) {
1335                         current_ace->owner_type = WORLD_ACE;
1336                         current_ace->unix_ug.world = -1;
1337                         current_ace->type = SMB_ACL_OTHER;
1338                 } else if (sid_equal(&current_ace->trustee, &global_sid_Creator_Owner)) {
1339                         current_ace->owner_type = UID_ACE;
1340                         current_ace->unix_ug.world = -1;
1341                         current_ace->type = SMB_ACL_USER_OBJ;
1342
1343                         /*
1344                          * The Creator Owner entry only specifies inheritable permissions,
1345                          * never access permissions. WinNT doesn't always set the ACE to
1346                          *INHERIT_ONLY, though.
1347                          */
1348
1349                         if (nt4_compatible_acls())
1350                                 psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
1351                 } else if (sid_equal(&current_ace->trustee, &global_sid_Creator_Group)) {
1352                         current_ace->owner_type = GID_ACE;
1353                         current_ace->unix_ug.world = -1;
1354                         current_ace->type = SMB_ACL_GROUP_OBJ;
1355
1356                         /*
1357                          * The Creator Group entry only specifies inheritable permissions,
1358                          * never access permissions. WinNT doesn't always set the ACE to
1359                          *INHERIT_ONLY, though.
1360                          */
1361                         if (nt4_compatible_acls())
1362                                 psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
1363
1364                 } else if (NT_STATUS_IS_OK(sid_to_gid( &current_ace->trustee, &current_ace->unix_ug.gid))) {
1365                         current_ace->owner_type = GID_ACE;
1366                         current_ace->type = SMB_ACL_GROUP;
1367                 } else if (NT_STATUS_IS_OK(sid_to_uid( &current_ace->trustee, &current_ace->unix_ug.uid))) {
1368                         current_ace->owner_type = UID_ACE;
1369                         current_ace->type = SMB_ACL_USER;
1370                 } else {
1371                         fstring str;
1372
1373                         free_canon_ace_list(file_ace);
1374                         free_canon_ace_list(dir_ace);
1375                         DEBUG(0,("create_canon_ace_lists: unable to map SID %s to uid or gid.\n",
1376                                 sid_to_string(str, &current_ace->trustee) ));
1377                         SAFE_FREE(current_ace);
1378                         return False;
1379                 }
1380
1381                 /*
1382                  * Map the given NT permissions into a UNIX mode_t containing only
1383                  * S_I(R|W|X)USR bits.
1384                  */
1385
1386                 current_ace->perms |= map_nt_perms( psa->info, S_IRUSR);
1387                 current_ace->attr = (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? ALLOW_ACE : DENY_ACE;
1388                 current_ace->inherited = ((psa->flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False);
1389
1390                 /*
1391                  * Now add the created ace to either the file list, the directory
1392                  * list, or both. We *MUST* preserve the order here (hence we use
1393                  * DLIST_ADD_END) as NT ACLs are order dependent.
1394                  */
1395
1396                 if (fsp->is_directory) {
1397
1398                         /*
1399                          * We can only add to the default POSIX ACE list if the ACE is
1400                          * designed to be inherited by both files and directories.
1401                          */
1402
1403                         if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) ==
1404                                 (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) {
1405
1406                                 DLIST_ADD_END(dir_ace, current_ace, tmp_ace);
1407
1408                                 /*
1409                                  * Note if this was an allow ace. We can't process
1410                                  * any further deny ace's after this.
1411                                  */
1412
1413                                 if (current_ace->attr == ALLOW_ACE)
1414                                         got_dir_allow = True;
1415
1416                                 if ((current_ace->attr == DENY_ACE) && got_dir_allow) {
1417                                         DEBUG(0,("create_canon_ace_lists: malformed ACL in inheritable ACL ! \
1418 Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
1419                                         free_canon_ace_list(file_ace);
1420                                         free_canon_ace_list(dir_ace);
1421                                         SAFE_FREE(current_ace);
1422                                         return False;
1423                                 }       
1424
1425                                 if( DEBUGLVL( 10 )) {
1426                                         dbgtext("create_canon_ace_lists: adding dir ACL:\n");
1427                                         print_canon_ace( current_ace, 0);
1428                                 }
1429
1430                                 /*
1431                                  * If this is not an inherit only ACE we need to add a duplicate
1432                                  * to the file acl.
1433                                  */
1434
1435                                 if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
1436                                         canon_ace *dup_ace = dup_canon_ace(current_ace);
1437
1438                                         if (!dup_ace) {
1439                                                 DEBUG(0,("create_canon_ace_lists: malloc fail !\n"));
1440                                                 free_canon_ace_list(file_ace);
1441                                                 free_canon_ace_list(dir_ace);
1442                                                 return False;
1443                                         }
1444
1445                                         /*
1446                                          * We must not free current_ace here as its
1447                                          * pointer is now owned by the dir_ace list.
1448                                          */
1449                                         current_ace = dup_ace;
1450                                 } else {
1451                                         /*
1452                                          * We must not free current_ace here as its
1453                                          * pointer is now owned by the dir_ace list.
1454                                          */
1455                                         current_ace = NULL;
1456                                 }
1457                         }
1458                 }
1459
1460                 /*
1461                  * Only add to the file ACL if not inherit only.
1462                  */
1463
1464                 if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
1465                         DLIST_ADD_END(file_ace, current_ace, tmp_ace);
1466
1467                         /*
1468                          * Note if this was an allow ace. We can't process
1469                          * any further deny ace's after this.
1470                          */
1471
1472                         if (current_ace->attr == ALLOW_ACE)
1473                                 got_file_allow = True;
1474
1475                         if ((current_ace->attr == DENY_ACE) && got_file_allow) {
1476                                 DEBUG(0,("create_canon_ace_lists: malformed ACL in file ACL ! \
1477 Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
1478                                 free_canon_ace_list(file_ace);
1479                                 free_canon_ace_list(dir_ace);
1480                                 SAFE_FREE(current_ace);
1481                                 return False;
1482                         }       
1483
1484                         if( DEBUGLVL( 10 )) {
1485                                 dbgtext("create_canon_ace_lists: adding file ACL:\n");
1486                                 print_canon_ace( current_ace, 0);
1487                         }
1488                         all_aces_are_inherit_only = False;
1489                         /*
1490                          * We must not free current_ace here as its
1491                          * pointer is now owned by the file_ace list.
1492                          */
1493                         current_ace = NULL;
1494                 }
1495
1496                 /*
1497                  * Free if ACE was not added.
1498                  */
1499
1500                 SAFE_FREE(current_ace);
1501         }
1502
1503         if (fsp->is_directory && all_aces_are_inherit_only) {
1504                 /*
1505                  * Windows 2000 is doing one of these weird 'inherit acl'
1506                  * traverses to conserve NTFS ACL resources. Just pretend
1507                  * there was no DACL sent. JRA.
1508                  */
1509
1510                 DEBUG(10,("create_canon_ace_lists: Win2k inherit acl traverse. Ignoring DACL.\n"));
1511                 free_canon_ace_list(file_ace);
1512                 free_canon_ace_list(dir_ace);
1513                 file_ace = NULL;
1514                 dir_ace = NULL;
1515         } else {
1516                 /*
1517                  * Check if we have SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries in each
1518                  * ACL. If we don't have them, check if any SMB_ACL_USER/SMB_ACL_GROUP
1519                  * entries can be converted to *_OBJ. Usually we will already have these
1520                  * entries in the Default ACL, and the Access ACL will not have them.
1521                  */
1522                 check_owning_objs(file_ace, pfile_owner_sid, pfile_grp_sid);
1523                 check_owning_objs(dir_ace, pfile_owner_sid, pfile_grp_sid);
1524         }
1525
1526         *ppfile_ace = file_ace;
1527         *ppdir_ace = dir_ace;
1528
1529         return True;
1530 }
1531
1532 /****************************************************************************
1533  ASCII art time again... JRA :-).
1534
1535  We have 4 cases to process when moving from an NT ACL to a POSIX ACL. Firstly,
1536  we insist the ACL is in canonical form (ie. all DENY entries preceede ALLOW
1537  entries). Secondly, the merge code has ensured that all duplicate SID entries for
1538  allow or deny have been merged, so the same SID can only appear once in the deny
1539  list or once in the allow list.
1540
1541  We then process as follows :
1542
1543  ---------------------------------------------------------------------------
1544  First pass - look for a Everyone DENY entry.
1545
1546  If it is deny all (rwx) trunate the list at this point.
1547  Else, walk the list from this point and use the deny permissions of this
1548  entry as a mask on all following allow entries. Finally, delete
1549  the Everyone DENY entry (we have applied it to everything possible).
1550
1551  In addition, in this pass we remove any DENY entries that have 
1552  no permissions (ie. they are a DENY nothing).
1553  ---------------------------------------------------------------------------
1554  Second pass - only deal with deny user entries.
1555
1556  DENY user1 (perms XXX)
1557
1558  new_perms = 0
1559  for all following allow group entries where user1 is in group
1560         new_perms |= group_perms;
1561
1562  user1 entry perms = new_perms & ~ XXX;
1563
1564  Convert the deny entry to an allow entry with the new perms and
1565  push to the end of the list. Note if the user was in no groups
1566  this maps to a specific allow nothing entry for this user.
1567
1568  The common case from the NT ACL choser (userX deny all) is
1569  optimised so we don't do the group lookup - we just map to
1570  an allow nothing entry.
1571
1572  What we're doing here is inferring the allow permissions the
1573  person setting the ACE on user1 wanted by looking at the allow
1574  permissions on the groups the user is currently in. This will
1575  be a snapshot, depending on group membership but is the best
1576  we can do and has the advantage of failing closed rather than
1577  open.
1578  ---------------------------------------------------------------------------
1579  Third pass - only deal with deny group entries.
1580
1581  DENY group1 (perms XXX)
1582
1583  for all following allow user entries where user is in group1
1584    user entry perms = user entry perms & ~ XXX;
1585
1586  If there is a group Everyone allow entry with permissions YYY,
1587  convert the group1 entry to an allow entry and modify its
1588  permissions to be :
1589
1590  new_perms = YYY & ~ XXX
1591
1592  and push to the end of the list.
1593
1594  If there is no group Everyone allow entry then convert the
1595  group1 entry to a allow nothing entry and push to the end of the list.
1596
1597  Note that the common case from the NT ACL choser (groupX deny all)
1598  cannot be optimised here as we need to modify user entries who are
1599  in the group to change them to a deny all also.
1600
1601  What we're doing here is modifying the allow permissions of
1602  user entries (which are more specific in POSIX ACLs) to mask
1603  out the explicit deny set on the group they are in. This will
1604  be a snapshot depending on current group membership but is the
1605  best we can do and has the advantage of failing closed rather
1606  than open.
1607  ---------------------------------------------------------------------------
1608  Fourth pass - cope with cumulative permissions.
1609
1610  for all allow user entries, if there exists an allow group entry with
1611  more permissive permissions, and the user is in that group, rewrite the
1612  allow user permissions to contain both sets of permissions.
1613
1614  Currently the code for this is #ifdef'ed out as these semantics make
1615  no sense to me. JRA.
1616  ---------------------------------------------------------------------------
1617
1618  Note we *MUST* do the deny user pass first as this will convert deny user
1619  entries into allow user entries which can then be processed by the deny
1620  group pass.
1621
1622  The above algorithm took a *lot* of thinking about - hence this
1623  explaination :-). JRA.
1624 ****************************************************************************/
1625
1626 /****************************************************************************
1627  Process a canon_ace list entries. This is very complex code. We need
1628  to go through and remove the "deny" permissions from any allow entry that matches
1629  the id of this entry. We have already refused any NT ACL that wasn't in correct
1630  order (DENY followed by ALLOW). If any allow entry ends up with zero permissions,
1631  we just remove it (to fail safe). We have already removed any duplicate ace
1632  entries. Treat an "Everyone" DENY_ACE as a special case - use it to mask all
1633  allow entries.
1634 ****************************************************************************/
1635
1636 static void process_deny_list( canon_ace **pp_ace_list )
1637 {
1638         extern DOM_SID global_sid_World;
1639         canon_ace *ace_list = *pp_ace_list;
1640         canon_ace *curr_ace = NULL;
1641         canon_ace *curr_ace_next = NULL;
1642
1643         /* Pass 1 above - look for an Everyone, deny entry. */
1644
1645         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1646                 canon_ace *allow_ace_p;
1647
1648                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1649
1650                 if (curr_ace->attr != DENY_ACE)
1651                         continue;
1652
1653                 if (curr_ace->perms == (mode_t)0) {
1654
1655                         /* Deny nothing entry - delete. */
1656
1657                         DLIST_REMOVE(ace_list, curr_ace);
1658                         continue;
1659                 }
1660
1661                 if (!sid_equal(&curr_ace->trustee, &global_sid_World))
1662                         continue;
1663
1664                 /* JRATEST - assert. */
1665                 SMB_ASSERT(curr_ace->owner_type == WORLD_ACE);
1666
1667                 if (curr_ace->perms == ALL_ACE_PERMS) {
1668
1669                         /*
1670                          * Optimisation. This is a DENY_ALL to Everyone. Truncate the
1671                          * list at this point including this entry.
1672                          */
1673
1674                         canon_ace *prev_entry = curr_ace->prev;
1675
1676                         free_canon_ace_list( curr_ace );
1677                         if (prev_entry)
1678                                 prev_entry->next = NULL;
1679                         else {
1680                                 /* We deleted the entire list. */
1681                                 ace_list = NULL;
1682                         }
1683                         break;
1684                 }
1685
1686                 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1687
1688                         /* 
1689                          * Only mask off allow entries.
1690                          */
1691
1692                         if (allow_ace_p->attr != ALLOW_ACE)
1693                                 continue;
1694
1695                         allow_ace_p->perms &= ~curr_ace->perms;
1696                 }
1697
1698                 /*
1699                  * Now it's been applied, remove it.
1700                  */
1701
1702                 DLIST_REMOVE(ace_list, curr_ace);
1703         }
1704
1705         /* Pass 2 above - deal with deny user entries. */
1706
1707         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1708                 mode_t new_perms = (mode_t)0;
1709                 canon_ace *allow_ace_p;
1710                 canon_ace *tmp_ace;
1711
1712                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1713
1714                 if (curr_ace->attr != DENY_ACE)
1715                         continue;
1716
1717                 if (curr_ace->owner_type != UID_ACE)
1718                         continue;
1719
1720                 if (curr_ace->perms == ALL_ACE_PERMS) {
1721
1722                         /*
1723                          * Optimisation - this is a deny everything to this user.
1724                          * Convert to an allow nothing and push to the end of the list.
1725                          */
1726
1727                         curr_ace->attr = ALLOW_ACE;
1728                         curr_ace->perms = (mode_t)0;
1729                         DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
1730                         continue;
1731                 }
1732
1733                 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1734
1735                         if (allow_ace_p->attr != ALLOW_ACE)
1736                                 continue;
1737
1738                         /* We process GID_ACE and WORLD_ACE entries only. */
1739
1740                         if (allow_ace_p->owner_type == UID_ACE)
1741                                 continue;
1742
1743                         if (uid_entry_in_group( curr_ace, allow_ace_p))
1744                                 new_perms |= allow_ace_p->perms;
1745                 }
1746
1747                 /*
1748                  * Convert to a allow entry, modify the perms and push to the end
1749                  * of the list.
1750                  */
1751
1752                 curr_ace->attr = ALLOW_ACE;
1753                 curr_ace->perms = (new_perms & ~curr_ace->perms);
1754                 DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
1755         }
1756
1757         /* Pass 3 above - deal with deny group entries. */
1758
1759         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1760                 canon_ace *tmp_ace;
1761                 canon_ace *allow_ace_p;
1762                 canon_ace *allow_everyone_p = NULL;
1763
1764                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1765
1766                 if (curr_ace->attr != DENY_ACE)
1767                         continue;
1768
1769                 if (curr_ace->owner_type != GID_ACE)
1770                         continue;
1771
1772                 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1773
1774                         if (allow_ace_p->attr != ALLOW_ACE)
1775                                 continue;
1776
1777                         /* Store a pointer to the Everyone allow, if it exists. */
1778                         if (allow_ace_p->owner_type == WORLD_ACE)
1779                                 allow_everyone_p = allow_ace_p;
1780
1781                         /* We process UID_ACE entries only. */
1782
1783                         if (allow_ace_p->owner_type != UID_ACE)
1784                                 continue;
1785
1786                         /* Mask off the deny group perms. */
1787
1788                         if (uid_entry_in_group( allow_ace_p, curr_ace))
1789                                 allow_ace_p->perms &= ~curr_ace->perms;
1790                 }
1791
1792                 /*
1793                  * Convert the deny to an allow with the correct perms and
1794                  * push to the end of the list.
1795                  */
1796
1797                 curr_ace->attr = ALLOW_ACE;
1798                 if (allow_everyone_p)
1799                         curr_ace->perms = allow_everyone_p->perms & ~curr_ace->perms;
1800                 else
1801                         curr_ace->perms = (mode_t)0;
1802                 DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
1803
1804         }
1805
1806         /* Doing this fourth pass allows Windows semantics to be layered
1807          * on top of POSIX semantics. I'm not sure if this is desirable.
1808          * For example, in W2K ACLs there is no way to say, "Group X no
1809          * access, user Y full access" if user Y is a member of group X.
1810          * This seems completely broken semantics to me.... JRA.
1811          */
1812
1813 #if 0
1814         /* Pass 4 above - deal with allow entries. */
1815
1816         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1817                 canon_ace *allow_ace_p;
1818
1819                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1820
1821                 if (curr_ace->attr != ALLOW_ACE)
1822                         continue;
1823
1824                 if (curr_ace->owner_type != UID_ACE)
1825                         continue;
1826
1827                 for (allow_ace_p = ace_list; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1828
1829                         if (allow_ace_p->attr != ALLOW_ACE)
1830                                 continue;
1831
1832                         /* We process GID_ACE entries only. */
1833
1834                         if (allow_ace_p->owner_type != GID_ACE)
1835                                 continue;
1836
1837                         /* OR in the group perms. */
1838
1839                         if (uid_entry_in_group( curr_ace, allow_ace_p))
1840                                 curr_ace->perms |= allow_ace_p->perms;
1841                 }
1842         }
1843 #endif
1844
1845         *pp_ace_list = ace_list;
1846 }
1847
1848 /****************************************************************************
1849  Create a default mode that will be used if a security descriptor entry has
1850  no user/group/world entries.
1851 ****************************************************************************/
1852
1853 static mode_t create_default_mode(files_struct *fsp, BOOL interitable_mode)
1854 {
1855         int snum = SNUM(fsp->conn);
1856         mode_t and_bits = (mode_t)0;
1857         mode_t or_bits = (mode_t)0;
1858         mode_t mode = interitable_mode ? unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name) : S_IRUSR;
1859
1860         if (fsp->is_directory)
1861                 mode |= (S_IWUSR|S_IXUSR);
1862
1863         /*
1864          * Now AND with the create mode/directory mode bits then OR with the
1865          * force create mode/force directory mode bits.
1866          */
1867
1868         if (fsp->is_directory) {
1869                 and_bits = lp_dir_security_mask(snum);
1870                 or_bits = lp_force_dir_security_mode(snum);
1871         } else {
1872                 and_bits = lp_security_mask(snum);
1873                 or_bits = lp_force_security_mode(snum);
1874         }
1875
1876         return ((mode & and_bits)|or_bits);
1877 }
1878
1879 /****************************************************************************
1880  Unpack a SEC_DESC into two canonical ace lists. We don't depend on this
1881  succeeding.
1882 ****************************************************************************/
1883
1884 static BOOL unpack_canon_ace(files_struct *fsp, 
1885                                                         SMB_STRUCT_STAT *pst,
1886                                                         DOM_SID *pfile_owner_sid,
1887                                                         DOM_SID *pfile_grp_sid,
1888                                                         canon_ace **ppfile_ace, canon_ace **ppdir_ace,
1889                                                         uint32 security_info_sent, SEC_DESC *psd)
1890 {
1891         canon_ace *file_ace = NULL;
1892         canon_ace *dir_ace = NULL;
1893
1894         *ppfile_ace = NULL;
1895         *ppdir_ace = NULL;
1896
1897         if(security_info_sent == 0) {
1898                 DEBUG(0,("unpack_canon_ace: no security info sent !\n"));
1899                 return False;
1900         }
1901
1902         /*
1903          * If no DACL then this is a chown only security descriptor.
1904          */
1905
1906         if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !psd->dacl)
1907                 return True;
1908
1909         /*
1910          * Now go through the DACL and create the canon_ace lists.
1911          */
1912
1913         if (!create_canon_ace_lists( fsp, pfile_owner_sid, pfile_grp_sid,
1914                                                                 &file_ace, &dir_ace, psd->dacl))
1915                 return False;
1916
1917         if ((file_ace == NULL) && (dir_ace == NULL)) {
1918                 /* W2K traverse DACL set - ignore. */
1919                 return True;
1920         }
1921
1922         /*
1923          * Go through the canon_ace list and merge entries
1924          * belonging to identical users of identical allow or deny type.
1925          * We can do this as all deny entries come first, followed by
1926          * all allow entries (we have mandated this before accepting this acl).
1927          */
1928
1929         print_canon_ace_list( "file ace - before merge", file_ace);
1930         merge_aces( &file_ace );
1931
1932         print_canon_ace_list( "dir ace - before merge", dir_ace);
1933         merge_aces( &dir_ace );
1934
1935         /*
1936          * NT ACLs are order dependent. Go through the acl lists and
1937          * process DENY entries by masking the allow entries.
1938          */
1939
1940         print_canon_ace_list( "file ace - before deny", file_ace);
1941         process_deny_list( &file_ace);
1942
1943         print_canon_ace_list( "dir ace - before deny", dir_ace);
1944         process_deny_list( &dir_ace);
1945
1946         /*
1947          * A well formed POSIX file or default ACL has at least 3 entries, a 
1948          * SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ
1949          * and optionally a mask entry. Ensure this is the case.
1950          */
1951
1952         print_canon_ace_list( "file ace - before valid", file_ace);
1953
1954         /*
1955          * A default 3 element mode entry for a file should be r-- --- ---.
1956          * A default 3 element mode entry for a directory should be rwx --- ---.
1957          */
1958
1959         pst->st_mode = create_default_mode(fsp, False);
1960
1961         if (!ensure_canon_entry_valid(&file_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
1962                 free_canon_ace_list(file_ace);
1963                 free_canon_ace_list(dir_ace);
1964                 return False;
1965         }
1966
1967         print_canon_ace_list( "dir ace - before valid", dir_ace);
1968
1969         /*
1970          * A default inheritable 3 element mode entry for a directory should be the
1971          * mode Samba will use to create a file within. Ensure user rwx bits are set if
1972          * it's a directory.
1973          */
1974
1975         pst->st_mode = create_default_mode(fsp, True);
1976
1977         if (dir_ace && !ensure_canon_entry_valid(&dir_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
1978                 free_canon_ace_list(file_ace);
1979                 free_canon_ace_list(dir_ace);
1980                 return False;
1981         }
1982
1983         print_canon_ace_list( "file ace - return", file_ace);
1984         print_canon_ace_list( "dir ace - return", dir_ace);
1985
1986         *ppfile_ace = file_ace;
1987         *ppdir_ace = dir_ace;
1988         return True;
1989
1990 }
1991
1992 /******************************************************************************
1993  When returning permissions, try and fit NT display
1994  semantics if possible. Note the the canon_entries here must have been malloced.
1995  The list format should be - first entry = owner, followed by group and other user
1996  entries, last entry = other.
1997
1998  Note that this doesn't exactly match the NT semantics for an ACL. As POSIX entries
1999  are not ordered, and match on the most specific entry rather than walking a list,
2000  then a simple POSIX permission of rw-r--r-- should really map to 5 entries,
2001
2002  Entry 0: owner : deny all except read and write.
2003  Entry 1: group : deny all except read.
2004  Entry 2: owner : allow read and write.
2005  Entry 3: group : allow read.
2006  Entry 4: Everyone : allow read.
2007
2008  But NT cannot display this in their ACL editor !
2009 ********************************************************************************/
2010
2011 static void arrange_posix_perms( char *filename, canon_ace **pp_list_head)
2012 {
2013         canon_ace *list_head = *pp_list_head;
2014         canon_ace *owner_ace = NULL;
2015         canon_ace *other_ace = NULL;
2016         canon_ace *ace = NULL;
2017
2018         for (ace = list_head; ace; ace = ace->next) {
2019                 if (ace->type == SMB_ACL_USER_OBJ)
2020                         owner_ace = ace;
2021                 else if (ace->type == SMB_ACL_OTHER) {
2022                         /* Last ace - this is "other" */
2023                         other_ace = ace;
2024                 }
2025         }
2026                 
2027         if (!owner_ace || !other_ace) {
2028                 DEBUG(0,("arrange_posix_perms: Invalid POSIX permissions for file %s, missing owner or other.\n",
2029                         filename ));
2030                 return;
2031         }
2032
2033         /*
2034          * The POSIX algorithm applies to owner first, and other last,
2035          * so ensure they are arranged in this order.
2036          */
2037
2038         if (owner_ace) {
2039                 DLIST_PROMOTE(list_head, owner_ace);
2040         }
2041
2042         if (other_ace) {
2043                 DLIST_DEMOTE(list_head, other_ace, ace);
2044         }
2045
2046         /* We have probably changed the head of the list. */
2047
2048         *pp_list_head = list_head;
2049 }
2050                 
2051 /****************************************************************************
2052  Create a linked list of canonical ACE entries.
2053 ****************************************************************************/
2054
2055 static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf,
2056                                         DOM_SID *powner, DOM_SID *pgroup, struct pai_val *pal, SMB_ACL_TYPE_T the_acl_type)
2057 {
2058         extern DOM_SID global_sid_World;
2059         connection_struct *conn = fsp->conn;
2060         mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR);
2061         canon_ace *list_head = NULL;
2062         canon_ace *ace = NULL;
2063         canon_ace *next_ace = NULL;
2064         int entry_id = SMB_ACL_FIRST_ENTRY;
2065         SMB_ACL_ENTRY_T entry;
2066         size_t ace_count;
2067
2068         while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
2069                 SMB_ACL_TAG_T tagtype;
2070                 SMB_ACL_PERMSET_T permset;
2071                 DOM_SID sid;
2072                 posix_id unix_ug;
2073                 enum ace_owner owner_type;
2074
2075                 /* get_next... */
2076                 if (entry_id == SMB_ACL_FIRST_ENTRY)
2077                         entry_id = SMB_ACL_NEXT_ENTRY;
2078
2079                 /* Is this a MASK entry ? */
2080                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
2081                         continue;
2082
2083                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
2084                         continue;
2085
2086                 /* Decide which SID to use based on the ACL type. */
2087                 switch(tagtype) {
2088                         case SMB_ACL_USER_OBJ:
2089                                 /* Get the SID from the owner. */
2090                                 sid_copy(&sid, powner);
2091                                 unix_ug.uid = psbuf->st_uid;
2092                                 owner_type = UID_ACE;
2093                                 break;
2094                         case SMB_ACL_USER:
2095                                 {
2096                                         uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
2097                                         if (puid == NULL) {
2098                                                 DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
2099                                                 continue;
2100                                         }
2101                                         /*
2102                                          * A SMB_ACL_USER entry for the owner is shadowed by the
2103                                          * SMB_ACL_USER_OBJ entry and Windows also cannot represent
2104                                          * that entry, so we ignore it. We also don't create such
2105                                          * entries out of the blue when setting ACLs, so a get/set
2106                                          * cycle will drop them.
2107                                          */
2108                                         if (the_acl_type == SMB_ACL_TYPE_ACCESS && *puid == psbuf->st_uid)
2109                                                 continue;
2110                                         uid_to_sid( &sid, *puid);
2111                                         unix_ug.uid = *puid;
2112                                         owner_type = UID_ACE;
2113                                         SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
2114                                         break;
2115                                 }
2116                         case SMB_ACL_GROUP_OBJ:
2117                                 /* Get the SID from the owning group. */
2118                                 sid_copy(&sid, pgroup);
2119                                 unix_ug.gid = psbuf->st_gid;
2120                                 owner_type = GID_ACE;
2121                                 break;
2122                         case SMB_ACL_GROUP:
2123                                 {
2124                                         gid_t *pgid = (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
2125                                         if (pgid == NULL) {
2126                                                 DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
2127                                                 continue;
2128                                         }
2129                                         gid_to_sid( &sid, *pgid);
2130                                         unix_ug.gid = *pgid;
2131                                         owner_type = GID_ACE;
2132                                         SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)pgid,tagtype);
2133                                         break;
2134                                 }
2135                         case SMB_ACL_MASK:
2136                                 acl_mask = convert_permset_to_mode_t(conn, permset);
2137                                 continue; /* Don't count the mask as an entry. */
2138                         case SMB_ACL_OTHER:
2139                                 /* Use the Everyone SID */
2140                                 sid = global_sid_World;
2141                                 unix_ug.world = -1;
2142                                 owner_type = WORLD_ACE;
2143                                 break;
2144                         default:
2145                                 DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype));
2146                                 continue;
2147                 }
2148
2149                 /*
2150                  * Add this entry to the list.
2151                  */
2152
2153                 if ((ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
2154                         goto fail;
2155
2156                 ZERO_STRUCTP(ace);
2157                 ace->type = tagtype;
2158                 ace->perms = convert_permset_to_mode_t(conn, permset);
2159                 ace->attr = ALLOW_ACE;
2160                 ace->trustee = sid;
2161                 ace->unix_ug = unix_ug;
2162                 ace->owner_type = owner_type;
2163                 ace->inherited = get_inherited_flag(pal, ace, (the_acl_type == SMB_ACL_TYPE_DEFAULT));
2164
2165                 DLIST_ADD(list_head, ace);
2166         }
2167
2168         /*
2169          * This next call will ensure we have at least a user/group/world set.
2170          */
2171
2172         if (!ensure_canon_entry_valid(&list_head, fsp, powner, pgroup, psbuf, False))
2173                 goto fail;
2174
2175         /*
2176          * Now go through the list, masking the permissions with the
2177          * acl_mask. Ensure all DENY Entries are at the start of the list.
2178          */
2179
2180         DEBUG(10,("canonicalise_acl: %s ace entries before arrange :\n", the_acl_type == SMB_ACL_TYPE_ACCESS ? "Access" : "Default" ));
2181
2182         for ( ace_count = 0, ace = list_head; ace; ace = next_ace, ace_count++) {
2183                 next_ace = ace->next;
2184
2185                 /* Masks are only applied to entries other than USER_OBJ and OTHER. */
2186                 if (ace->type != SMB_ACL_OTHER && ace->type != SMB_ACL_USER_OBJ)
2187                         ace->perms &= acl_mask;
2188
2189                 if (ace->perms == 0) {
2190                         DLIST_PROMOTE(list_head, ace);
2191                 }
2192
2193                 if( DEBUGLVL( 10 ) ) {
2194                         print_canon_ace(ace, ace_count);
2195                 }
2196         }
2197
2198         arrange_posix_perms(fsp->fsp_name,&list_head );
2199
2200         print_canon_ace_list( "canonicalise_acl: ace entries after arrange", list_head );
2201
2202         return list_head;
2203
2204   fail:
2205
2206         free_canon_ace_list(list_head);
2207         return NULL;
2208 }
2209
2210 /****************************************************************************
2211  Attempt to apply an ACL to a file or directory.
2212 ****************************************************************************/
2213
2214 static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL default_ace, BOOL *pacl_set_support)
2215 {
2216         connection_struct *conn = fsp->conn;
2217         BOOL ret = False;
2218         SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, (int)count_canon_ace_list(the_ace) + 1);
2219         canon_ace *p_ace;
2220         int i;
2221         SMB_ACL_ENTRY_T mask_entry;
2222         BOOL got_mask_entry = False;
2223         SMB_ACL_PERMSET_T mask_permset;
2224         SMB_ACL_TYPE_T the_acl_type = (default_ace ? SMB_ACL_TYPE_DEFAULT : SMB_ACL_TYPE_ACCESS);
2225         BOOL needs_mask = False;
2226         mode_t mask_perms = 0;
2227
2228 #if defined(POSIX_ACL_NEEDS_MASK)
2229         /* HP-UX always wants to have a mask (called "class" there). */
2230         needs_mask = True;
2231 #endif
2232
2233         if (the_acl == NULL) {
2234
2235                 if (errno != ENOSYS) {
2236                         /*
2237                          * Only print this error message if we have some kind of ACL
2238                          * support that's not working. Otherwise we would always get this.
2239                          */
2240                         DEBUG(0,("set_canon_ace_list: Unable to init %s ACL. (%s)\n",
2241                                 default_ace ? "default" : "file", strerror(errno) ));
2242                 }
2243                 *pacl_set_support = False;
2244                 return False;
2245         }
2246
2247         if( DEBUGLVL( 10 )) {
2248                 dbgtext("set_canon_ace_list: setting ACL:\n");
2249                 for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
2250                         print_canon_ace( p_ace, i);
2251                 }
2252         }
2253
2254         for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
2255                 SMB_ACL_ENTRY_T the_entry;
2256                 SMB_ACL_PERMSET_T the_permset;
2257
2258                 /*
2259                  * ACLs only "need" an ACL_MASK entry if there are any named user or
2260                  * named group entries. But if there is an ACL_MASK entry, it applies
2261                  * to ACL_USER, ACL_GROUP, and ACL_GROUP_OBJ entries. Set the mask
2262                  * so that it doesn't deny (i.e., mask off) any permissions.
2263                  */
2264
2265                 if (p_ace->type == SMB_ACL_USER || p_ace->type == SMB_ACL_GROUP) {
2266                         needs_mask = True;
2267                         mask_perms |= p_ace->perms;
2268                 } else if (p_ace->type == SMB_ACL_GROUP_OBJ) {
2269                         mask_perms |= p_ace->perms;
2270                 }
2271
2272                 /*
2273                  * Get the entry for this ACE.
2274                  */
2275
2276                 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) {
2277                         DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n",
2278                                 i, strerror(errno) ));
2279                         goto done;
2280                 }
2281
2282                 if (p_ace->type == SMB_ACL_MASK) {
2283                         mask_entry = the_entry;
2284                         got_mask_entry = True;
2285                 }
2286
2287                 /*
2288                  * Ok - we now know the ACL calls should be working, don't
2289                  * allow fallback to chmod.
2290                  */
2291
2292                 *pacl_set_support = True;
2293
2294                 /*
2295                  * Initialise the entry from the canon_ace.
2296                  */
2297
2298                 /*
2299                  * First tell the entry what type of ACE this is.
2300                  */
2301
2302                 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, p_ace->type) == -1) {
2303                         DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n",
2304                                 i, strerror(errno) ));
2305                         goto done;
2306                 }
2307
2308                 /*
2309                  * Only set the qualifier (user or group id) if the entry is a user
2310                  * or group id ACE.
2311                  */
2312
2313                 if ((p_ace->type == SMB_ACL_USER) || (p_ace->type == SMB_ACL_GROUP)) {
2314                         if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&p_ace->unix_ug.uid) == -1) {
2315                                 DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n",
2316                                         i, strerror(errno) ));
2317                                 goto done;
2318                         }
2319                 }
2320
2321                 /*
2322                  * Convert the mode_t perms in the canon_ace to a POSIX permset.
2323                  */
2324
2325                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) {
2326                         DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n",
2327                                 i, strerror(errno) ));
2328                         goto done;
2329                 }
2330
2331                 if (map_acl_perms_to_permset(conn, p_ace->perms, &the_permset) == -1) {
2332                         DEBUG(0,("set_canon_ace_list: Failed to create permset for mode (%u) on entry %d. (%s)\n",
2333                                 (unsigned int)p_ace->perms, i, strerror(errno) ));
2334                         goto done;
2335                 }
2336
2337                 /*
2338                  * ..and apply them to the entry.
2339                  */
2340
2341                 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) {
2342                         DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n",
2343                                 i, strerror(errno) ));
2344                         goto done;
2345                 }
2346
2347                 if( DEBUGLVL( 10 ))
2348                         print_canon_ace( p_ace, i);
2349
2350         }
2351
2352         if (needs_mask && !got_mask_entry) {
2353                 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &mask_entry) == -1) {
2354                         DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) ));
2355                         goto done;
2356                 }
2357
2358                 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, mask_entry, SMB_ACL_MASK) == -1) {
2359                         DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno) ));
2360                         goto done;
2361                 }
2362
2363                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, mask_entry, &mask_permset) == -1) {
2364                         DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) ));
2365                         goto done;
2366                 }
2367
2368                 if (map_acl_perms_to_permset(conn, S_IRUSR|S_IWUSR|S_IXUSR, &mask_permset) == -1) {
2369                         DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno) ));
2370                         goto done;
2371                 }
2372
2373                 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, mask_entry, mask_permset) == -1) {
2374                         DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) ));
2375                         goto done;
2376                 }
2377         }
2378
2379         /*
2380          * Check if the ACL is valid.
2381          */
2382
2383         if (SMB_VFS_SYS_ACL_VALID(conn, the_acl) == -1) {
2384                 DEBUG(0,("set_canon_ace_list: ACL type (%s) is invalid for set (%s).\n",
2385                                 the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
2386                                 strerror(errno) ));
2387                 goto done;
2388         }
2389
2390         /*
2391          * Finally apply it to the file or directory.
2392          */
2393
2394         if(default_ace || fsp->is_directory || fsp->fd == -1) {
2395                 if (SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name, the_acl_type, the_acl) == -1) {
2396                         /*
2397                          * Some systems allow all the above calls and only fail with no ACL support
2398                          * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
2399                          */
2400                         if (errno == ENOSYS)
2401                                 *pacl_set_support = False;
2402
2403 #ifdef ENOTSUP
2404                         if (errno == ENOTSUP)
2405                                 *pacl_set_support = False;
2406 #endif
2407
2408                         DEBUG(2,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n",
2409                                         the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
2410                                         fsp->fsp_name, strerror(errno) ));
2411                         goto done;
2412                 }
2413         } else {
2414                 if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fd, the_acl) == -1) {
2415                         /*
2416                          * Some systems allow all the above calls and only fail with no ACL support
2417                          * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
2418                          */
2419                         if (errno == ENOSYS)
2420                                 *pacl_set_support = False;
2421
2422 #ifdef ENOTSUP
2423                         if (errno == ENOTSUP)
2424                                 *pacl_set_support = False;
2425 #endif
2426
2427                         DEBUG(2,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n",
2428                                         fsp->fsp_name, strerror(errno) ));
2429                         goto done;
2430                 }
2431         }
2432
2433         ret = True;
2434
2435   done:
2436
2437         if (the_acl != NULL)
2438             SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
2439
2440         return ret;
2441 }
2442
2443 /****************************************************************************
2444  Find a particular canon_ace entry.
2445 ****************************************************************************/
2446
2447 static struct canon_ace *canon_ace_entry_for(struct canon_ace *list, SMB_ACL_TAG_T type, posix_id *id)
2448 {
2449         while (list) {
2450                 if (list->type == type && ((type != SMB_ACL_USER && type != SMB_ACL_GROUP) ||
2451                                 (type == SMB_ACL_USER  && id && id->uid == list->unix_ug.uid) ||
2452                                 (type == SMB_ACL_GROUP && id && id->gid == list->unix_ug.gid)))
2453                         break;
2454                 list = list->next;
2455         }
2456         return list;
2457 }
2458
2459 /****************************************************************************
2460  
2461 ****************************************************************************/
2462
2463 SMB_ACL_T free_empty_sys_acl(connection_struct *conn, SMB_ACL_T the_acl)
2464 {
2465         SMB_ACL_ENTRY_T entry;
2466
2467         if (!the_acl)
2468                 return NULL;
2469         if (SMB_VFS_SYS_ACL_GET_ENTRY(conn, the_acl, SMB_ACL_FIRST_ENTRY, &entry) != 1) {
2470                 SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
2471                 return NULL;
2472         }
2473         return the_acl;
2474 }
2475
2476 /****************************************************************************
2477  Convert a canon_ace to a generic 3 element permission - if possible.
2478 ****************************************************************************/
2479
2480 #define MAP_PERM(p,mask,result) (((p) & (mask)) ? (result) : 0 )
2481
2482 static BOOL convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file_ace_list, mode_t *posix_perms)
2483 {
2484         int snum = SNUM(fsp->conn);
2485         size_t ace_count = count_canon_ace_list(file_ace_list);
2486         canon_ace *ace_p;
2487         canon_ace *owner_ace = NULL;
2488         canon_ace *group_ace = NULL;
2489         canon_ace *other_ace = NULL;
2490         mode_t and_bits;
2491         mode_t or_bits;
2492
2493         if (ace_count != 3) {
2494                 DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE entries for file %s to convert to \
2495 posix perms.\n", fsp->fsp_name ));
2496                 return False;
2497         }
2498
2499         for (ace_p = file_ace_list; ace_p; ace_p = ace_p->next) {
2500                 if (ace_p->owner_type == UID_ACE)
2501                         owner_ace = ace_p;
2502                 else if (ace_p->owner_type == GID_ACE)
2503                         group_ace = ace_p;
2504                 else if (ace_p->owner_type == WORLD_ACE)
2505                         other_ace = ace_p;
2506         }
2507
2508         if (!owner_ace || !group_ace || !other_ace) {
2509                 DEBUG(3,("convert_canon_ace_to_posix_perms: Can't get standard entries for file %s.\n",
2510                                 fsp->fsp_name ));
2511                 return False;
2512         }
2513
2514         *posix_perms = (mode_t)0;
2515
2516         *posix_perms |= owner_ace->perms;
2517         *posix_perms |= MAP_PERM(group_ace->perms, S_IRUSR, S_IRGRP);
2518         *posix_perms |= MAP_PERM(group_ace->perms, S_IWUSR, S_IWGRP);
2519         *posix_perms |= MAP_PERM(group_ace->perms, S_IXUSR, S_IXGRP);
2520         *posix_perms |= MAP_PERM(other_ace->perms, S_IRUSR, S_IROTH);
2521         *posix_perms |= MAP_PERM(other_ace->perms, S_IWUSR, S_IWOTH);
2522         *posix_perms |= MAP_PERM(other_ace->perms, S_IXUSR, S_IXOTH);
2523
2524         /* The owner must have at least read access. */
2525
2526         *posix_perms |= S_IRUSR;
2527         if (fsp->is_directory)
2528                 *posix_perms |= (S_IWUSR|S_IXUSR);
2529
2530         /* If requested apply the masks. */
2531
2532         /* Get the initial bits to apply. */
2533
2534         if (fsp->is_directory) {
2535                 and_bits = lp_dir_security_mask(snum);
2536                 or_bits = lp_force_dir_security_mode(snum);
2537         } else {
2538                 and_bits = lp_security_mask(snum);
2539                 or_bits = lp_force_security_mode(snum);
2540         }
2541
2542         *posix_perms = (((*posix_perms) & and_bits)|or_bits);
2543
2544         DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o to perm=0%o for file %s.\n",
2545                 (int)owner_ace->perms, (int)group_ace->perms, (int)other_ace->perms, (int)*posix_perms,
2546                 fsp->fsp_name ));
2547
2548         return True;
2549 }
2550
2551 static int nt_ace_comp( SEC_ACE *a1, SEC_ACE *a2)
2552 {
2553         if (a1->type == a2->type)
2554                 return 0;
2555
2556         if (a1->type == SEC_ACE_TYPE_ACCESS_DENIED && a2->type == SEC_ACE_TYPE_ACCESS_ALLOWED)
2557                 return -1;
2558         return 1;
2559 }
2560
2561 /****************************************************************************
2562   Incoming NT ACLs on a directory can be split into a default POSIX acl (CI|OI|IO) and
2563   a normal POSIX acl. Win2k needs these split acls re-merging into one ACL
2564   with CI|OI set so it is inherited and also applies to the directory.
2565   Based on code from "Jim McDonough" <jmcd@us.ibm.com>.
2566 ****************************************************************************/
2567
2568 static size_t merge_default_aces( SEC_ACE *nt_ace_list, size_t num_aces)
2569 {
2570         size_t i, j;
2571
2572         for (i = 0; i < num_aces; i++) {
2573                 for (j = i+1; j < num_aces; j++) {
2574                         uint32 i_flags_ni = (nt_ace_list[i].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
2575                         uint32 j_flags_ni = (nt_ace_list[j].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
2576                         BOOL i_inh = (nt_ace_list[i].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
2577                         BOOL j_inh = (nt_ace_list[j].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
2578
2579                         /* We know the lower number ACE's are file entries. */
2580                         if ((nt_ace_list[i].type == nt_ace_list[j].type) &&
2581                                 (nt_ace_list[i].size == nt_ace_list[j].size) &&
2582                                 (nt_ace_list[i].info.mask == nt_ace_list[j].info.mask) &&
2583                                 sid_equal(&nt_ace_list[i].trustee, &nt_ace_list[j].trustee) &&
2584                                 (i_inh == j_inh) &&
2585                                 (i_flags_ni == 0) &&
2586                                 (j_flags_ni == (SEC_ACE_FLAG_OBJECT_INHERIT|
2587                                                   SEC_ACE_FLAG_CONTAINER_INHERIT|
2588                                                   SEC_ACE_FLAG_INHERIT_ONLY))) {
2589                                 /*
2590                                  * W2K wants to have access allowed zero access ACE's
2591                                  * at the end of the list. If the mask is zero, merge
2592                                  * the non-inherited ACE onto the inherited ACE.
2593                                  */
2594
2595                                 if (nt_ace_list[i].info.mask == 0) {
2596                                         nt_ace_list[j].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2597                                                                 (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2598                                         if (num_aces - i - 1 > 0)
2599                                                 memmove(&nt_ace_list[i], &nt_ace_list[i+1], (num_aces-i-1) *
2600                                                                 sizeof(SEC_ACE));
2601
2602                                         DEBUG(10,("merge_default_aces: Merging zero access ACE %u onto ACE %u.\n",
2603                                                 (unsigned int)i, (unsigned int)j ));
2604                                 } else {
2605                                         /*
2606                                          * These are identical except for the flags.
2607                                          * Merge the inherited ACE onto the non-inherited ACE.
2608                                          */
2609
2610                                         nt_ace_list[i].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2611                                                                 (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2612                                         if (num_aces - j - 1 > 0)
2613                                                 memmove(&nt_ace_list[j], &nt_ace_list[j+1], (num_aces-j-1) *
2614                                                                 sizeof(SEC_ACE));
2615
2616                                         DEBUG(10,("merge_default_aces: Merging ACE %u onto ACE %u.\n",
2617                                                 (unsigned int)j, (unsigned int)i ));
2618                                 }
2619                                 num_aces--;
2620                                 break;
2621                         }
2622                 }
2623         }
2624
2625         return num_aces;
2626 }
2627 /****************************************************************************
2628  Reply to query a security descriptor from an fsp. If it succeeds it allocates
2629  the space for the return elements and returns the size needed to return the
2630  security descriptor. This should be the only external function needed for
2631  the UNIX style get ACL.
2632 ****************************************************************************/
2633
2634 size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc)
2635 {
2636         extern DOM_SID global_sid_Builtin_Administrators;
2637         extern DOM_SID global_sid_Builtin_Users;
2638         extern DOM_SID global_sid_Creator_Owner;
2639         extern DOM_SID global_sid_Creator_Group;
2640         connection_struct *conn = fsp->conn;
2641         SMB_STRUCT_STAT sbuf;
2642         SEC_ACE *nt_ace_list = NULL;
2643         DOM_SID owner_sid;
2644         DOM_SID group_sid;
2645         size_t sd_size = 0;
2646         SEC_ACL *psa = NULL;
2647         size_t num_acls = 0;
2648         size_t num_dir_acls = 0;
2649         size_t num_aces = 0;
2650         SMB_ACL_T posix_acl = NULL;
2651         SMB_ACL_T dir_acl = NULL;
2652         canon_ace *file_ace = NULL;
2653         canon_ace *dir_ace = NULL;
2654         size_t num_profile_acls = 0;
2655         struct pai_val *pal = NULL;
2656  
2657         *ppdesc = NULL;
2658
2659         DEBUG(10,("get_nt_acl: called for file %s\n", fsp->fsp_name ));
2660
2661         if(fsp->is_directory || fsp->fd == -1) {
2662
2663                 /* Get the stat struct for the owner info. */
2664                 if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) {
2665                         return 0;
2666                 }
2667                 /*
2668                  * Get the ACL from the path.
2669                  */
2670
2671                 posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_ACCESS);
2672
2673                 /*
2674                  * If it's a directory get the default POSIX ACL.
2675                  */
2676
2677                 if(fsp->is_directory) {
2678                         dir_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_DEFAULT);
2679                         dir_acl = free_empty_sys_acl(conn, dir_acl);
2680                 }
2681
2682         } else {
2683
2684                 /* Get the stat struct for the owner info. */
2685                 if(SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0) {
2686                         return 0;
2687                 }
2688                 /*
2689                  * Get the ACL from the fd.
2690                  */
2691                 posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fd);
2692         }
2693
2694         DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n",
2695                         posix_acl ? "present" :  "absent",
2696                         dir_acl ? "present" :  "absent" ));
2697
2698         pal = load_inherited_info(fsp);
2699
2700         /*
2701          * Get the owner, group and world SIDs.
2702          */
2703
2704         if (lp_profile_acls(SNUM(fsp->conn))) {
2705                 /* For WXP SP1 the owner must be administrators. */
2706                 sid_copy(&owner_sid, &global_sid_Builtin_Administrators);
2707                 sid_copy(&group_sid, &global_sid_Builtin_Users);
2708                 num_profile_acls = 2;
2709         } else {
2710                 create_file_sids(&sbuf, &owner_sid, &group_sid);
2711         }
2712
2713         if ((security_info & DACL_SECURITY_INFORMATION) && !(security_info & PROTECTED_DACL_SECURITY_INFORMATION)) {
2714
2715                 /*
2716                  * In the optimum case Creator Owner and Creator Group would be used for
2717                  * the ACL_USER_OBJ and ACL_GROUP_OBJ entries, respectively, but this
2718                  * would lead to usability problems under Windows: The Creator entries
2719                  * are only available in browse lists of directories and not for files;
2720                  * additionally the identity of the owning group couldn't be determined.
2721                  * We therefore use those identities only for Default ACLs. 
2722                  */
2723
2724                 /* Create the canon_ace lists. */
2725                 file_ace = canonicalise_acl( fsp, posix_acl, &sbuf, &owner_sid, &group_sid, pal, SMB_ACL_TYPE_ACCESS );
2726
2727                 /* We must have *some* ACLS. */
2728         
2729                 if (count_canon_ace_list(file_ace) == 0) {
2730                         DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", fsp->fsp_name ));
2731                         return 0;
2732                 }
2733
2734                 if (fsp->is_directory && dir_acl) {
2735                         dir_ace = canonicalise_acl(fsp, dir_acl, &sbuf,
2736                                         &global_sid_Creator_Owner,
2737                                         &global_sid_Creator_Group, pal, SMB_ACL_TYPE_DEFAULT );
2738                 }
2739
2740                 /*
2741                  * Create the NT ACE list from the canonical ace lists.
2742                  */
2743
2744                 {
2745                         canon_ace *ace;
2746                         int nt_acl_type;
2747                         int i;
2748
2749                         if (nt4_compatible_acls() && dir_ace) {
2750                                 /*
2751                                  * NT 4 chokes if an ACL contains an INHERIT_ONLY entry
2752                                  * but no non-INHERIT_ONLY entry for one SID. So we only
2753                                  * remove entries from the Access ACL if the
2754                                  * corresponding Default ACL entries have also been
2755                                  * removed. ACEs for CREATOR-OWNER and CREATOR-GROUP
2756                                  * are exceptions. We can do nothing
2757                                  * intelligent if the Default ACL contains entries that
2758                                  * are not also contained in the Access ACL, so this
2759                                  * case will still fail under NT 4.
2760                                  */
2761
2762                                 ace = canon_ace_entry_for(dir_ace, SMB_ACL_OTHER, NULL);
2763                                 if (ace && !ace->perms) {
2764                                         DLIST_REMOVE(dir_ace, ace);
2765                                         SAFE_FREE(ace);
2766
2767                                         ace = canon_ace_entry_for(file_ace, SMB_ACL_OTHER, NULL);
2768                                         if (ace && !ace->perms) {
2769                                                 DLIST_REMOVE(file_ace, ace);
2770                                                 SAFE_FREE(ace);
2771                                         }
2772                                 }
2773
2774                                 /*
2775                                  * WinNT doesn't usually have Creator Group
2776                                  * in browse lists, so we send this entry to
2777                                  * WinNT even if it contains no relevant
2778                                  * permissions. Once we can add
2779                                  * Creator Group to browse lists we can
2780                                  * re-enable this.
2781                                  */
2782
2783 #if 0
2784                                 ace = canon_ace_entry_for(dir_ace, SMB_ACL_GROUP_OBJ, NULL);
2785                                 if (ace && !ace->perms) {
2786                                         DLIST_REMOVE(dir_ace, ace);
2787                                         SAFE_FREE(ace);
2788                                 }
2789 #endif
2790
2791                                 ace = canon_ace_entry_for(file_ace, SMB_ACL_GROUP_OBJ, NULL);
2792                                 if (ace && !ace->perms) {
2793                                         DLIST_REMOVE(file_ace, ace);
2794                                         SAFE_FREE(ace);
2795                                 }
2796                         }
2797
2798                         num_acls = count_canon_ace_list(file_ace);
2799                         num_dir_acls = count_canon_ace_list(dir_ace);
2800
2801                         /* Allocate the ace list. */
2802                         if ((nt_ace_list = (SEC_ACE *)malloc((num_acls + num_profile_acls + num_dir_acls)* sizeof(SEC_ACE))) == NULL) {
2803                                 DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
2804                                 goto done;
2805                         }
2806
2807                         memset(nt_ace_list, '\0', (num_acls + num_dir_acls) * sizeof(SEC_ACE) );
2808                                                                                                         
2809                         /*
2810                          * Create the NT ACE list from the canonical ace lists.
2811                          */
2812         
2813                         ace = file_ace;
2814
2815                         for (i = 0; i < num_acls; i++, ace = ace->next) {
2816                                 SEC_ACCESS acc;
2817
2818                                 acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
2819                                 init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc, ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2820                         }
2821
2822                         /* The User must have access to a profile share - even if we can't map the SID. */
2823                         if (lp_profile_acls(SNUM(fsp->conn))) {
2824                                 SEC_ACCESS acc;
2825
2826                                 init_sec_access(&acc,FILE_GENERIC_ALL);
2827                                 init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED,
2828                                                 acc, 0);
2829                         }
2830
2831                         ace = dir_ace;
2832
2833                         for (i = 0; i < num_dir_acls; i++, ace = ace->next) {
2834                                 SEC_ACCESS acc;
2835         
2836                                 acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
2837                                 init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc,
2838                                                 SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2839                                                 SEC_ACE_FLAG_INHERIT_ONLY|
2840                                                 (ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 0));
2841                         }
2842
2843                         /* The User must have access to a profile share - even if we can't map the SID. */
2844                         if (lp_profile_acls(SNUM(fsp->conn))) {
2845                                 SEC_ACCESS acc;
2846                         
2847                                 init_sec_access(&acc,FILE_GENERIC_ALL);
2848                                 init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, acc,
2849                                                 SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2850                                                 SEC_ACE_FLAG_INHERIT_ONLY|0);
2851                         }
2852
2853                         /*
2854                          * Merge POSIX default ACLs and normal ACLs into one NT ACE.
2855                          * Win2K needs this to get the inheritance correct when replacing ACLs
2856                          * on a directory tree. Based on work by Jim @ IBM.
2857                          */
2858
2859                         num_aces = merge_default_aces(nt_ace_list, num_aces);
2860
2861                         /*
2862                          * Sort to force deny entries to the front.
2863                          */
2864         
2865                         if (num_aces)
2866                                 qsort( nt_ace_list, num_aces, sizeof(nt_ace_list[0]), QSORT_CAST nt_ace_comp);
2867                 }
2868
2869                 if (num_aces) {
2870                         if((psa = make_sec_acl( main_loop_talloc_get(), ACL_REVISION, num_aces, nt_ace_list)) == NULL) {
2871                                 DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
2872                                 goto done;
2873                         }
2874                 }
2875         } /* security_info & DACL_SECURITY_INFORMATION */
2876
2877         *ppdesc = make_standard_sec_desc( main_loop_talloc_get(),
2878                         (security_info & OWNER_SECURITY_INFORMATION) ? &owner_sid : NULL,
2879                         (security_info & GROUP_SECURITY_INFORMATION) ? &group_sid : NULL,
2880                         psa,
2881                         &sd_size);
2882
2883         if(!*ppdesc) {
2884                 DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
2885                 sd_size = 0;
2886         } else {
2887                 /*
2888                  * Windows 2000: The DACL_PROTECTED flag in the security
2889                  * descriptor marks the ACL as non-inheriting, i.e., no
2890                  * ACEs from higher level directories propagate to this
2891                  * ACL. In the POSIX ACL model permissions are only
2892                  * inherited at file create time, so ACLs never contain
2893                  * any ACEs that are inherited dynamically. The DACL_PROTECTED
2894                  * flag doesn't seem to bother Windows NT.
2895                  */
2896                 if (get_protected_flag(pal))
2897                         (*ppdesc)->type |= SE_DESC_DACL_PROTECTED;
2898         }
2899
2900  done:
2901
2902         if (posix_acl)
2903                 SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
2904         if (dir_acl)
2905                 SMB_VFS_SYS_ACL_FREE_ACL(conn, dir_acl);
2906         free_canon_ace_list(file_ace);
2907         free_canon_ace_list(dir_ace);
2908         free_inherited_info(pal);
2909         SAFE_FREE(nt_ace_list);
2910
2911         return sd_size;
2912 }
2913
2914 /****************************************************************************
2915  Try to chown a file. We will be able to chown it under the following conditions.
2916
2917   1) If we have root privileges, then it will just work.
2918   2) If we have write permission to the file and dos_filemodes is set
2919      then allow chown to the currently authenticated user.
2920 ****************************************************************************/
2921
2922 static int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid)
2923 {
2924         int ret;
2925         extern struct current_user current_user;
2926         files_struct *fsp;
2927         SMB_STRUCT_STAT st;
2928
2929         /* try the direct way first */
2930         ret = SMB_VFS_CHOWN(conn, fname, uid, gid);
2931         if (ret == 0)
2932                 return 0;
2933
2934         if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
2935                 return -1;
2936
2937         if (SMB_VFS_STAT(conn,fname,&st))
2938                 return -1;
2939
2940         fsp = open_file_fchmod(conn,fname,&st);
2941         if (!fsp)
2942                 return -1;
2943
2944         /* only allow chown to the current user. This is more secure,
2945            and also copes with the case where the SID in a take ownership ACL is
2946            a local SID on the users workstation 
2947         */
2948         uid = current_user.uid;
2949
2950         become_root();
2951         /* Keep the current file gid the same. */
2952         ret = SMB_VFS_FCHOWN(fsp, fsp->fd, uid, (gid_t)-1);
2953         unbecome_root();
2954
2955         close_file_fchmod(fsp);
2956
2957         return ret;
2958 }
2959
2960 /****************************************************************************
2961  Reply to set a security descriptor on an fsp. security_info_sent is the
2962  description of the following NT ACL.
2963  This should be the only external function needed for the UNIX style set ACL.
2964 ****************************************************************************/
2965
2966 BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
2967 {
2968         connection_struct *conn = fsp->conn;
2969         uid_t user = (uid_t)-1;
2970         gid_t grp = (gid_t)-1;
2971         SMB_STRUCT_STAT sbuf;  
2972         DOM_SID file_owner_sid;
2973         DOM_SID file_grp_sid;
2974         canon_ace *file_ace_list = NULL;
2975         canon_ace *dir_ace_list = NULL;
2976         BOOL acl_perms = False;
2977         mode_t orig_mode = (mode_t)0;
2978         uid_t orig_uid;
2979         gid_t orig_gid;
2980         BOOL need_chown = False;
2981         extern struct current_user current_user;
2982
2983         DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name ));
2984
2985         if (!CAN_WRITE(conn)) {
2986                 DEBUG(10,("set acl rejected on read-only share\n"));
2987                 return False;
2988         }
2989
2990         /*
2991          * Get the current state of the file.
2992          */
2993
2994         if(fsp->is_directory || fsp->fd == -1) {
2995                 if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0)
2996                         return False;
2997         } else {
2998                 if(SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0)
2999                         return False;
3000         }
3001
3002         /* Save the original elements we check against. */
3003         orig_mode = sbuf.st_mode;
3004         orig_uid = sbuf.st_uid;
3005         orig_gid = sbuf.st_gid;
3006
3007         /*
3008          * Unpack the user/group/world id's.
3009          */
3010
3011         if (!unpack_nt_owners( &sbuf, &user, &grp, security_info_sent, psd))
3012                 return False;
3013
3014         /*
3015          * Do we need to chown ?
3016          */
3017
3018         if (((user != (uid_t)-1) && (orig_uid != user)) || (( grp != (gid_t)-1) && (orig_gid != grp)))
3019                 need_chown = True;
3020
3021         /*
3022          * Chown before setting ACL only if we don't change the user, or
3023          * if we change to the current user, but not if we want to give away
3024          * the file.
3025          */
3026
3027         if (need_chown && (user == (uid_t)-1 || user == current_user.uid)) {
3028
3029                 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
3030                                 fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
3031
3032                 if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
3033                         DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
3034                                 fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
3035                         return False;
3036                 }
3037
3038                 /*
3039                  * Recheck the current state of the file, which may have changed.
3040                  * (suid/sgid bits, for instance)
3041                  */
3042
3043                 if(fsp->is_directory) {
3044                         if(SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf) != 0) {
3045                                 return False;
3046                         }
3047                 } else {
3048
3049                         int ret;
3050     
3051                         if(fsp->fd == -1)
3052                                 ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf);
3053                         else
3054                                 ret = SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf);
3055   
3056                         if(ret != 0)
3057                                 return False;
3058                 }
3059
3060                 /* Save the original elements we check against. */
3061                 orig_mode = sbuf.st_mode;
3062                 orig_uid = sbuf.st_uid;
3063                 orig_gid = sbuf.st_gid;
3064
3065                 /* We did it, don't try again */
3066                 need_chown = False;
3067         }
3068
3069         create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid);
3070
3071         acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid,
3072                                                                         &file_ace_list, &dir_ace_list, security_info_sent, psd);
3073
3074         /* Ignore W2K traverse DACL set. */
3075         if (file_ace_list || dir_ace_list) {
3076
3077                 if (!acl_perms) {
3078                         DEBUG(3,("set_nt_acl: cannot set permissions\n"));
3079                         free_canon_ace_list(file_ace_list);
3080                         free_canon_ace_list(dir_ace_list); 
3081                         return False;
3082                 }
3083
3084                 /*
3085                  * Only change security if we got a DACL.
3086                  */
3087
3088                 if((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl != NULL)) {
3089
3090                         BOOL acl_set_support = False;
3091                         BOOL ret = False;
3092
3093                         /*
3094                          * Try using the POSIX ACL set first. Fall back to chmod if
3095                          * we have no ACL support on this filesystem.
3096                          */
3097
3098                         if (acl_perms && file_ace_list) {
3099                                 ret = set_canon_ace_list(fsp, file_ace_list, False, &acl_set_support);
3100                                 if (acl_set_support && ret == False) {
3101                                         DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) ));
3102                                         free_canon_ace_list(file_ace_list);
3103                                         free_canon_ace_list(dir_ace_list); 
3104                                         return False;
3105                                 }
3106                         }
3107
3108                         if (acl_perms && acl_set_support && fsp->is_directory) {
3109                                 if (dir_ace_list) {
3110                                         if (!set_canon_ace_list(fsp, dir_ace_list, True, &acl_set_support)) {
3111                                                 DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) ));
3112                                                 free_canon_ace_list(file_ace_list);
3113                                                 free_canon_ace_list(dir_ace_list); 
3114                                                 return False;
3115                                         }
3116                                 } else {
3117
3118                                         /*
3119                                          * No default ACL - delete one if it exists.
3120                                          */
3121
3122                                         if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name) == -1) {
3123                                                 DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno)));
3124                                                 free_canon_ace_list(file_ace_list);
3125                                                 free_canon_ace_list(dir_ace_list);
3126                                                 return False;
3127                                         }
3128                                 }
3129                         }
3130
3131                         if (acl_set_support)
3132                                 store_inheritance_attributes(fsp, file_ace_list, dir_ace_list,
3133                                                 (psd->type & SE_DESC_DACL_PROTECTED) ? True : False);
3134
3135                         /*
3136                          * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
3137                          */
3138
3139                         if(!acl_set_support && acl_perms) {
3140                                 mode_t posix_perms;
3141
3142                                 if (!convert_canon_ace_to_posix_perms( fsp, file_ace_list, &posix_perms)) {
3143                                         free_canon_ace_list(file_ace_list);
3144                                         free_canon_ace_list(dir_ace_list);
3145                                         DEBUG(3,("set_nt_acl: failed to convert file acl to posix permissions for file %s.\n",
3146                                                 fsp->fsp_name ));
3147                                         return False;
3148                                 }
3149
3150                                 if (orig_mode != posix_perms) {
3151
3152                                         DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
3153                                                 fsp->fsp_name, (unsigned int)posix_perms ));
3154
3155                                         if(SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms) == -1) {
3156                                                 DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n",
3157                                                                 fsp->fsp_name, (unsigned int)posix_perms, strerror(errno) ));
3158                                                 free_canon_ace_list(file_ace_list);
3159                                                 free_canon_ace_list(dir_ace_list);
3160                                                 return False;
3161                                         }
3162                                 }
3163                         }
3164                 }
3165
3166                 free_canon_ace_list(file_ace_list);
3167                 free_canon_ace_list(dir_ace_list); 
3168         }
3169
3170         /* Any chown pending? */
3171         if (need_chown) {
3172
3173                 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
3174                         fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
3175
3176                 if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
3177                         DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
3178                                 fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
3179                         return False;
3180                 }
3181         }
3182
3183         return True;
3184 }
3185
3186 /****************************************************************************
3187  Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3188  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3189 ****************************************************************************/
3190
3191 static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mode_t mode)
3192 {
3193         int entry_id = SMB_ACL_FIRST_ENTRY;
3194         SMB_ACL_ENTRY_T entry;
3195         int num_entries = 0;
3196
3197         while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
3198                 SMB_ACL_TAG_T tagtype;
3199                 SMB_ACL_PERMSET_T permset;
3200                 mode_t perms;
3201
3202                 /* get_next... */
3203                 if (entry_id == SMB_ACL_FIRST_ENTRY)
3204                         entry_id = SMB_ACL_NEXT_ENTRY;
3205
3206                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
3207                         return -1;
3208
3209                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
3210                         return -1;
3211
3212                 num_entries++;
3213
3214                 switch(tagtype) {
3215                         case SMB_ACL_USER_OBJ:
3216                                 perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
3217                                 break;
3218                         case SMB_ACL_GROUP_OBJ:
3219                                 perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
3220                                 break;
3221                         case SMB_ACL_MASK:
3222                                 /*
3223                                  * FIXME: The ACL_MASK entry permissions should really be set to
3224                                  * the union of the permissions of all ACL_USER,
3225                                  * ACL_GROUP_OBJ, and ACL_GROUP entries. That's what
3226                                  * acl_calc_mask() does, but Samba ACLs doesn't provide it.
3227                                  */
3228                                 perms = S_IRUSR|S_IWUSR|S_IXUSR;
3229                                 break;
3230                         case SMB_ACL_OTHER:
3231                                 perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
3232                                 break;
3233                         default:
3234                                 continue;
3235                 }
3236
3237                 if (map_acl_perms_to_permset(conn, perms, &permset) == -1)
3238                         return -1;
3239
3240                 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, entry, permset) == -1)
3241                         return -1;
3242         }
3243
3244         /*
3245          * If this is a simple 3 element ACL or no elements then it's a standard
3246          * UNIX permission set. Just use chmod...       
3247          */
3248
3249         if ((num_entries == 3) || (num_entries == 0))
3250                 return -1;
3251
3252         return 0;
3253 }
3254
3255 /****************************************************************************
3256  Get the access ACL of FROM, do a chmod by setting the ACL USER_OBJ,
3257  GROUP_OBJ and OTHER bits in an ACL and set the mask to rwx. Set the
3258  resulting ACL on TO.  Note that name is in UNIX character set.
3259 ****************************************************************************/
3260
3261 static int copy_access_acl(connection_struct *conn, const char *from, const char *to, mode_t mode)
3262 {
3263         SMB_ACL_T posix_acl = NULL;
3264         int ret = -1;
3265
3266         if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, from, SMB_ACL_TYPE_ACCESS)) == NULL)
3267                 return -1;
3268
3269         if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
3270                 goto done;
3271
3272         ret = SMB_VFS_SYS_ACL_SET_FILE(conn, to, SMB_ACL_TYPE_ACCESS, posix_acl);
3273
3274  done:
3275
3276         SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
3277         return ret;
3278 }
3279
3280 /****************************************************************************
3281  Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3282  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3283  Note that name is in UNIX character set.
3284 ****************************************************************************/
3285
3286 int chmod_acl(connection_struct *conn, const char *name, mode_t mode)
3287 {
3288         return copy_access_acl(conn, name, name, mode);
3289 }
3290
3291 /****************************************************************************
3292  If "inherit permissions" is set and the parent directory has no default
3293  ACL but it does have an Access ACL, inherit this Access ACL to file name.
3294 ****************************************************************************/
3295
3296 int inherit_access_acl(connection_struct *conn, const char *name, mode_t mode)
3297 {
3298         pstring dirname;
3299         pstrcpy(dirname, parent_dirname(name));
3300
3301         if (!lp_inherit_perms(SNUM(conn)) || directory_has_default_acl(conn, dirname))
3302                 return 0;
3303
3304         return copy_access_acl(conn, dirname, name, mode);
3305 }
3306
3307 /****************************************************************************
3308  Do an fchmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3309  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3310 ****************************************************************************/
3311
3312 int fchmod_acl(files_struct *fsp, int fd, mode_t mode)
3313 {
3314         connection_struct *conn = fsp->conn;
3315         SMB_ACL_T posix_acl = NULL;
3316         int ret = -1;
3317
3318         if ((posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fd)) == NULL)
3319                 return -1;
3320
3321         if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
3322                 goto done;
3323
3324         ret = SMB_VFS_SYS_ACL_SET_FD(fsp, fd, posix_acl);
3325
3326   done:
3327
3328         SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
3329         return ret;
3330 }
3331
3332 /****************************************************************************
3333  Check for an existing default POSIX ACL on a directory.
3334 ****************************************************************************/
3335
3336 BOOL directory_has_default_acl(connection_struct *conn, const char *fname)
3337 {
3338         SMB_ACL_T dir_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_DEFAULT);
3339         BOOL has_acl = False;
3340         SMB_ACL_ENTRY_T entry;
3341
3342         if (dir_acl != NULL && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, dir_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1))
3343                 has_acl = True;
3344
3345         if (dir_acl)
3346                 SMB_VFS_SYS_ACL_FREE_ACL(conn, dir_acl);
3347         return has_acl;
3348 }