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