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