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