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