r9293: Fix error path memory leak bug found by Coverity - also potential NULL
[obnox/samba/samba-obnox.git] / source / smbd / posix_acls.c
1 /*
2    Unix SMB/CIFS implementation.
3    SMB NT Security Descriptor / Unix permission conversion.
4    Copyright (C) Jeremy Allison 1994-2000.
5    Copyright (C) Andreas Gruenbacher 2002.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 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 pai_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 pai_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,(pai_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 pai_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 (!pai_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->fh->fd != -1)
233                         SMB_VFS_FREMOVEXATTR(fsp, fsp->fh->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, pai_protected, &store_size);
240
241         if (fsp->fh->fd != -1)
242                 ret = SMB_VFS_FSETXATTR(fsp, fsp->fh->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", pai_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->pai_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->pai_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->pai_protected ? " (pai_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->fh->fd != -1)
449                         ret = SMB_VFS_FGETXATTR(fsp, fsp->fh->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->pai_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 snum, 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 (lp_acl_map_full_control(snum) && ((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
1064         for (pace = *pp_ace; pace; pace = pace->next) {
1065                 if (pace->type == SMB_ACL_USER_OBJ) {
1066
1067                         if (setting_acl)
1068                                 apply_default_perms(fsp, pace, S_IRUSR);
1069                         got_user = True;
1070
1071                 } else if (pace->type == SMB_ACL_GROUP_OBJ) {
1072
1073                         /*
1074                          * Ensure create mask/force create mode is respected on set.
1075                          */
1076
1077                         if (setting_acl)
1078                                 apply_default_perms(fsp, pace, S_IRGRP);
1079                         got_grp = True;
1080
1081                 } else if (pace->type == SMB_ACL_OTHER) {
1082
1083                         /*
1084                          * Ensure create mask/force create mode is respected on set.
1085                          */
1086
1087                         if (setting_acl)
1088                                 apply_default_perms(fsp, pace, S_IROTH);
1089                         got_other = True;
1090                         pace_other = pace;
1091                 }
1092         }
1093
1094         if (!got_user) {
1095                 if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) {
1096                         DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
1097                         return False;
1098                 }
1099
1100                 ZERO_STRUCTP(pace);
1101                 pace->type = SMB_ACL_USER_OBJ;
1102                 pace->owner_type = UID_ACE;
1103                 pace->unix_ug.uid = pst->st_uid;
1104                 pace->trustee = *pfile_owner_sid;
1105                 pace->attr = ALLOW_ACE;
1106
1107                 if (setting_acl) {
1108                         /* See if the owning user is in any of the other groups in
1109                            the ACE. If so, OR in the permissions from that group. */
1110
1111                         BOOL group_matched = False;
1112                         canon_ace *pace_iter;
1113
1114                         for (pace_iter = *pp_ace; pace_iter; pace_iter = pace_iter->next) {
1115                                 if (pace_iter->type == SMB_ACL_GROUP_OBJ || pace_iter->type == SMB_ACL_GROUP) {
1116                                         if (uid_entry_in_group(pace, pace_iter)) {
1117                                                 pace->perms |= pace_iter->perms;
1118                                                 group_matched = True;
1119                                         }
1120                                 }
1121                         }
1122
1123                         /* If we only got an "everyone" perm, just use that. */
1124                         if (!group_matched) {
1125                                 if (got_other)
1126                                         pace->perms = pace_other->perms;
1127                                 else
1128                                         pace->perms = 0;
1129                         }
1130
1131                         apply_default_perms(fsp, pace, S_IRUSR);
1132                 } else {
1133                         pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR);
1134                 }
1135
1136                 DLIST_ADD(*pp_ace, pace);
1137         }
1138
1139         if (!got_grp) {
1140                 if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) {
1141                         DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
1142                         return False;
1143                 }
1144
1145                 ZERO_STRUCTP(pace);
1146                 pace->type = SMB_ACL_GROUP_OBJ;
1147                 pace->owner_type = GID_ACE;
1148                 pace->unix_ug.uid = pst->st_gid;
1149                 pace->trustee = *pfile_grp_sid;
1150                 pace->attr = ALLOW_ACE;
1151                 if (setting_acl) {
1152                         /* If we only got an "everyone" perm, just use that. */
1153                         if (got_other)
1154                                 pace->perms = pace_other->perms;
1155                         else
1156                                 pace->perms = 0;
1157                         apply_default_perms(fsp, pace, S_IRGRP);
1158                 } else {
1159                         pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP);
1160                 }
1161
1162                 DLIST_ADD(*pp_ace, pace);
1163         }
1164
1165         if (!got_other) {
1166                 if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) {
1167                         DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
1168                         return False;
1169                 }
1170
1171                 ZERO_STRUCTP(pace);
1172                 pace->type = SMB_ACL_OTHER;
1173                 pace->owner_type = WORLD_ACE;
1174                 pace->unix_ug.world = -1;
1175                 pace->trustee = global_sid_World;
1176                 pace->attr = ALLOW_ACE;
1177                 if (setting_acl) {
1178                         pace->perms = 0;
1179                         apply_default_perms(fsp, pace, S_IROTH);
1180                 } else
1181                         pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IROTH, S_IWOTH, S_IXOTH);
1182
1183                 DLIST_ADD(*pp_ace, pace);
1184         }
1185
1186         return True;
1187 }
1188
1189 /****************************************************************************
1190  Check if a POSIX ACL has the required SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries.
1191  If it does not have them, check if there are any entries where the trustee is the
1192  file owner or the owning group, and map these to SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ.
1193 ****************************************************************************/
1194
1195 static void check_owning_objs(canon_ace *ace, DOM_SID *pfile_owner_sid, DOM_SID *pfile_grp_sid)
1196 {
1197         BOOL got_user_obj, got_group_obj;
1198         canon_ace *current_ace;
1199         int i, entries;
1200
1201         entries = count_canon_ace_list(ace);
1202         got_user_obj = False;
1203         got_group_obj = False;
1204
1205         for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
1206                 if (current_ace->type == SMB_ACL_USER_OBJ)
1207                         got_user_obj = True;
1208                 else if (current_ace->type == SMB_ACL_GROUP_OBJ)
1209                         got_group_obj = True;
1210         }
1211         if (got_user_obj && got_group_obj) {
1212                 DEBUG(10,("check_owning_objs: ACL had owning user/group entries.\n"));
1213                 return;
1214         }
1215
1216         for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
1217                 if (!got_user_obj && current_ace->owner_type == UID_ACE &&
1218                                 sid_equal(&current_ace->trustee, pfile_owner_sid)) {
1219                         current_ace->type = SMB_ACL_USER_OBJ;
1220                         got_user_obj = True;
1221                 }
1222                 if (!got_group_obj && current_ace->owner_type == GID_ACE &&
1223                                 sid_equal(&current_ace->trustee, pfile_grp_sid)) {
1224                         current_ace->type = SMB_ACL_GROUP_OBJ;
1225                         got_group_obj = True;
1226                 }
1227         }
1228         if (!got_user_obj)
1229                 DEBUG(10,("check_owning_objs: ACL is missing an owner entry.\n"));
1230         if (!got_group_obj)
1231                 DEBUG(10,("check_owning_objs: ACL is missing an owning group entry.\n"));
1232 }
1233
1234 /****************************************************************************
1235  Unpack a SEC_DESC into two canonical ace lists.
1236 ****************************************************************************/
1237
1238 static BOOL create_canon_ace_lists(files_struct *fsp, SMB_STRUCT_STAT *pst,
1239                                                         DOM_SID *pfile_owner_sid,
1240                                                         DOM_SID *pfile_grp_sid,
1241                                                         canon_ace **ppfile_ace, canon_ace **ppdir_ace,
1242                                                         SEC_ACL *dacl)
1243 {
1244         BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False);
1245         canon_ace *file_ace = NULL;
1246         canon_ace *dir_ace = NULL;
1247         canon_ace *tmp_ace = NULL;
1248         canon_ace *current_ace = NULL;
1249         BOOL got_dir_allow = False;
1250         BOOL got_file_allow = False;
1251         int i, j;
1252
1253         *ppfile_ace = NULL;
1254         *ppdir_ace = NULL;
1255
1256         /*
1257          * Convert the incoming ACL into a more regular form.
1258          */
1259
1260         for(i = 0; i < dacl->num_aces; i++) {
1261                 SEC_ACE *psa = &dacl->ace[i];
1262
1263                 if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) && (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
1264                         DEBUG(3,("create_canon_ace_lists: unable to set anything but an ALLOW or DENY ACE.\n"));
1265                         return False;
1266                 }
1267
1268                 if (nt4_compatible_acls()) {
1269                         /*
1270                          * The security mask may be UNIX_ACCESS_NONE which should map into
1271                          * no permissions (we overload the WRITE_OWNER bit for this) or it
1272                          * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
1273                          * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
1274                          */
1275
1276                         /*
1277                          * Convert GENERIC bits to specific bits.
1278                          */
1279  
1280                         se_map_generic(&psa->info.mask, &file_generic_mapping);
1281
1282                         psa->info.mask &= (UNIX_ACCESS_NONE|FILE_ALL_ACCESS);
1283
1284                         if(psa->info.mask != UNIX_ACCESS_NONE)
1285                                 psa->info.mask &= ~UNIX_ACCESS_NONE;
1286                 }
1287         }
1288
1289         /*
1290          * Deal with the fact that NT 4.x re-writes the canonical format
1291          * that we return for default ACLs. If a directory ACE is identical
1292          * to a inherited directory ACE then NT changes the bits so that the
1293          * first ACE is set to OI|IO and the second ACE for this SID is set
1294          * to CI. We need to repair this. JRA.
1295          */
1296
1297         for(i = 0; i < dacl->num_aces; i++) {
1298                 SEC_ACE *psa1 = &dacl->ace[i];
1299
1300                 for (j = i + 1; j < dacl->num_aces; j++) {
1301                         SEC_ACE *psa2 = &dacl->ace[j];
1302
1303                         if (psa1->info.mask != psa2->info.mask)
1304                                 continue;
1305
1306                         if (!sid_equal(&psa1->trustee, &psa2->trustee))
1307                                 continue;
1308
1309                         /*
1310                          * Ok - permission bits and SIDs are equal.
1311                          * Check if flags were re-written.
1312                          */
1313
1314                         if (psa1->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
1315
1316                                 psa1->flags |= (psa2->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
1317                                 psa2->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
1318                                 
1319                         } else if (psa2->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
1320
1321                                 psa2->flags |= (psa1->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
1322                                 psa1->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
1323                                 
1324                         }
1325                 }
1326         }
1327
1328         for(i = 0; i < dacl->num_aces; i++) {
1329                 SEC_ACE *psa = &dacl->ace[i];
1330
1331                 /*
1332                  * Ignore non-mappable SIDs (NT Authority, BUILTIN etc).
1333                  */
1334
1335                 if (non_mappable_sid(&psa->trustee)) {
1336                         fstring str;
1337                         DEBUG(10,("create_canon_ace_lists: ignoring non-mappable SID %s\n",
1338                                 sid_to_string(str, &psa->trustee) ));
1339                         continue;
1340                 }
1341
1342                 /*
1343                  * Create a cannon_ace entry representing this NT DACL ACE.
1344                  */
1345
1346                 if ((current_ace = SMB_MALLOC_P(canon_ace)) == NULL) {
1347                         free_canon_ace_list(file_ace);
1348                         free_canon_ace_list(dir_ace);
1349                         DEBUG(0,("create_canon_ace_lists: malloc fail.\n"));
1350                         return False;
1351                 }
1352
1353                 ZERO_STRUCTP(current_ace);
1354
1355                 sid_copy(&current_ace->trustee, &psa->trustee);
1356
1357                 /*
1358                  * Try and work out if the SID is a user or group
1359                  * as we need to flag these differently for POSIX.
1360                  * Note what kind of a POSIX ACL this should map to.
1361                  */
1362
1363                 if( sid_equal(&current_ace->trustee, &global_sid_World)) {
1364                         current_ace->owner_type = WORLD_ACE;
1365                         current_ace->unix_ug.world = -1;
1366                         current_ace->type = SMB_ACL_OTHER;
1367                 } else if (sid_equal(&current_ace->trustee, &global_sid_Creator_Owner)) {
1368                         current_ace->owner_type = UID_ACE;
1369                         current_ace->unix_ug.uid = pst->st_uid;
1370                         current_ace->type = SMB_ACL_USER_OBJ;
1371
1372                         /*
1373                          * The Creator Owner entry only specifies inheritable permissions,
1374                          * never access permissions. WinNT doesn't always set the ACE to
1375                          *INHERIT_ONLY, though.
1376                          */
1377
1378                         if (nt4_compatible_acls())
1379                                 psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
1380                 } else if (sid_equal(&current_ace->trustee, &global_sid_Creator_Group)) {
1381                         current_ace->owner_type = GID_ACE;
1382                         current_ace->unix_ug.gid = pst->st_gid;
1383                         current_ace->type = SMB_ACL_GROUP_OBJ;
1384
1385                         /*
1386                          * The Creator Group entry only specifies inheritable permissions,
1387                          * never access permissions. WinNT doesn't always set the ACE to
1388                          *INHERIT_ONLY, though.
1389                          */
1390                         if (nt4_compatible_acls())
1391                                 psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
1392
1393                 } else if (NT_STATUS_IS_OK(sid_to_uid( &current_ace->trustee, &current_ace->unix_ug.uid))) {
1394                         current_ace->owner_type = UID_ACE;
1395                         current_ace->type = SMB_ACL_USER;
1396                 } else if (NT_STATUS_IS_OK(sid_to_gid( &current_ace->trustee, &current_ace->unix_ug.gid))) {
1397                         current_ace->owner_type = GID_ACE;
1398                         current_ace->type = SMB_ACL_GROUP;
1399                 } else {
1400                         fstring str;
1401
1402                         free_canon_ace_list(file_ace);
1403                         free_canon_ace_list(dir_ace);
1404                         DEBUG(0,("create_canon_ace_lists: unable to map SID %s to uid or gid.\n",
1405                                 sid_to_string(str, &current_ace->trustee) ));
1406                         SAFE_FREE(current_ace);
1407                         return False;
1408                 }
1409
1410                 /*
1411                  * Map the given NT permissions into a UNIX mode_t containing only
1412                  * S_I(R|W|X)USR bits.
1413                  */
1414
1415                 current_ace->perms |= map_nt_perms( psa->info, S_IRUSR);
1416                 current_ace->attr = (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? ALLOW_ACE : DENY_ACE;
1417                 current_ace->inherited = ((psa->flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False);
1418
1419                 /*
1420                  * Now add the created ace to either the file list, the directory
1421                  * list, or both. We *MUST* preserve the order here (hence we use
1422                  * DLIST_ADD_END) as NT ACLs are order dependent.
1423                  */
1424
1425                 if (fsp->is_directory) {
1426
1427                         /*
1428                          * We can only add to the default POSIX ACE list if the ACE is
1429                          * designed to be inherited by both files and directories.
1430                          */
1431
1432                         if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) ==
1433                                 (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) {
1434
1435                                 DLIST_ADD_END(dir_ace, current_ace, tmp_ace);
1436
1437                                 /*
1438                                  * Note if this was an allow ace. We can't process
1439                                  * any further deny ace's after this.
1440                                  */
1441
1442                                 if (current_ace->attr == ALLOW_ACE)
1443                                         got_dir_allow = True;
1444
1445                                 if ((current_ace->attr == DENY_ACE) && got_dir_allow) {
1446                                         DEBUG(0,("create_canon_ace_lists: malformed ACL in inheritable ACL ! \
1447 Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
1448                                         free_canon_ace_list(file_ace);
1449                                         free_canon_ace_list(dir_ace);
1450                                         SAFE_FREE(current_ace);
1451                                         return False;
1452                                 }       
1453
1454                                 if( DEBUGLVL( 10 )) {
1455                                         dbgtext("create_canon_ace_lists: adding dir ACL:\n");
1456                                         print_canon_ace( current_ace, 0);
1457                                 }
1458
1459                                 /*
1460                                  * If this is not an inherit only ACE we need to add a duplicate
1461                                  * to the file acl.
1462                                  */
1463
1464                                 if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
1465                                         canon_ace *dup_ace = dup_canon_ace(current_ace);
1466
1467                                         if (!dup_ace) {
1468                                                 DEBUG(0,("create_canon_ace_lists: malloc fail !\n"));
1469                                                 free_canon_ace_list(file_ace);
1470                                                 free_canon_ace_list(dir_ace);
1471                                                 return False;
1472                                         }
1473
1474                                         /*
1475                                          * We must not free current_ace here as its
1476                                          * pointer is now owned by the dir_ace list.
1477                                          */
1478                                         current_ace = dup_ace;
1479                                 } else {
1480                                         /*
1481                                          * We must not free current_ace here as its
1482                                          * pointer is now owned by the dir_ace list.
1483                                          */
1484                                         current_ace = NULL;
1485                                 }
1486                         }
1487                 }
1488
1489                 /*
1490                  * Only add to the file ACL if not inherit only.
1491                  */
1492
1493                 if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
1494                         DLIST_ADD_END(file_ace, current_ace, tmp_ace);
1495
1496                         /*
1497                          * Note if this was an allow ace. We can't process
1498                          * any further deny ace's after this.
1499                          */
1500
1501                         if (current_ace->attr == ALLOW_ACE)
1502                                 got_file_allow = True;
1503
1504                         if ((current_ace->attr == DENY_ACE) && got_file_allow) {
1505                                 DEBUG(0,("create_canon_ace_lists: malformed ACL in file ACL ! \
1506 Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
1507                                 free_canon_ace_list(file_ace);
1508                                 free_canon_ace_list(dir_ace);
1509                                 SAFE_FREE(current_ace);
1510                                 return False;
1511                         }       
1512
1513                         if( DEBUGLVL( 10 )) {
1514                                 dbgtext("create_canon_ace_lists: adding file ACL:\n");
1515                                 print_canon_ace( current_ace, 0);
1516                         }
1517                         all_aces_are_inherit_only = False;
1518                         /*
1519                          * We must not free current_ace here as its
1520                          * pointer is now owned by the file_ace list.
1521                          */
1522                         current_ace = NULL;
1523                 }
1524
1525                 /*
1526                  * Free if ACE was not added.
1527                  */
1528
1529                 SAFE_FREE(current_ace);
1530         }
1531
1532         if (fsp->is_directory && all_aces_are_inherit_only) {
1533                 /*
1534                  * Windows 2000 is doing one of these weird 'inherit acl'
1535                  * traverses to conserve NTFS ACL resources. Just pretend
1536                  * there was no DACL sent. JRA.
1537                  */
1538
1539                 DEBUG(10,("create_canon_ace_lists: Win2k inherit acl traverse. Ignoring DACL.\n"));
1540                 free_canon_ace_list(file_ace);
1541                 free_canon_ace_list(dir_ace);
1542                 file_ace = NULL;
1543                 dir_ace = NULL;
1544         } else {
1545                 /*
1546                  * Check if we have SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries in each
1547                  * ACL. If we don't have them, check if any SMB_ACL_USER/SMB_ACL_GROUP
1548                  * entries can be converted to *_OBJ. Usually we will already have these
1549                  * entries in the Default ACL, and the Access ACL will not have them.
1550                  */
1551                 if (file_ace) {
1552                         check_owning_objs(file_ace, pfile_owner_sid, pfile_grp_sid);
1553                 }
1554                 if (dir_ace) {
1555                         check_owning_objs(dir_ace, pfile_owner_sid, pfile_grp_sid);
1556                 }
1557         }
1558
1559         *ppfile_ace = file_ace;
1560         *ppdir_ace = dir_ace;
1561
1562         return True;
1563 }
1564
1565 /****************************************************************************
1566  ASCII art time again... JRA :-).
1567
1568  We have 4 cases to process when moving from an NT ACL to a POSIX ACL. Firstly,
1569  we insist the ACL is in canonical form (ie. all DENY entries preceede ALLOW
1570  entries). Secondly, the merge code has ensured that all duplicate SID entries for
1571  allow or deny have been merged, so the same SID can only appear once in the deny
1572  list or once in the allow list.
1573
1574  We then process as follows :
1575
1576  ---------------------------------------------------------------------------
1577  First pass - look for a Everyone DENY entry.
1578
1579  If it is deny all (rwx) trunate the list at this point.
1580  Else, walk the list from this point and use the deny permissions of this
1581  entry as a mask on all following allow entries. Finally, delete
1582  the Everyone DENY entry (we have applied it to everything possible).
1583
1584  In addition, in this pass we remove any DENY entries that have 
1585  no permissions (ie. they are a DENY nothing).
1586  ---------------------------------------------------------------------------
1587  Second pass - only deal with deny user entries.
1588
1589  DENY user1 (perms XXX)
1590
1591  new_perms = 0
1592  for all following allow group entries where user1 is in group
1593         new_perms |= group_perms;
1594
1595  user1 entry perms = new_perms & ~ XXX;
1596
1597  Convert the deny entry to an allow entry with the new perms and
1598  push to the end of the list. Note if the user was in no groups
1599  this maps to a specific allow nothing entry for this user.
1600
1601  The common case from the NT ACL choser (userX deny all) is
1602  optimised so we don't do the group lookup - we just map to
1603  an allow nothing entry.
1604
1605  What we're doing here is inferring the allow permissions the
1606  person setting the ACE on user1 wanted by looking at the allow
1607  permissions on the groups the user is currently in. This will
1608  be a snapshot, depending on group membership but is the best
1609  we can do and has the advantage of failing closed rather than
1610  open.
1611  ---------------------------------------------------------------------------
1612  Third pass - only deal with deny group entries.
1613
1614  DENY group1 (perms XXX)
1615
1616  for all following allow user entries where user is in group1
1617    user entry perms = user entry perms & ~ XXX;
1618
1619  If there is a group Everyone allow entry with permissions YYY,
1620  convert the group1 entry to an allow entry and modify its
1621  permissions to be :
1622
1623  new_perms = YYY & ~ XXX
1624
1625  and push to the end of the list.
1626
1627  If there is no group Everyone allow entry then convert the
1628  group1 entry to a allow nothing entry and push to the end of the list.
1629
1630  Note that the common case from the NT ACL choser (groupX deny all)
1631  cannot be optimised here as we need to modify user entries who are
1632  in the group to change them to a deny all also.
1633
1634  What we're doing here is modifying the allow permissions of
1635  user entries (which are more specific in POSIX ACLs) to mask
1636  out the explicit deny set on the group they are in. This will
1637  be a snapshot depending on current group membership but is the
1638  best we can do and has the advantage of failing closed rather
1639  than open.
1640  ---------------------------------------------------------------------------
1641  Fourth pass - cope with cumulative permissions.
1642
1643  for all allow user entries, if there exists an allow group entry with
1644  more permissive permissions, and the user is in that group, rewrite the
1645  allow user permissions to contain both sets of permissions.
1646
1647  Currently the code for this is #ifdef'ed out as these semantics make
1648  no sense to me. JRA.
1649  ---------------------------------------------------------------------------
1650
1651  Note we *MUST* do the deny user pass first as this will convert deny user
1652  entries into allow user entries which can then be processed by the deny
1653  group pass.
1654
1655  The above algorithm took a *lot* of thinking about - hence this
1656  explaination :-). JRA.
1657 ****************************************************************************/
1658
1659 /****************************************************************************
1660  Process a canon_ace list entries. This is very complex code. We need
1661  to go through and remove the "deny" permissions from any allow entry that matches
1662  the id of this entry. We have already refused any NT ACL that wasn't in correct
1663  order (DENY followed by ALLOW). If any allow entry ends up with zero permissions,
1664  we just remove it (to fail safe). We have already removed any duplicate ace
1665  entries. Treat an "Everyone" DENY_ACE as a special case - use it to mask all
1666  allow entries.
1667 ****************************************************************************/
1668
1669 static void process_deny_list( canon_ace **pp_ace_list )
1670 {
1671         canon_ace *ace_list = *pp_ace_list;
1672         canon_ace *curr_ace = NULL;
1673         canon_ace *curr_ace_next = NULL;
1674
1675         /* Pass 1 above - look for an Everyone, deny entry. */
1676
1677         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1678                 canon_ace *allow_ace_p;
1679
1680                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1681
1682                 if (curr_ace->attr != DENY_ACE)
1683                         continue;
1684
1685                 if (curr_ace->perms == (mode_t)0) {
1686
1687                         /* Deny nothing entry - delete. */
1688
1689                         DLIST_REMOVE(ace_list, curr_ace);
1690                         continue;
1691                 }
1692
1693                 if (!sid_equal(&curr_ace->trustee, &global_sid_World))
1694                         continue;
1695
1696                 /* JRATEST - assert. */
1697                 SMB_ASSERT(curr_ace->owner_type == WORLD_ACE);
1698
1699                 if (curr_ace->perms == ALL_ACE_PERMS) {
1700
1701                         /*
1702                          * Optimisation. This is a DENY_ALL to Everyone. Truncate the
1703                          * list at this point including this entry.
1704                          */
1705
1706                         canon_ace *prev_entry = curr_ace->prev;
1707
1708                         free_canon_ace_list( curr_ace );
1709                         if (prev_entry)
1710                                 prev_entry->next = NULL;
1711                         else {
1712                                 /* We deleted the entire list. */
1713                                 ace_list = NULL;
1714                         }
1715                         break;
1716                 }
1717
1718                 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1719
1720                         /* 
1721                          * Only mask off allow entries.
1722                          */
1723
1724                         if (allow_ace_p->attr != ALLOW_ACE)
1725                                 continue;
1726
1727                         allow_ace_p->perms &= ~curr_ace->perms;
1728                 }
1729
1730                 /*
1731                  * Now it's been applied, remove it.
1732                  */
1733
1734                 DLIST_REMOVE(ace_list, curr_ace);
1735         }
1736
1737         /* Pass 2 above - deal with deny user entries. */
1738
1739         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1740                 mode_t new_perms = (mode_t)0;
1741                 canon_ace *allow_ace_p;
1742                 canon_ace *tmp_ace;
1743
1744                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1745
1746                 if (curr_ace->attr != DENY_ACE)
1747                         continue;
1748
1749                 if (curr_ace->owner_type != UID_ACE)
1750                         continue;
1751
1752                 if (curr_ace->perms == ALL_ACE_PERMS) {
1753
1754                         /*
1755                          * Optimisation - this is a deny everything to this user.
1756                          * Convert to an allow nothing and push to the end of the list.
1757                          */
1758
1759                         curr_ace->attr = ALLOW_ACE;
1760                         curr_ace->perms = (mode_t)0;
1761                         DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
1762                         continue;
1763                 }
1764
1765                 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1766
1767                         if (allow_ace_p->attr != ALLOW_ACE)
1768                                 continue;
1769
1770                         /* We process GID_ACE and WORLD_ACE entries only. */
1771
1772                         if (allow_ace_p->owner_type == UID_ACE)
1773                                 continue;
1774
1775                         if (uid_entry_in_group( curr_ace, allow_ace_p))
1776                                 new_perms |= allow_ace_p->perms;
1777                 }
1778
1779                 /*
1780                  * Convert to a allow entry, modify the perms and push to the end
1781                  * of the list.
1782                  */
1783
1784                 curr_ace->attr = ALLOW_ACE;
1785                 curr_ace->perms = (new_perms & ~curr_ace->perms);
1786                 DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
1787         }
1788
1789         /* Pass 3 above - deal with deny group entries. */
1790
1791         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1792                 canon_ace *tmp_ace;
1793                 canon_ace *allow_ace_p;
1794                 canon_ace *allow_everyone_p = NULL;
1795
1796                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1797
1798                 if (curr_ace->attr != DENY_ACE)
1799                         continue;
1800
1801                 if (curr_ace->owner_type != GID_ACE)
1802                         continue;
1803
1804                 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1805
1806                         if (allow_ace_p->attr != ALLOW_ACE)
1807                                 continue;
1808
1809                         /* Store a pointer to the Everyone allow, if it exists. */
1810                         if (allow_ace_p->owner_type == WORLD_ACE)
1811                                 allow_everyone_p = allow_ace_p;
1812
1813                         /* We process UID_ACE entries only. */
1814
1815                         if (allow_ace_p->owner_type != UID_ACE)
1816                                 continue;
1817
1818                         /* Mask off the deny group perms. */
1819
1820                         if (uid_entry_in_group( allow_ace_p, curr_ace))
1821                                 allow_ace_p->perms &= ~curr_ace->perms;
1822                 }
1823
1824                 /*
1825                  * Convert the deny to an allow with the correct perms and
1826                  * push to the end of the list.
1827                  */
1828
1829                 curr_ace->attr = ALLOW_ACE;
1830                 if (allow_everyone_p)
1831                         curr_ace->perms = allow_everyone_p->perms & ~curr_ace->perms;
1832                 else
1833                         curr_ace->perms = (mode_t)0;
1834                 DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
1835
1836         }
1837
1838         /* Doing this fourth pass allows Windows semantics to be layered
1839          * on top of POSIX semantics. I'm not sure if this is desirable.
1840          * For example, in W2K ACLs there is no way to say, "Group X no
1841          * access, user Y full access" if user Y is a member of group X.
1842          * This seems completely broken semantics to me.... JRA.
1843          */
1844
1845 #if 0
1846         /* Pass 4 above - deal with allow entries. */
1847
1848         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1849                 canon_ace *allow_ace_p;
1850
1851                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1852
1853                 if (curr_ace->attr != ALLOW_ACE)
1854                         continue;
1855
1856                 if (curr_ace->owner_type != UID_ACE)
1857                         continue;
1858
1859                 for (allow_ace_p = ace_list; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1860
1861                         if (allow_ace_p->attr != ALLOW_ACE)
1862                                 continue;
1863
1864                         /* We process GID_ACE entries only. */
1865
1866                         if (allow_ace_p->owner_type != GID_ACE)
1867                                 continue;
1868
1869                         /* OR in the group perms. */
1870
1871                         if (uid_entry_in_group( curr_ace, allow_ace_p))
1872                                 curr_ace->perms |= allow_ace_p->perms;
1873                 }
1874         }
1875 #endif
1876
1877         *pp_ace_list = ace_list;
1878 }
1879
1880 /****************************************************************************
1881  Create a default mode that will be used if a security descriptor entry has
1882  no user/group/world entries.
1883 ****************************************************************************/
1884
1885 static mode_t create_default_mode(files_struct *fsp, BOOL interitable_mode)
1886 {
1887         int snum = SNUM(fsp->conn);
1888         mode_t and_bits = (mode_t)0;
1889         mode_t or_bits = (mode_t)0;
1890         mode_t mode = interitable_mode ? unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name, False) : S_IRUSR;
1891
1892         if (fsp->is_directory)
1893                 mode |= (S_IWUSR|S_IXUSR);
1894
1895         /*
1896          * Now AND with the create mode/directory mode bits then OR with the
1897          * force create mode/force directory mode bits.
1898          */
1899
1900         if (fsp->is_directory) {
1901                 and_bits = lp_dir_security_mask(snum);
1902                 or_bits = lp_force_dir_security_mode(snum);
1903         } else {
1904                 and_bits = lp_security_mask(snum);
1905                 or_bits = lp_force_security_mode(snum);
1906         }
1907
1908         return ((mode & and_bits)|or_bits);
1909 }
1910
1911 /****************************************************************************
1912  Unpack a SEC_DESC into two canonical ace lists. We don't depend on this
1913  succeeding.
1914 ****************************************************************************/
1915
1916 static BOOL unpack_canon_ace(files_struct *fsp, 
1917                                                         SMB_STRUCT_STAT *pst,
1918                                                         DOM_SID *pfile_owner_sid,
1919                                                         DOM_SID *pfile_grp_sid,
1920                                                         canon_ace **ppfile_ace, canon_ace **ppdir_ace,
1921                                                         uint32 security_info_sent, SEC_DESC *psd)
1922 {
1923         canon_ace *file_ace = NULL;
1924         canon_ace *dir_ace = NULL;
1925
1926         *ppfile_ace = NULL;
1927         *ppdir_ace = NULL;
1928
1929         if(security_info_sent == 0) {
1930                 DEBUG(0,("unpack_canon_ace: no security info sent !\n"));
1931                 return False;
1932         }
1933
1934         /*
1935          * If no DACL then this is a chown only security descriptor.
1936          */
1937
1938         if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !psd->dacl)
1939                 return True;
1940
1941         /*
1942          * Now go through the DACL and create the canon_ace lists.
1943          */
1944
1945         if (!create_canon_ace_lists( fsp, pst, pfile_owner_sid, pfile_grp_sid,
1946                                                                 &file_ace, &dir_ace, psd->dacl))
1947                 return False;
1948
1949         if ((file_ace == NULL) && (dir_ace == NULL)) {
1950                 /* W2K traverse DACL set - ignore. */
1951                 return True;
1952         }
1953
1954         /*
1955          * Go through the canon_ace list and merge entries
1956          * belonging to identical users of identical allow or deny type.
1957          * We can do this as all deny entries come first, followed by
1958          * all allow entries (we have mandated this before accepting this acl).
1959          */
1960
1961         print_canon_ace_list( "file ace - before merge", file_ace);
1962         merge_aces( &file_ace );
1963
1964         print_canon_ace_list( "dir ace - before merge", dir_ace);
1965         merge_aces( &dir_ace );
1966
1967         /*
1968          * NT ACLs are order dependent. Go through the acl lists and
1969          * process DENY entries by masking the allow entries.
1970          */
1971
1972         print_canon_ace_list( "file ace - before deny", file_ace);
1973         process_deny_list( &file_ace);
1974
1975         print_canon_ace_list( "dir ace - before deny", dir_ace);
1976         process_deny_list( &dir_ace);
1977
1978         /*
1979          * A well formed POSIX file or default ACL has at least 3 entries, a 
1980          * SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ
1981          * and optionally a mask entry. Ensure this is the case.
1982          */
1983
1984         print_canon_ace_list( "file ace - before valid", file_ace);
1985
1986         /*
1987          * A default 3 element mode entry for a file should be r-- --- ---.
1988          * A default 3 element mode entry for a directory should be rwx --- ---.
1989          */
1990
1991         pst->st_mode = create_default_mode(fsp, False);
1992
1993         if (!ensure_canon_entry_valid(&file_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
1994                 free_canon_ace_list(file_ace);
1995                 free_canon_ace_list(dir_ace);
1996                 return False;
1997         }
1998
1999         print_canon_ace_list( "dir ace - before valid", dir_ace);
2000
2001         /*
2002          * A default inheritable 3 element mode entry for a directory should be the
2003          * mode Samba will use to create a file within. Ensure user rwx bits are set if
2004          * it's a directory.
2005          */
2006
2007         pst->st_mode = create_default_mode(fsp, True);
2008
2009         if (dir_ace && !ensure_canon_entry_valid(&dir_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
2010                 free_canon_ace_list(file_ace);
2011                 free_canon_ace_list(dir_ace);
2012                 return False;
2013         }
2014
2015         print_canon_ace_list( "file ace - return", file_ace);
2016         print_canon_ace_list( "dir ace - return", dir_ace);
2017
2018         *ppfile_ace = file_ace;
2019         *ppdir_ace = dir_ace;
2020         return True;
2021
2022 }
2023
2024 /******************************************************************************
2025  When returning permissions, try and fit NT display
2026  semantics if possible. Note the the canon_entries here must have been malloced.
2027  The list format should be - first entry = owner, followed by group and other user
2028  entries, last entry = other.
2029
2030  Note that this doesn't exactly match the NT semantics for an ACL. As POSIX entries
2031  are not ordered, and match on the most specific entry rather than walking a list,
2032  then a simple POSIX permission of rw-r--r-- should really map to 5 entries,
2033
2034  Entry 0: owner : deny all except read and write.
2035  Entry 1: owner : allow read and write.
2036  Entry 2: group : deny all except read.
2037  Entry 3: group : allow read.
2038  Entry 4: Everyone : allow read.
2039
2040  But NT cannot display this in their ACL editor !
2041 ********************************************************************************/
2042
2043 static void arrange_posix_perms( char *filename, canon_ace **pp_list_head)
2044 {
2045         canon_ace *list_head = *pp_list_head;
2046         canon_ace *owner_ace = NULL;
2047         canon_ace *other_ace = NULL;
2048         canon_ace *ace = NULL;
2049
2050         for (ace = list_head; ace; ace = ace->next) {
2051                 if (ace->type == SMB_ACL_USER_OBJ)
2052                         owner_ace = ace;
2053                 else if (ace->type == SMB_ACL_OTHER) {
2054                         /* Last ace - this is "other" */
2055                         other_ace = ace;
2056                 }
2057         }
2058                 
2059         if (!owner_ace || !other_ace) {
2060                 DEBUG(0,("arrange_posix_perms: Invalid POSIX permissions for file %s, missing owner or other.\n",
2061                         filename ));
2062                 return;
2063         }
2064
2065         /*
2066          * The POSIX algorithm applies to owner first, and other last,
2067          * so ensure they are arranged in this order.
2068          */
2069
2070         if (owner_ace) {
2071                 DLIST_PROMOTE(list_head, owner_ace);
2072         }
2073
2074         if (other_ace) {
2075                 DLIST_DEMOTE(list_head, other_ace, ace);
2076         }
2077
2078         /* We have probably changed the head of the list. */
2079
2080         *pp_list_head = list_head;
2081 }
2082                 
2083 /****************************************************************************
2084  Create a linked list of canonical ACE entries.
2085 ****************************************************************************/
2086
2087 static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf,
2088                                         const DOM_SID *powner, const DOM_SID *pgroup, struct pai_val *pal, SMB_ACL_TYPE_T the_acl_type)
2089 {
2090         connection_struct *conn = fsp->conn;
2091         mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR);
2092         canon_ace *list_head = NULL;
2093         canon_ace *ace = NULL;
2094         canon_ace *next_ace = NULL;
2095         int entry_id = SMB_ACL_FIRST_ENTRY;
2096         SMB_ACL_ENTRY_T entry;
2097         size_t ace_count;
2098
2099         while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
2100                 SMB_ACL_TAG_T tagtype;
2101                 SMB_ACL_PERMSET_T permset;
2102                 DOM_SID sid;
2103                 posix_id unix_ug;
2104                 enum ace_owner owner_type;
2105
2106                 /* get_next... */
2107                 if (entry_id == SMB_ACL_FIRST_ENTRY)
2108                         entry_id = SMB_ACL_NEXT_ENTRY;
2109
2110                 /* Is this a MASK entry ? */
2111                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
2112                         continue;
2113
2114                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
2115                         continue;
2116
2117                 /* Decide which SID to use based on the ACL type. */
2118                 switch(tagtype) {
2119                         case SMB_ACL_USER_OBJ:
2120                                 /* Get the SID from the owner. */
2121                                 sid_copy(&sid, powner);
2122                                 unix_ug.uid = psbuf->st_uid;
2123                                 owner_type = UID_ACE;
2124                                 break;
2125                         case SMB_ACL_USER:
2126                                 {
2127                                         uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
2128                                         if (puid == NULL) {
2129                                                 DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
2130                                                 continue;
2131                                         }
2132                                         /*
2133                                          * A SMB_ACL_USER entry for the owner is shadowed by the
2134                                          * SMB_ACL_USER_OBJ entry and Windows also cannot represent
2135                                          * that entry, so we ignore it. We also don't create such
2136                                          * entries out of the blue when setting ACLs, so a get/set
2137                                          * cycle will drop them.
2138                                          */
2139                                         if (the_acl_type == SMB_ACL_TYPE_ACCESS && *puid == psbuf->st_uid) {
2140                                                 SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
2141                                                 continue;
2142                                         }
2143                                         uid_to_sid( &sid, *puid);
2144                                         unix_ug.uid = *puid;
2145                                         owner_type = UID_ACE;
2146                                         SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
2147                                         break;
2148                                 }
2149                         case SMB_ACL_GROUP_OBJ:
2150                                 /* Get the SID from the owning group. */
2151                                 sid_copy(&sid, pgroup);
2152                                 unix_ug.gid = psbuf->st_gid;
2153                                 owner_type = GID_ACE;
2154                                 break;
2155                         case SMB_ACL_GROUP:
2156                                 {
2157                                         gid_t *pgid = (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
2158                                         if (pgid == NULL) {
2159                                                 DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
2160                                                 continue;
2161                                         }
2162                                         gid_to_sid( &sid, *pgid);
2163                                         unix_ug.gid = *pgid;
2164                                         owner_type = GID_ACE;
2165                                         SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)pgid,tagtype);
2166                                         break;
2167                                 }
2168                         case SMB_ACL_MASK:
2169                                 acl_mask = convert_permset_to_mode_t(conn, permset);
2170                                 continue; /* Don't count the mask as an entry. */
2171                         case SMB_ACL_OTHER:
2172                                 /* Use the Everyone SID */
2173                                 sid = global_sid_World;
2174                                 unix_ug.world = -1;
2175                                 owner_type = WORLD_ACE;
2176                                 break;
2177                         default:
2178                                 DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype));
2179                                 continue;
2180                 }
2181
2182                 /*
2183                  * Add this entry to the list.
2184                  */
2185
2186                 if ((ace = SMB_MALLOC_P(canon_ace)) == NULL)
2187                         goto fail;
2188
2189                 ZERO_STRUCTP(ace);
2190                 ace->type = tagtype;
2191                 ace->perms = convert_permset_to_mode_t(conn, permset);
2192                 ace->attr = ALLOW_ACE;
2193                 ace->trustee = sid;
2194                 ace->unix_ug = unix_ug;
2195                 ace->owner_type = owner_type;
2196                 ace->inherited = get_inherited_flag(pal, ace, (the_acl_type == SMB_ACL_TYPE_DEFAULT));
2197
2198                 DLIST_ADD(list_head, ace);
2199         }
2200
2201         /*
2202          * This next call will ensure we have at least a user/group/world set.
2203          */
2204
2205         if (!ensure_canon_entry_valid(&list_head, fsp, powner, pgroup, psbuf, False))
2206                 goto fail;
2207
2208         /*
2209          * Now go through the list, masking the permissions with the
2210          * acl_mask. Ensure all DENY Entries are at the start of the list.
2211          */
2212
2213         DEBUG(10,("canonicalise_acl: %s ace entries before arrange :\n", the_acl_type == SMB_ACL_TYPE_ACCESS ? "Access" : "Default" ));
2214
2215         for ( ace_count = 0, ace = list_head; ace; ace = next_ace, ace_count++) {
2216                 next_ace = ace->next;
2217
2218                 /* Masks are only applied to entries other than USER_OBJ and OTHER. */
2219                 if (ace->type != SMB_ACL_OTHER && ace->type != SMB_ACL_USER_OBJ)
2220                         ace->perms &= acl_mask;
2221
2222                 if (ace->perms == 0) {
2223                         DLIST_PROMOTE(list_head, ace);
2224                 }
2225
2226                 if( DEBUGLVL( 10 ) ) {
2227                         print_canon_ace(ace, ace_count);
2228                 }
2229         }
2230
2231         arrange_posix_perms(fsp->fsp_name,&list_head );
2232
2233         print_canon_ace_list( "canonicalise_acl: ace entries after arrange", list_head );
2234
2235         return list_head;
2236
2237   fail:
2238
2239         free_canon_ace_list(list_head);
2240         return NULL;
2241 }
2242
2243 /****************************************************************************
2244  Check if the current user group list contains a given group.
2245 ****************************************************************************/
2246
2247 static BOOL current_user_in_group(gid_t gid)
2248 {
2249         int i;
2250
2251         for (i = 0; i < current_user.ngroups; i++) {
2252                 if (current_user.groups[i] == gid) {
2253                         return True;
2254                 }
2255         }
2256
2257         return False;
2258 }
2259
2260 /****************************************************************************
2261  Should we override a deny ?
2262 ****************************************************************************/
2263
2264 static BOOL acl_group_override(connection_struct *conn, gid_t prim_gid)
2265 {
2266         if ((errno == EACCES || errno == EPERM) &&
2267                         lp_acl_group_control(SNUM(conn)) &&
2268                         current_user_in_group(prim_gid)) {
2269                 return True;
2270         } else {
2271                 return False;
2272         }
2273 }
2274
2275 /****************************************************************************
2276  Attempt to apply an ACL to a file or directory.
2277 ****************************************************************************/
2278
2279 static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL default_ace, gid_t prim_gid, BOOL *pacl_set_support)
2280 {
2281         connection_struct *conn = fsp->conn;
2282         BOOL ret = False;
2283         SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, (int)count_canon_ace_list(the_ace) + 1);
2284         canon_ace *p_ace;
2285         int i;
2286         SMB_ACL_ENTRY_T mask_entry;
2287         BOOL got_mask_entry = False;
2288         SMB_ACL_PERMSET_T mask_permset;
2289         SMB_ACL_TYPE_T the_acl_type = (default_ace ? SMB_ACL_TYPE_DEFAULT : SMB_ACL_TYPE_ACCESS);
2290         BOOL needs_mask = False;
2291         mode_t mask_perms = 0;
2292
2293 #if defined(POSIX_ACL_NEEDS_MASK)
2294         /* HP-UX always wants to have a mask (called "class" there). */
2295         needs_mask = True;
2296 #endif
2297
2298         if (the_acl == NULL) {
2299
2300                 if (!no_acl_syscall_error(errno)) {
2301                         /*
2302                          * Only print this error message if we have some kind of ACL
2303                          * support that's not working. Otherwise we would always get this.
2304                          */
2305                         DEBUG(0,("set_canon_ace_list: Unable to init %s ACL. (%s)\n",
2306                                 default_ace ? "default" : "file", strerror(errno) ));
2307                 }
2308                 *pacl_set_support = False;
2309                 return False;
2310         }
2311
2312         if( DEBUGLVL( 10 )) {
2313                 dbgtext("set_canon_ace_list: setting ACL:\n");
2314                 for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
2315                         print_canon_ace( p_ace, i);
2316                 }
2317         }
2318
2319         for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
2320                 SMB_ACL_ENTRY_T the_entry;
2321                 SMB_ACL_PERMSET_T the_permset;
2322
2323                 /*
2324                  * ACLs only "need" an ACL_MASK entry if there are any named user or
2325                  * named group entries. But if there is an ACL_MASK entry, it applies
2326                  * to ACL_USER, ACL_GROUP, and ACL_GROUP_OBJ entries. Set the mask
2327                  * so that it doesn't deny (i.e., mask off) any permissions.
2328                  */
2329
2330                 if (p_ace->type == SMB_ACL_USER || p_ace->type == SMB_ACL_GROUP) {
2331                         needs_mask = True;
2332                         mask_perms |= p_ace->perms;
2333                 } else if (p_ace->type == SMB_ACL_GROUP_OBJ) {
2334                         mask_perms |= p_ace->perms;
2335                 }
2336
2337                 /*
2338                  * Get the entry for this ACE.
2339                  */
2340
2341                 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) {
2342                         DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n",
2343                                 i, strerror(errno) ));
2344                         goto fail;
2345                 }
2346
2347                 if (p_ace->type == SMB_ACL_MASK) {
2348                         mask_entry = the_entry;
2349                         got_mask_entry = True;
2350                 }
2351
2352                 /*
2353                  * Ok - we now know the ACL calls should be working, don't
2354                  * allow fallback to chmod.
2355                  */
2356
2357                 *pacl_set_support = True;
2358
2359                 /*
2360                  * Initialise the entry from the canon_ace.
2361                  */
2362
2363                 /*
2364                  * First tell the entry what type of ACE this is.
2365                  */
2366
2367                 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, p_ace->type) == -1) {
2368                         DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n",
2369                                 i, strerror(errno) ));
2370                         goto fail;
2371                 }
2372
2373                 /*
2374                  * Only set the qualifier (user or group id) if the entry is a user
2375                  * or group id ACE.
2376                  */
2377
2378                 if ((p_ace->type == SMB_ACL_USER) || (p_ace->type == SMB_ACL_GROUP)) {
2379                         if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&p_ace->unix_ug.uid) == -1) {
2380                                 DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n",
2381                                         i, strerror(errno) ));
2382                                 goto fail;
2383                         }
2384                 }
2385
2386                 /*
2387                  * Convert the mode_t perms in the canon_ace to a POSIX permset.
2388                  */
2389
2390                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) {
2391                         DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n",
2392                                 i, strerror(errno) ));
2393                         goto fail;
2394                 }
2395
2396                 if (map_acl_perms_to_permset(conn, p_ace->perms, &the_permset) == -1) {
2397                         DEBUG(0,("set_canon_ace_list: Failed to create permset for mode (%u) on entry %d. (%s)\n",
2398                                 (unsigned int)p_ace->perms, i, strerror(errno) ));
2399                         goto fail;
2400                 }
2401
2402                 /*
2403                  * ..and apply them to the entry.
2404                  */
2405
2406                 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) {
2407                         DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n",
2408                                 i, strerror(errno) ));
2409                         goto fail;
2410                 }
2411
2412                 if( DEBUGLVL( 10 ))
2413                         print_canon_ace( p_ace, i);
2414
2415         }
2416
2417         if (needs_mask && !got_mask_entry) {
2418                 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &mask_entry) == -1) {
2419                         DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) ));
2420                         goto fail;
2421                 }
2422
2423                 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, mask_entry, SMB_ACL_MASK) == -1) {
2424                         DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno) ));
2425                         goto fail;
2426                 }
2427
2428                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, mask_entry, &mask_permset) == -1) {
2429                         DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) ));
2430                         goto fail;
2431                 }
2432
2433                 if (map_acl_perms_to_permset(conn, S_IRUSR|S_IWUSR|S_IXUSR, &mask_permset) == -1) {
2434                         DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno) ));
2435                         goto fail;
2436                 }
2437
2438                 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, mask_entry, mask_permset) == -1) {
2439                         DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) ));
2440                         goto fail;
2441                 }
2442         }
2443
2444         /*
2445          * Check if the ACL is valid.
2446          */
2447
2448         if (SMB_VFS_SYS_ACL_VALID(conn, the_acl) == -1) {
2449                 DEBUG(0,("set_canon_ace_list: ACL type (%s) is invalid for set (%s).\n",
2450                                 the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
2451                                 strerror(errno) ));
2452                 goto fail;
2453         }
2454
2455         /*
2456          * Finally apply it to the file or directory.
2457          */
2458
2459         if(default_ace || fsp->is_directory || fsp->fh->fd == -1) {
2460                 if (SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name, the_acl_type, the_acl) == -1) {
2461                         /*
2462                          * Some systems allow all the above calls and only fail with no ACL support
2463                          * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
2464                          */
2465                         if (no_acl_syscall_error(errno)) {
2466                                 *pacl_set_support = False;
2467                         }
2468
2469                         if (acl_group_override(conn, prim_gid)) {
2470                                 int sret;
2471
2472                                 DEBUG(5,("set_canon_ace_list: acl group control on and current user in file %s primary group.\n",
2473                                         fsp->fsp_name ));
2474
2475                                 become_root();
2476                                 sret = SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name, the_acl_type, the_acl);
2477                                 unbecome_root();
2478                                 if (sret == 0) {
2479                                         ret = True;     
2480                                 }
2481                         }
2482
2483                         if (ret == False) {
2484                                 DEBUG(2,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n",
2485                                                 the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
2486                                                 fsp->fsp_name, strerror(errno) ));
2487                                 goto fail;
2488                         }
2489                 }
2490         } else {
2491                 if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fh->fd, the_acl) == -1) {
2492                         /*
2493                          * Some systems allow all the above calls and only fail with no ACL support
2494                          * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
2495                          */
2496                         if (no_acl_syscall_error(errno)) {
2497                                 *pacl_set_support = False;
2498                         }
2499
2500                         if (acl_group_override(conn, prim_gid)) {
2501                                 int sret;
2502
2503                                 DEBUG(5,("set_canon_ace_list: acl group control on and current user in file %s primary group.\n",
2504                                         fsp->fsp_name ));
2505
2506                                 become_root();
2507                                 sret = SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fh->fd, the_acl);
2508                                 unbecome_root();
2509                                 if (sret == 0) {
2510                                         ret = True;
2511                                 }
2512                         }
2513
2514                         if (ret == False) {
2515                                 DEBUG(2,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n",
2516                                                 fsp->fsp_name, strerror(errno) ));
2517                                 goto fail;
2518                         }
2519                 }
2520         }
2521
2522         ret = True;
2523
2524   fail:
2525
2526         if (the_acl != NULL) {
2527                 SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
2528         }
2529
2530         return ret;
2531 }
2532
2533 /****************************************************************************
2534  Find a particular canon_ace entry.
2535 ****************************************************************************/
2536
2537 static struct canon_ace *canon_ace_entry_for(struct canon_ace *list, SMB_ACL_TAG_T type, posix_id *id)
2538 {
2539         while (list) {
2540                 if (list->type == type && ((type != SMB_ACL_USER && type != SMB_ACL_GROUP) ||
2541                                 (type == SMB_ACL_USER  && id && id->uid == list->unix_ug.uid) ||
2542                                 (type == SMB_ACL_GROUP && id && id->gid == list->unix_ug.gid)))
2543                         break;
2544                 list = list->next;
2545         }
2546         return list;
2547 }
2548
2549 /****************************************************************************
2550  
2551 ****************************************************************************/
2552
2553 SMB_ACL_T free_empty_sys_acl(connection_struct *conn, SMB_ACL_T the_acl)
2554 {
2555         SMB_ACL_ENTRY_T entry;
2556
2557         if (!the_acl)
2558                 return NULL;
2559         if (SMB_VFS_SYS_ACL_GET_ENTRY(conn, the_acl, SMB_ACL_FIRST_ENTRY, &entry) != 1) {
2560                 SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
2561                 return NULL;
2562         }
2563         return the_acl;
2564 }
2565
2566 /****************************************************************************
2567  Convert a canon_ace to a generic 3 element permission - if possible.
2568 ****************************************************************************/
2569
2570 #define MAP_PERM(p,mask,result) (((p) & (mask)) ? (result) : 0 )
2571
2572 static BOOL convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file_ace_list, mode_t *posix_perms)
2573 {
2574         int snum = SNUM(fsp->conn);
2575         size_t ace_count = count_canon_ace_list(file_ace_list);
2576         canon_ace *ace_p;
2577         canon_ace *owner_ace = NULL;
2578         canon_ace *group_ace = NULL;
2579         canon_ace *other_ace = NULL;
2580         mode_t and_bits;
2581         mode_t or_bits;
2582
2583         if (ace_count != 3) {
2584                 DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE entries for file %s to convert to \
2585 posix perms.\n", fsp->fsp_name ));
2586                 return False;
2587         }
2588
2589         for (ace_p = file_ace_list; ace_p; ace_p = ace_p->next) {
2590                 if (ace_p->owner_type == UID_ACE)
2591                         owner_ace = ace_p;
2592                 else if (ace_p->owner_type == GID_ACE)
2593                         group_ace = ace_p;
2594                 else if (ace_p->owner_type == WORLD_ACE)
2595                         other_ace = ace_p;
2596         }
2597
2598         if (!owner_ace || !group_ace || !other_ace) {
2599                 DEBUG(3,("convert_canon_ace_to_posix_perms: Can't get standard entries for file %s.\n",
2600                                 fsp->fsp_name ));
2601                 return False;
2602         }
2603
2604         *posix_perms = (mode_t)0;
2605
2606         *posix_perms |= owner_ace->perms;
2607         *posix_perms |= MAP_PERM(group_ace->perms, S_IRUSR, S_IRGRP);
2608         *posix_perms |= MAP_PERM(group_ace->perms, S_IWUSR, S_IWGRP);
2609         *posix_perms |= MAP_PERM(group_ace->perms, S_IXUSR, S_IXGRP);
2610         *posix_perms |= MAP_PERM(other_ace->perms, S_IRUSR, S_IROTH);
2611         *posix_perms |= MAP_PERM(other_ace->perms, S_IWUSR, S_IWOTH);
2612         *posix_perms |= MAP_PERM(other_ace->perms, S_IXUSR, S_IXOTH);
2613
2614         /* The owner must have at least read access. */
2615
2616         *posix_perms |= S_IRUSR;
2617         if (fsp->is_directory)
2618                 *posix_perms |= (S_IWUSR|S_IXUSR);
2619
2620         /* If requested apply the masks. */
2621
2622         /* Get the initial bits to apply. */
2623
2624         if (fsp->is_directory) {
2625                 and_bits = lp_dir_security_mask(snum);
2626                 or_bits = lp_force_dir_security_mode(snum);
2627         } else {
2628                 and_bits = lp_security_mask(snum);
2629                 or_bits = lp_force_security_mode(snum);
2630         }
2631
2632         *posix_perms = (((*posix_perms) & and_bits)|or_bits);
2633
2634         DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o to perm=0%o for file %s.\n",
2635                 (int)owner_ace->perms, (int)group_ace->perms, (int)other_ace->perms, (int)*posix_perms,
2636                 fsp->fsp_name ));
2637
2638         return True;
2639 }
2640
2641 /****************************************************************************
2642   Incoming NT ACLs on a directory can be split into a default POSIX acl (CI|OI|IO) and
2643   a normal POSIX acl. Win2k needs these split acls re-merging into one ACL
2644   with CI|OI set so it is inherited and also applies to the directory.
2645   Based on code from "Jim McDonough" <jmcd@us.ibm.com>.
2646 ****************************************************************************/
2647
2648 static size_t merge_default_aces( SEC_ACE *nt_ace_list, size_t num_aces)
2649 {
2650         size_t i, j;
2651
2652         for (i = 0; i < num_aces; i++) {
2653                 for (j = i+1; j < num_aces; j++) {
2654                         uint32 i_flags_ni = (nt_ace_list[i].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
2655                         uint32 j_flags_ni = (nt_ace_list[j].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
2656                         BOOL i_inh = (nt_ace_list[i].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
2657                         BOOL j_inh = (nt_ace_list[j].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
2658
2659                         /* We know the lower number ACE's are file entries. */
2660                         if ((nt_ace_list[i].type == nt_ace_list[j].type) &&
2661                                 (nt_ace_list[i].size == nt_ace_list[j].size) &&
2662                                 (nt_ace_list[i].info.mask == nt_ace_list[j].info.mask) &&
2663                                 sid_equal(&nt_ace_list[i].trustee, &nt_ace_list[j].trustee) &&
2664                                 (i_inh == j_inh) &&
2665                                 (i_flags_ni == 0) &&
2666                                 (j_flags_ni == (SEC_ACE_FLAG_OBJECT_INHERIT|
2667                                                   SEC_ACE_FLAG_CONTAINER_INHERIT|
2668                                                   SEC_ACE_FLAG_INHERIT_ONLY))) {
2669                                 /*
2670                                  * W2K wants to have access allowed zero access ACE's
2671                                  * at the end of the list. If the mask is zero, merge
2672                                  * the non-inherited ACE onto the inherited ACE.
2673                                  */
2674
2675                                 if (nt_ace_list[i].info.mask == 0) {
2676                                         nt_ace_list[j].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2677                                                                 (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2678                                         if (num_aces - i - 1 > 0)
2679                                                 memmove(&nt_ace_list[i], &nt_ace_list[i+1], (num_aces-i-1) *
2680                                                                 sizeof(SEC_ACE));
2681
2682                                         DEBUG(10,("merge_default_aces: Merging zero access ACE %u onto ACE %u.\n",
2683                                                 (unsigned int)i, (unsigned int)j ));
2684                                 } else {
2685                                         /*
2686                                          * These are identical except for the flags.
2687                                          * Merge the inherited ACE onto the non-inherited ACE.
2688                                          */
2689
2690                                         nt_ace_list[i].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2691                                                                 (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2692                                         if (num_aces - j - 1 > 0)
2693                                                 memmove(&nt_ace_list[j], &nt_ace_list[j+1], (num_aces-j-1) *
2694                                                                 sizeof(SEC_ACE));
2695
2696                                         DEBUG(10,("merge_default_aces: Merging ACE %u onto ACE %u.\n",
2697                                                 (unsigned int)j, (unsigned int)i ));
2698                                 }
2699                                 num_aces--;
2700                                 break;
2701                         }
2702                 }
2703         }
2704
2705         return num_aces;
2706 }
2707 /****************************************************************************
2708  Reply to query a security descriptor from an fsp. If it succeeds it allocates
2709  the space for the return elements and returns the size needed to return the
2710  security descriptor. This should be the only external function needed for
2711  the UNIX style get ACL.
2712 ****************************************************************************/
2713
2714 size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc)
2715 {
2716         connection_struct *conn = fsp->conn;
2717         SMB_STRUCT_STAT sbuf;
2718         SEC_ACE *nt_ace_list = NULL;
2719         DOM_SID owner_sid;
2720         DOM_SID group_sid;
2721         size_t sd_size = 0;
2722         SEC_ACL *psa = NULL;
2723         size_t num_acls = 0;
2724         size_t num_def_acls = 0;
2725         size_t num_aces = 0;
2726         SMB_ACL_T posix_acl = NULL;
2727         SMB_ACL_T def_acl = NULL;
2728         canon_ace *file_ace = NULL;
2729         canon_ace *dir_ace = NULL;
2730         size_t num_profile_acls = 0;
2731         struct pai_val *pal = NULL;
2732         SEC_DESC *psd = NULL;
2733
2734         *ppdesc = NULL;
2735
2736         DEBUG(10,("get_nt_acl: called for file %s\n", fsp->fsp_name ));
2737
2738         if(fsp->is_directory || fsp->fh->fd == -1) {
2739
2740                 /* Get the stat struct for the owner info. */
2741                 if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) {
2742                         return 0;
2743                 }
2744                 /*
2745                  * Get the ACL from the path.
2746                  */
2747
2748                 posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_ACCESS);
2749
2750                 /*
2751                  * If it's a directory get the default POSIX ACL.
2752                  */
2753
2754                 if(fsp->is_directory) {
2755                         def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_DEFAULT);
2756                         def_acl = free_empty_sys_acl(conn, def_acl);
2757                 }
2758
2759         } else {
2760
2761                 /* Get the stat struct for the owner info. */
2762                 if(SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf) != 0) {
2763                         return 0;
2764                 }
2765                 /*
2766                  * Get the ACL from the fd.
2767                  */
2768                 posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fh->fd);
2769         }
2770
2771         DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n",
2772                         posix_acl ? "present" :  "absent",
2773                         def_acl ? "present" :  "absent" ));
2774
2775         pal = load_inherited_info(fsp);
2776
2777         /*
2778          * Get the owner, group and world SIDs.
2779          */
2780
2781         if (lp_profile_acls(SNUM(conn))) {
2782                 /* For WXP SP1 the owner must be administrators. */
2783                 sid_copy(&owner_sid, &global_sid_Builtin_Administrators);
2784                 sid_copy(&group_sid, &global_sid_Builtin_Users);
2785                 num_profile_acls = 2;
2786         } else {
2787                 create_file_sids(&sbuf, &owner_sid, &group_sid);
2788         }
2789
2790         if ((security_info & DACL_SECURITY_INFORMATION) && !(security_info & PROTECTED_DACL_SECURITY_INFORMATION)) {
2791
2792                 /*
2793                  * In the optimum case Creator Owner and Creator Group would be used for
2794                  * the ACL_USER_OBJ and ACL_GROUP_OBJ entries, respectively, but this
2795                  * would lead to usability problems under Windows: The Creator entries
2796                  * are only available in browse lists of directories and not for files;
2797                  * additionally the identity of the owning group couldn't be determined.
2798                  * We therefore use those identities only for Default ACLs. 
2799                  */
2800
2801                 /* Create the canon_ace lists. */
2802                 file_ace = canonicalise_acl( fsp, posix_acl, &sbuf, &owner_sid, &group_sid, pal, SMB_ACL_TYPE_ACCESS );
2803
2804                 /* We must have *some* ACLS. */
2805         
2806                 if (count_canon_ace_list(file_ace) == 0) {
2807                         DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", fsp->fsp_name ));
2808                         goto done;
2809                 }
2810
2811                 if (fsp->is_directory && def_acl) {
2812                         dir_ace = canonicalise_acl(fsp, def_acl, &sbuf,
2813                                         &global_sid_Creator_Owner,
2814                                         &global_sid_Creator_Group, pal, SMB_ACL_TYPE_DEFAULT );
2815                 }
2816
2817                 /*
2818                  * Create the NT ACE list from the canonical ace lists.
2819                  */
2820
2821                 {
2822                         canon_ace *ace;
2823                         int nt_acl_type;
2824                         int i;
2825
2826                         if (nt4_compatible_acls() && dir_ace) {
2827                                 /*
2828                                  * NT 4 chokes if an ACL contains an INHERIT_ONLY entry
2829                                  * but no non-INHERIT_ONLY entry for one SID. So we only
2830                                  * remove entries from the Access ACL if the
2831                                  * corresponding Default ACL entries have also been
2832                                  * removed. ACEs for CREATOR-OWNER and CREATOR-GROUP
2833                                  * are exceptions. We can do nothing
2834                                  * intelligent if the Default ACL contains entries that
2835                                  * are not also contained in the Access ACL, so this
2836                                  * case will still fail under NT 4.
2837                                  */
2838
2839                                 ace = canon_ace_entry_for(dir_ace, SMB_ACL_OTHER, NULL);
2840                                 if (ace && !ace->perms) {
2841                                         DLIST_REMOVE(dir_ace, ace);
2842                                         SAFE_FREE(ace);
2843
2844                                         ace = canon_ace_entry_for(file_ace, SMB_ACL_OTHER, NULL);
2845                                         if (ace && !ace->perms) {
2846                                                 DLIST_REMOVE(file_ace, ace);
2847                                                 SAFE_FREE(ace);
2848                                         }
2849                                 }
2850
2851                                 /*
2852                                  * WinNT doesn't usually have Creator Group
2853                                  * in browse lists, so we send this entry to
2854                                  * WinNT even if it contains no relevant
2855                                  * permissions. Once we can add
2856                                  * Creator Group to browse lists we can
2857                                  * re-enable this.
2858                                  */
2859
2860 #if 0
2861                                 ace = canon_ace_entry_for(dir_ace, SMB_ACL_GROUP_OBJ, NULL);
2862                                 if (ace && !ace->perms) {
2863                                         DLIST_REMOVE(dir_ace, ace);
2864                                         SAFE_FREE(ace);
2865                                 }
2866 #endif
2867
2868                                 ace = canon_ace_entry_for(file_ace, SMB_ACL_GROUP_OBJ, NULL);
2869                                 if (ace && !ace->perms) {
2870                                         DLIST_REMOVE(file_ace, ace);
2871                                         SAFE_FREE(ace);
2872                                 }
2873                         }
2874
2875                         num_acls = count_canon_ace_list(file_ace);
2876                         num_def_acls = count_canon_ace_list(dir_ace);
2877
2878                         /* Allocate the ace list. */
2879                         if ((nt_ace_list = SMB_MALLOC_ARRAY(SEC_ACE,num_acls + num_profile_acls + num_def_acls)) == NULL) {
2880                                 DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
2881                                 goto done;
2882                         }
2883
2884                         memset(nt_ace_list, '\0', (num_acls + num_def_acls) * sizeof(SEC_ACE) );
2885                                                                                                         
2886                         /*
2887                          * Create the NT ACE list from the canonical ace lists.
2888                          */
2889         
2890                         ace = file_ace;
2891
2892                         for (i = 0; i < num_acls; i++, ace = ace->next) {
2893                                 SEC_ACCESS acc;
2894
2895                                 acc = map_canon_ace_perms(SNUM(conn), &nt_acl_type, &owner_sid, ace, fsp->is_directory);
2896                                 init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc, ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2897                         }
2898
2899                         /* The User must have access to a profile share - even if we can't map the SID. */
2900                         if (lp_profile_acls(SNUM(conn))) {
2901                                 SEC_ACCESS acc;
2902
2903                                 init_sec_access(&acc,FILE_GENERIC_ALL);
2904                                 init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED,
2905                                                 acc, 0);
2906                         }
2907
2908                         ace = dir_ace;
2909
2910                         for (i = 0; i < num_def_acls; i++, ace = ace->next) {
2911                                 SEC_ACCESS acc;
2912         
2913                                 acc = map_canon_ace_perms(SNUM(conn), &nt_acl_type, &owner_sid, ace, fsp->is_directory);
2914                                 init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc,
2915                                                 SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2916                                                 SEC_ACE_FLAG_INHERIT_ONLY|
2917                                                 (ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 0));
2918                         }
2919
2920                         /* The User must have access to a profile share - even if we can't map the SID. */
2921                         if (lp_profile_acls(SNUM(conn))) {
2922                                 SEC_ACCESS acc;
2923                         
2924                                 init_sec_access(&acc,FILE_GENERIC_ALL);
2925                                 init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, acc,
2926                                                 SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2927                                                 SEC_ACE_FLAG_INHERIT_ONLY|0);
2928                         }
2929
2930                         /*
2931                          * Merge POSIX default ACLs and normal ACLs into one NT ACE.
2932                          * Win2K needs this to get the inheritance correct when replacing ACLs
2933                          * on a directory tree. Based on work by Jim @ IBM.
2934                          */
2935
2936                         num_aces = merge_default_aces(nt_ace_list, num_aces);
2937
2938                 }
2939
2940                 if (num_aces) {
2941                         if((psa = make_sec_acl( main_loop_talloc_get(), NT4_ACL_REVISION, num_aces, nt_ace_list)) == NULL) {
2942                                 DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
2943                                 goto done;
2944                         }
2945                 }
2946         } /* security_info & DACL_SECURITY_INFORMATION */
2947
2948         psd = make_standard_sec_desc( main_loop_talloc_get(),
2949                         (security_info & OWNER_SECURITY_INFORMATION) ? &owner_sid : NULL,
2950                         (security_info & GROUP_SECURITY_INFORMATION) ? &group_sid : NULL,
2951                         psa,
2952                         &sd_size);
2953
2954         if(!psd) {
2955                 DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
2956                 sd_size = 0;
2957                 goto done;
2958         }
2959
2960         /*
2961          * Windows 2000: The DACL_PROTECTED flag in the security
2962          * descriptor marks the ACL as non-inheriting, i.e., no
2963          * ACEs from higher level directories propagate to this
2964          * ACL. In the POSIX ACL model permissions are only
2965          * inherited at file create time, so ACLs never contain
2966          * any ACEs that are inherited dynamically. The DACL_PROTECTED
2967          * flag doesn't seem to bother Windows NT.
2968          * Always set this if map acl inherit is turned off.
2969          */
2970         if (get_protected_flag(pal) || !lp_map_acl_inherit(SNUM(conn))) {
2971                 psd->type |= SE_DESC_DACL_PROTECTED;
2972         }
2973
2974         if (psd->dacl) {
2975                 dacl_sort_into_canonical_order(psd->dacl->ace, (unsigned int)psd->dacl->num_aces);
2976         }
2977
2978         *ppdesc = psd;
2979
2980  done:
2981
2982         if (posix_acl) {
2983                 SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
2984         }
2985         if (def_acl) {
2986                 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
2987         }
2988         free_canon_ace_list(file_ace);
2989         free_canon_ace_list(dir_ace);
2990         free_inherited_info(pal);
2991         SAFE_FREE(nt_ace_list);
2992
2993         return sd_size;
2994 }
2995
2996 /****************************************************************************
2997  Try to chown a file. We will be able to chown it under the following conditions.
2998
2999   1) If we have root privileges, then it will just work.
3000   2) If we have SeTakeOwnershipPrivilege we can change the user to the current user.
3001   3) If we have write permission to the file and dos_filemodes is set
3002      then allow chown to the currently authenticated user.
3003 ****************************************************************************/
3004
3005 static int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid)
3006 {
3007         int ret;
3008         files_struct *fsp;
3009         SMB_STRUCT_STAT st;
3010         SE_PRIV se_take_ownership = SE_TAKE_OWNERSHIP;
3011
3012         if(!CAN_WRITE(conn)) {
3013                 return -1;
3014         }
3015
3016         /* Case (1). */
3017         /* try the direct way first */
3018         ret = SMB_VFS_CHOWN(conn, fname, uid, gid);
3019         if (ret == 0)
3020                 return 0;
3021
3022         /* Case (2). */
3023         if (lp_enable_privileges() &&
3024                         (uid == current_user.uid) &&
3025                         (user_has_privileges(current_user.nt_user_token,&se_take_ownership))) {
3026                 become_root();
3027                 /* Keep the current file gid the same - take ownership doesn't imply group change. */
3028                 ret = SMB_VFS_CHOWN(conn, fname, uid, (gid_t)-1);
3029                 unbecome_root();
3030                 return ret;
3031         }
3032
3033         /* Case (3). */
3034         if (!lp_dos_filemode(SNUM(conn))) {
3035                 return -1;
3036         }
3037
3038         if (SMB_VFS_STAT(conn,fname,&st)) {
3039                 return -1;
3040         }
3041
3042         fsp = open_file_fchmod(conn,fname,&st);
3043         if (!fsp) {
3044                 return -1;
3045         }
3046
3047         /* only allow chown to the current user. This is more secure,
3048            and also copes with the case where the SID in a take ownership ACL is
3049            a local SID on the users workstation 
3050         */
3051         uid = current_user.uid;
3052
3053         become_root();
3054         /* Keep the current file gid the same. */
3055         ret = SMB_VFS_FCHOWN(fsp, fsp->fh->fd, uid, (gid_t)-1);
3056         unbecome_root();
3057
3058         close_file_fchmod(fsp);
3059
3060         return ret;
3061 }
3062
3063 /****************************************************************************
3064  Reply to set a security descriptor on an fsp. security_info_sent is the
3065  description of the following NT ACL.
3066  This should be the only external function needed for the UNIX style set ACL.
3067 ****************************************************************************/
3068
3069 BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
3070 {
3071         connection_struct *conn = fsp->conn;
3072         uid_t user = (uid_t)-1;
3073         gid_t grp = (gid_t)-1;
3074         SMB_STRUCT_STAT sbuf;  
3075         DOM_SID file_owner_sid;
3076         DOM_SID file_grp_sid;
3077         canon_ace *file_ace_list = NULL;
3078         canon_ace *dir_ace_list = NULL;
3079         BOOL acl_perms = False;
3080         mode_t orig_mode = (mode_t)0;
3081         uid_t orig_uid;
3082         gid_t orig_gid;
3083         BOOL need_chown = False;
3084
3085         DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name ));
3086
3087         if (!CAN_WRITE(conn)) {
3088                 DEBUG(10,("set acl rejected on read-only share\n"));
3089                 return False;
3090         }
3091
3092         /*
3093          * Get the current state of the file.
3094          */
3095
3096         if(fsp->is_directory || fsp->fh->fd == -1) {
3097                 if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0)
3098                         return False;
3099         } else {
3100                 if(SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf) != 0)
3101                         return False;
3102         }
3103
3104         /* Save the original elements we check against. */
3105         orig_mode = sbuf.st_mode;
3106         orig_uid = sbuf.st_uid;
3107         orig_gid = sbuf.st_gid;
3108
3109         /*
3110          * Unpack the user/group/world id's.
3111          */
3112
3113         if (!unpack_nt_owners( SNUM(conn), &sbuf, &user, &grp, security_info_sent, psd)) {
3114                 return False;
3115         }
3116
3117         /*
3118          * Do we need to chown ?
3119          */
3120
3121         if (((user != (uid_t)-1) && (orig_uid != user)) || (( grp != (gid_t)-1) && (orig_gid != grp))) {
3122                 need_chown = True;
3123         }
3124
3125         /*
3126          * Chown before setting ACL only if we don't change the user, or
3127          * if we change to the current user, but not if we want to give away
3128          * the file.
3129          */
3130
3131         if (need_chown && (user == (uid_t)-1 || user == current_user.uid)) {
3132
3133                 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
3134                                 fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
3135
3136                 if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
3137                         DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
3138                                 fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
3139                         return False;
3140                 }
3141
3142                 /*
3143                  * Recheck the current state of the file, which may have changed.
3144                  * (suid/sgid bits, for instance)
3145                  */
3146
3147                 if(fsp->is_directory) {
3148                         if(SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf) != 0) {
3149                                 return False;
3150                         }
3151                 } else {
3152
3153                         int ret;
3154     
3155                         if(fsp->fh->fd == -1)
3156                                 ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf);
3157                         else
3158                                 ret = SMB_VFS_FSTAT(fsp,fsp->fh->fd,&sbuf);
3159   
3160                         if(ret != 0)
3161                                 return False;
3162                 }
3163
3164                 /* Save the original elements we check against. */
3165                 orig_mode = sbuf.st_mode;
3166                 orig_uid = sbuf.st_uid;
3167                 orig_gid = sbuf.st_gid;
3168
3169                 /* We did it, don't try again */
3170                 need_chown = False;
3171         }
3172
3173         create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid);
3174
3175         acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid,
3176                                         &file_ace_list, &dir_ace_list, security_info_sent, psd);
3177
3178         /* Ignore W2K traverse DACL set. */
3179         if (file_ace_list || dir_ace_list) {
3180
3181                 if (!acl_perms) {
3182                         DEBUG(3,("set_nt_acl: cannot set permissions\n"));
3183                         free_canon_ace_list(file_ace_list);
3184                         free_canon_ace_list(dir_ace_list); 
3185                         return False;
3186                 }
3187
3188                 /*
3189                  * Only change security if we got a DACL.
3190                  */
3191
3192                 if((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl != NULL)) {
3193
3194                         BOOL acl_set_support = False;
3195                         BOOL ret = False;
3196
3197                         /*
3198                          * Try using the POSIX ACL set first. Fall back to chmod if
3199                          * we have no ACL support on this filesystem.
3200                          */
3201
3202                         if (acl_perms && file_ace_list) {
3203                                 ret = set_canon_ace_list(fsp, file_ace_list, False, sbuf.st_gid, &acl_set_support);
3204                                 if (acl_set_support && ret == False) {
3205                                         DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) ));
3206                                         free_canon_ace_list(file_ace_list);
3207                                         free_canon_ace_list(dir_ace_list); 
3208                                         return False;
3209                                 }
3210                         }
3211
3212                         if (acl_perms && acl_set_support && fsp->is_directory) {
3213                                 if (dir_ace_list) {
3214                                         if (!set_canon_ace_list(fsp, dir_ace_list, True, sbuf.st_gid, &acl_set_support)) {
3215                                                 DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) ));
3216                                                 free_canon_ace_list(file_ace_list);
3217                                                 free_canon_ace_list(dir_ace_list); 
3218                                                 return False;
3219                                         }
3220                                 } else {
3221
3222                                         /*
3223                                          * No default ACL - delete one if it exists.
3224                                          */
3225
3226                                         if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name) == -1) {
3227                                                 int sret = -1;
3228
3229                                                 if (acl_group_override(conn, sbuf.st_gid)) {
3230                                                         DEBUG(5,("set_nt_acl: acl group control on and "
3231                                                                 "current user in file %s primary group. Override delete_def_acl\n",
3232                                                                 fsp->fsp_name ));
3233
3234                                                         become_root();
3235                                                         sret = SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name);
3236                                                         unbecome_root();
3237                                                 }
3238
3239                                                 if (sret == -1) {
3240                                                         DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno)));
3241                                                         free_canon_ace_list(file_ace_list);
3242                                                         free_canon_ace_list(dir_ace_list);
3243                                                         return False;
3244                                                 }
3245                                         }
3246                                 }
3247                         }
3248
3249                         if (acl_set_support) {
3250                                 store_inheritance_attributes(fsp, file_ace_list, dir_ace_list,
3251                                                 (psd->type & SE_DESC_DACL_PROTECTED) ? True : False);
3252                         }
3253
3254                         /*
3255                          * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
3256                          */
3257
3258                         if(!acl_set_support && acl_perms) {
3259                                 mode_t posix_perms;
3260
3261                                 if (!convert_canon_ace_to_posix_perms( fsp, file_ace_list, &posix_perms)) {
3262                                         free_canon_ace_list(file_ace_list);
3263                                         free_canon_ace_list(dir_ace_list);
3264                                         DEBUG(3,("set_nt_acl: failed to convert file acl to posix permissions for file %s.\n",
3265                                                 fsp->fsp_name ));
3266                                         return False;
3267                                 }
3268
3269                                 if (orig_mode != posix_perms) {
3270
3271                                         DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
3272                                                 fsp->fsp_name, (unsigned int)posix_perms ));
3273
3274                                         if(SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms) == -1) {
3275                                                 int sret = -1;
3276                                                 if (acl_group_override(conn, sbuf.st_gid)) {
3277                                                         DEBUG(5,("set_nt_acl: acl group control on and "
3278                                                                 "current user in file %s primary group. Override chmod\n",
3279                                                                 fsp->fsp_name ));
3280
3281                                                         become_root();
3282                                                         sret = SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms);
3283                                                         unbecome_root();
3284                                                 }
3285
3286                                                 if (sret == -1) {
3287                                                         DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n",
3288                                                                 fsp->fsp_name, (unsigned int)posix_perms, strerror(errno) ));
3289                                                         free_canon_ace_list(file_ace_list);
3290                                                         free_canon_ace_list(dir_ace_list);
3291                                                         return False;
3292                                                 }
3293                                         }
3294                                 }
3295                         }
3296                 }
3297
3298                 free_canon_ace_list(file_ace_list);
3299                 free_canon_ace_list(dir_ace_list); 
3300         }
3301
3302         /* Any chown pending? */
3303         if (need_chown) {
3304
3305                 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
3306                         fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
3307
3308                 if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
3309                         DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
3310                                 fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
3311                         return False;
3312                 }
3313         }
3314
3315         return True;
3316 }
3317
3318 /****************************************************************************
3319  Get the actual group bits stored on a file with an ACL. Has no effect if
3320  the file has no ACL. Needed in dosmode code where the stat() will return
3321  the mask bits, not the real group bits, for a file with an ACL.
3322 ****************************************************************************/
3323
3324 int get_acl_group_bits( connection_struct *conn, const char *fname, mode_t *mode )
3325 {
3326         int entry_id = SMB_ACL_FIRST_ENTRY;
3327         SMB_ACL_ENTRY_T entry;
3328         SMB_ACL_T posix_acl;
3329         int result = -1;
3330
3331         posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS);
3332         if (posix_acl == (SMB_ACL_T)NULL)
3333                 return -1;
3334
3335         while (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
3336                 SMB_ACL_TAG_T tagtype;
3337                 SMB_ACL_PERMSET_T permset;
3338
3339                 /* get_next... */
3340                 if (entry_id == SMB_ACL_FIRST_ENTRY)
3341                         entry_id = SMB_ACL_NEXT_ENTRY;
3342
3343                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) ==-1)
3344                         break;
3345
3346                 if (tagtype == SMB_ACL_GROUP_OBJ) {
3347                         if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
3348                                 break;
3349                         } else {
3350                                 *mode &= ~(S_IRGRP|S_IWGRP|S_IXGRP);
3351                                 *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRGRP : 0);
3352                                 *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWGRP : 0);
3353                                 *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXGRP : 0);
3354                                 result = 0;
3355                                 break;
3356                         }
3357                 }
3358         }
3359         SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
3360         return result;
3361 }
3362
3363 /****************************************************************************
3364  Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3365  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3366 ****************************************************************************/
3367
3368 static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mode_t mode)
3369 {
3370         int entry_id = SMB_ACL_FIRST_ENTRY;
3371         SMB_ACL_ENTRY_T entry;
3372         int num_entries = 0;
3373
3374         while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
3375                 SMB_ACL_TAG_T tagtype;
3376                 SMB_ACL_PERMSET_T permset;
3377                 mode_t perms;
3378
3379                 /* get_next... */
3380                 if (entry_id == SMB_ACL_FIRST_ENTRY)
3381                         entry_id = SMB_ACL_NEXT_ENTRY;
3382
3383                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
3384                         return -1;
3385
3386                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
3387                         return -1;
3388
3389                 num_entries++;
3390
3391                 switch(tagtype) {
3392                         case SMB_ACL_USER_OBJ:
3393                                 perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
3394                                 break;
3395                         case SMB_ACL_GROUP_OBJ:
3396                                 perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
3397                                 break;
3398                         case SMB_ACL_MASK:
3399                                 /*
3400                                  * FIXME: The ACL_MASK entry permissions should really be set to
3401                                  * the union of the permissions of all ACL_USER,
3402                                  * ACL_GROUP_OBJ, and ACL_GROUP entries. That's what
3403                                  * acl_calc_mask() does, but Samba ACLs doesn't provide it.
3404                                  */
3405                                 perms = S_IRUSR|S_IWUSR|S_IXUSR;
3406                                 break;
3407                         case SMB_ACL_OTHER:
3408                                 perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
3409                                 break;
3410                         default:
3411                                 continue;
3412                 }
3413
3414                 if (map_acl_perms_to_permset(conn, perms, &permset) == -1)
3415                         return -1;
3416
3417                 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, entry, permset) == -1)
3418                         return -1;
3419         }
3420
3421         /*
3422          * If this is a simple 3 element ACL or no elements then it's a standard
3423          * UNIX permission set. Just use chmod...       
3424          */
3425
3426         if ((num_entries == 3) || (num_entries == 0))
3427                 return -1;
3428
3429         return 0;
3430 }
3431
3432 /****************************************************************************
3433  Get the access ACL of FROM, do a chmod by setting the ACL USER_OBJ,
3434  GROUP_OBJ and OTHER bits in an ACL and set the mask to rwx. Set the
3435  resulting ACL on TO.  Note that name is in UNIX character set.
3436 ****************************************************************************/
3437
3438 static int copy_access_acl(connection_struct *conn, const char *from, const char *to, mode_t mode)
3439 {
3440         SMB_ACL_T posix_acl = NULL;
3441         int ret = -1;
3442
3443         if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, from, SMB_ACL_TYPE_ACCESS)) == NULL)
3444                 return -1;
3445
3446         if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
3447                 goto done;
3448
3449         ret = SMB_VFS_SYS_ACL_SET_FILE(conn, to, SMB_ACL_TYPE_ACCESS, posix_acl);
3450
3451  done:
3452
3453         SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
3454         return ret;
3455 }
3456
3457 /****************************************************************************
3458  Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3459  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3460  Note that name is in UNIX character set.
3461 ****************************************************************************/
3462
3463 int chmod_acl(connection_struct *conn, const char *name, mode_t mode)
3464 {
3465         return copy_access_acl(conn, name, name, mode);
3466 }
3467
3468 /****************************************************************************
3469  If "inherit permissions" is set and the parent directory has no default
3470  ACL but it does have an Access ACL, inherit this Access ACL to file name.
3471 ****************************************************************************/
3472
3473 int inherit_access_acl(connection_struct *conn, const char *name, mode_t mode)
3474 {
3475         pstring dirname;
3476         pstrcpy(dirname, parent_dirname(name));
3477
3478         if (!lp_inherit_perms(SNUM(conn)) || directory_has_default_acl(conn, dirname))
3479                 return 0;
3480
3481         return copy_access_acl(conn, dirname, name, mode);
3482 }
3483
3484 /****************************************************************************
3485  Do an fchmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3486  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3487 ****************************************************************************/
3488
3489 int fchmod_acl(files_struct *fsp, int fd, mode_t mode)
3490 {
3491         connection_struct *conn = fsp->conn;
3492         SMB_ACL_T posix_acl = NULL;
3493         int ret = -1;
3494
3495         if ((posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fd)) == NULL)
3496                 return -1;
3497
3498         if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
3499                 goto done;
3500
3501         ret = SMB_VFS_SYS_ACL_SET_FD(fsp, fd, posix_acl);
3502
3503   done:
3504
3505         SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
3506         return ret;
3507 }
3508
3509 /****************************************************************************
3510  Check for an existing default POSIX ACL on a directory.
3511 ****************************************************************************/
3512
3513 BOOL directory_has_default_acl(connection_struct *conn, const char *fname)
3514 {
3515         SMB_ACL_T def_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_DEFAULT);
3516         BOOL has_acl = False;
3517         SMB_ACL_ENTRY_T entry;
3518
3519         if (def_acl != NULL && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, def_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1)) {
3520                 has_acl = True;
3521         }
3522
3523         if (def_acl) {
3524                 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
3525         }
3526         return has_acl;
3527 }
3528
3529 /****************************************************************************
3530  Map from wire type to permset.
3531 ****************************************************************************/
3532
3533 static BOOL unix_ex_wire_to_permset(connection_struct *conn, unsigned char wire_perm, SMB_ACL_PERMSET_T *p_permset)
3534 {
3535         if (wire_perm & ~(SMB_POSIX_ACL_READ|SMB_POSIX_ACL_WRITE|SMB_POSIX_ACL_EXECUTE)) {
3536                 return False;
3537         }
3538
3539         if (SMB_VFS_SYS_ACL_CLEAR_PERMS(conn, *p_permset) ==  -1) {
3540                 return False;
3541         }
3542
3543         if (wire_perm & SMB_POSIX_ACL_READ) {
3544                 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_READ) == -1) {
3545                         return False;
3546                 }
3547         }
3548         if (wire_perm & SMB_POSIX_ACL_WRITE) {
3549                 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_WRITE) == -1) {
3550                         return False;
3551                 }
3552         }
3553         if (wire_perm & SMB_POSIX_ACL_EXECUTE) {
3554                 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_EXECUTE) == -1) {
3555                         return False;
3556                 }
3557         }
3558         return True;
3559 }
3560
3561 /****************************************************************************
3562  Map from wire type to tagtype.
3563 ****************************************************************************/
3564
3565 static BOOL unix_ex_wire_to_tagtype(unsigned char wire_tt, SMB_ACL_TAG_T *p_tt)
3566 {
3567         switch (wire_tt) {
3568                 case SMB_POSIX_ACL_USER_OBJ:
3569                         *p_tt = SMB_ACL_USER_OBJ;
3570                         break;
3571                 case SMB_POSIX_ACL_USER:
3572                         *p_tt = SMB_ACL_USER;
3573                         break;
3574                 case SMB_POSIX_ACL_GROUP_OBJ:
3575                         *p_tt = SMB_ACL_GROUP_OBJ;
3576                         break;
3577                 case SMB_POSIX_ACL_GROUP:
3578                         *p_tt = SMB_ACL_GROUP;
3579                         break;
3580                 case SMB_POSIX_ACL_MASK:
3581                         *p_tt = SMB_ACL_MASK;
3582                         break;
3583                 case SMB_POSIX_ACL_OTHER:
3584                         *p_tt = SMB_ACL_OTHER;
3585                         break;
3586                 default:
3587                         return False;
3588         }
3589         return True;
3590 }
3591
3592 /****************************************************************************
3593  Create a new POSIX acl from wire permissions.
3594  FIXME ! How does the share mask/mode fit into this.... ?
3595 ****************************************************************************/
3596
3597 static SMB_ACL_T create_posix_acl_from_wire(connection_struct *conn, uint16 num_acls, const char *pdata)
3598 {
3599         unsigned int i;
3600         SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, num_acls);
3601
3602         if (the_acl == NULL) {
3603                 return NULL;
3604         }
3605
3606         for (i = 0; i < num_acls; i++) {
3607                 SMB_ACL_ENTRY_T the_entry;
3608                 SMB_ACL_PERMSET_T the_permset;
3609                 SMB_ACL_TAG_T tag_type;
3610
3611                 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) {
3612                         DEBUG(0,("create_posix_acl_from_wire: Failed to create entry %u. (%s)\n",
3613                                 i, strerror(errno) ));
3614                         goto fail;
3615                 }
3616
3617                 if (!unix_ex_wire_to_tagtype(CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)), &tag_type)) {
3618                         DEBUG(0,("create_posix_acl_from_wire: invalid wire tagtype %u on entry %u.\n",
3619                                 CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)), i ));
3620                         goto fail;
3621                 }
3622
3623                 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, tag_type) == -1) {
3624                         DEBUG(0,("create_posix_acl_from_wire: Failed to set tagtype on entry %u. (%s)\n",
3625                                 i, strerror(errno) ));
3626                         goto fail;
3627                 }
3628
3629                 /* Get the permset pointer from the new ACL entry. */
3630                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) {
3631                         DEBUG(0,("create_posix_acl_from_wire: Failed to get permset on entry %u. (%s)\n",
3632                                 i, strerror(errno) ));
3633                         goto fail;
3634                 }
3635
3636                 /* Map from wire to permissions. */
3637                 if (!unix_ex_wire_to_permset(conn, CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+1), &the_permset)) {
3638                         DEBUG(0,("create_posix_acl_from_wire: invalid permset %u on entry %u.\n",
3639                                 CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE) + 1), i ));
3640                         goto fail;
3641                 }
3642
3643                 /* Now apply to the new ACL entry. */
3644                 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) {
3645                         DEBUG(0,("create_posix_acl_from_wire: Failed to add permset on entry %u. (%s)\n",
3646                                 i, strerror(errno) ));
3647                         goto fail;
3648                 }
3649
3650                 if (tag_type == SMB_ACL_USER) {
3651                         uint32 uidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3652                         uid_t uid = (uid_t)uidval;
3653                         if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&uid) == -1) {
3654                                 DEBUG(0,("create_posix_acl_from_wire: Failed to set uid %u on entry %u. (%s)\n",
3655                                         (unsigned int)uid, i, strerror(errno) ));
3656                                 goto fail;
3657                         }
3658                 }
3659
3660                 if (tag_type == SMB_ACL_GROUP) {
3661                         uint32 gidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3662                         gid_t gid = (uid_t)gidval;
3663                         if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&gid) == -1) {
3664                                 DEBUG(0,("create_posix_acl_from_wire: Failed to set gid %u on entry %u. (%s)\n",
3665                                         (unsigned int)gid, i, strerror(errno) ));
3666                                 goto fail;
3667                         }
3668                 }
3669         }
3670
3671         return the_acl;
3672
3673  fail:
3674
3675         if (the_acl != NULL) {
3676                 SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
3677         }
3678         return NULL;
3679 }
3680
3681 /****************************************************************************
3682  Calls from UNIX extensions - Default POSIX ACL set.
3683  If num_def_acls == 0 and not a directory just return. If it is a directory
3684  and num_def_acls == 0 then remove the default acl. Else set the default acl
3685  on the directory.
3686 ****************************************************************************/
3687
3688 BOOL set_unix_posix_default_acl(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf,
3689                                 uint16 num_def_acls, const char *pdata)
3690 {
3691         SMB_ACL_T def_acl = NULL;
3692
3693         if (num_def_acls && !S_ISDIR(psbuf->st_mode)) {
3694                 DEBUG(5,("set_unix_posix_default_acl: Can't set default ACL on non-directory file %s\n", fname ));
3695                 errno = EISDIR;
3696                 return False;
3697         }
3698
3699         if (!num_def_acls) {
3700                 /* Remove the default ACL. */
3701                 if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fname) == -1) {
3702                         DEBUG(5,("set_unix_posix_default_acl: acl_delete_def_file failed on directory %s (%s)\n",
3703                                 fname, strerror(errno) ));
3704                         return False;
3705                 }
3706                 return True;
3707         }
3708
3709         if ((def_acl = create_posix_acl_from_wire(conn, num_def_acls, pdata)) == NULL) {
3710                 return False;
3711         }
3712
3713         if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_DEFAULT, def_acl) == -1) {
3714                 DEBUG(5,("set_unix_posix_default_acl: acl_set_file failed on directory %s (%s)\n",
3715                         fname, strerror(errno) ));
3716                 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
3717                 return False;
3718         }
3719
3720         DEBUG(10,("set_unix_posix_default_acl: set default acl for file %s\n", fname ));
3721         SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
3722         return True;
3723 }
3724
3725 /****************************************************************************
3726  Remove an ACL from a file. As we don't have acl_delete_entry() available
3727  we must read the current acl and copy all entries except MASK, USER and GROUP
3728  to a new acl, then set that. This (at least on Linux) causes any ACL to be
3729  removed.
3730  FIXME ! How does the share mask/mode fit into this.... ?
3731 ****************************************************************************/
3732
3733 static BOOL remove_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname)
3734 {
3735         SMB_ACL_T file_acl = NULL;
3736         int entry_id = SMB_ACL_FIRST_ENTRY;
3737         SMB_ACL_ENTRY_T entry;
3738         BOOL ret = False;
3739         /* Create a new ACL with only 3 entries, u/g/w. */
3740         SMB_ACL_T new_file_acl = SMB_VFS_SYS_ACL_INIT(conn, 3);
3741         SMB_ACL_ENTRY_T user_ent = NULL;
3742         SMB_ACL_ENTRY_T group_ent = NULL;
3743         SMB_ACL_ENTRY_T other_ent = NULL;
3744
3745         if (new_file_acl == NULL) {
3746                 DEBUG(5,("remove_posix_acl: failed to init new ACL with 3 entries for file %s.\n", fname));
3747                 return False;
3748         }
3749
3750         /* Now create the u/g/w entries. */
3751         if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &user_ent) == -1) {
3752                 DEBUG(5,("remove_posix_acl: Failed to create user entry for file %s. (%s)\n",
3753                         fname, strerror(errno) ));
3754                 goto done;
3755         }
3756         if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, user_ent, SMB_ACL_USER_OBJ) == -1) {
3757                 DEBUG(5,("remove_posix_acl: Failed to set user entry for file %s. (%s)\n",
3758                         fname, strerror(errno) ));
3759                 goto done;
3760         }
3761
3762         if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &group_ent) == -1) {
3763                 DEBUG(5,("remove_posix_acl: Failed to create group entry for file %s. (%s)\n",
3764                         fname, strerror(errno) ));
3765                 goto done;
3766         }
3767         if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, group_ent, SMB_ACL_GROUP_OBJ) == -1) {
3768                 DEBUG(5,("remove_posix_acl: Failed to set group entry for file %s. (%s)\n",
3769                         fname, strerror(errno) ));
3770                 goto done;
3771         }
3772
3773         if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &other_ent) == -1) {
3774                 DEBUG(5,("remove_posix_acl: Failed to create other entry for file %s. (%s)\n",
3775                         fname, strerror(errno) ));
3776                 goto done;
3777         }
3778         if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, other_ent, SMB_ACL_OTHER) == -1) {
3779                 DEBUG(5,("remove_posix_acl: Failed to set other entry for file %s. (%s)\n",
3780                         fname, strerror(errno) ));
3781                 goto done;
3782         }
3783
3784         /* Get the current file ACL. */
3785         if (fsp && fsp->fh->fd != -1) {
3786                 file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fh->fd);
3787         } else {
3788                 file_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_ACCESS);
3789         }
3790
3791         if (file_acl == NULL) {
3792                 /* This is only returned if an error occurred. Even for a file with
3793                    no acl a u/g/w acl should be returned. */
3794                 DEBUG(5,("remove_posix_acl: failed to get ACL from file %s (%s).\n",
3795                         fname, strerror(errno) ));
3796                 goto done;
3797         }
3798
3799         while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, file_acl, entry_id, &entry) == 1) {
3800                 SMB_ACL_TAG_T tagtype;
3801                 SMB_ACL_PERMSET_T permset;
3802
3803                 /* get_next... */
3804                 if (entry_id == SMB_ACL_FIRST_ENTRY)
3805                         entry_id = SMB_ACL_NEXT_ENTRY;
3806
3807                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
3808                         DEBUG(5,("remove_posix_acl: failed to get tagtype from ACL on file %s (%s).\n",
3809                                 fname, strerror(errno) ));
3810                         goto done;
3811                 }
3812
3813                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
3814                         DEBUG(5,("remove_posix_acl: failed to get permset from ACL on file %s (%s).\n",
3815                                 fname, strerror(errno) ));
3816                         goto done;
3817                 }
3818
3819                 if (tagtype == SMB_ACL_USER_OBJ) {
3820                         if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, user_ent, permset) == -1) {
3821                                 DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
3822                                         fname, strerror(errno) ));
3823                         }
3824                 } else if (tagtype == SMB_ACL_GROUP_OBJ) {
3825                         if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, group_ent, permset) == -1) {
3826                                 DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
3827                                         fname, strerror(errno) ));
3828                         }
3829                 } else if (tagtype == SMB_ACL_OTHER) {
3830                         if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, other_ent, permset) == -1) {
3831                                 DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
3832                                         fname, strerror(errno) ));
3833                         }
3834                 }
3835         }
3836
3837         ret = True;
3838
3839  done:
3840
3841         if (file_acl) {
3842                 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
3843         }
3844         if (new_file_acl) {
3845                 SMB_VFS_SYS_ACL_FREE_ACL(conn, new_file_acl);
3846         }
3847         return ret;
3848 }
3849
3850 /****************************************************************************
3851  Calls from UNIX extensions - POSIX ACL set.
3852  If num_def_acls == 0 then read/modify/write acl after removing all entries
3853  except SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER.
3854 ****************************************************************************/
3855
3856 BOOL set_unix_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname, uint16 num_acls, const char *pdata)
3857 {
3858         SMB_ACL_T file_acl = NULL;
3859
3860         if (!num_acls) {
3861                 /* Remove the ACL from the file. */
3862                 return remove_posix_acl(conn, fsp, fname);
3863         }
3864
3865         if ((file_acl = create_posix_acl_from_wire(conn, num_acls, pdata)) == NULL) {
3866                 return False;
3867         }
3868
3869         if (fsp && fsp->fh->fd != -1) {
3870                 /* The preferred way - use an open fd. */
3871                 if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fh->fd, file_acl) == -1) {
3872                         DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n",
3873                                 fname, strerror(errno) ));
3874                         SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
3875                         return False;
3876                 }
3877         } else {
3878                 if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS, file_acl) == -1) {
3879                         DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n",
3880                                 fname, strerror(errno) ));
3881                         SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
3882                         return False;
3883                 }
3884         }
3885
3886         DEBUG(10,("set_unix_posix_acl: set acl for file %s\n", fname ));
3887         SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
3888         return True;
3889 }
3890
3891 /****************************************************************************
3892  Check for POSIX group ACLs. If none use stat entry.
3893  Return -1 if no match, 0 if match and denied, 1 if match and allowed.
3894 ****************************************************************************/
3895
3896 static int check_posix_acl_group_write(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf)
3897 {
3898         SMB_ACL_T posix_acl = NULL;
3899         int entry_id = SMB_ACL_FIRST_ENTRY;
3900         SMB_ACL_ENTRY_T entry;
3901         int i;
3902         BOOL seen_mask = False;
3903         int ret = -1;
3904         gid_t cu_gid;
3905
3906         if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS)) == NULL) {
3907                 goto check_stat;
3908         }
3909
3910         /* First ensure the group mask allows group read. */
3911         /* Also check any user entries (these take preference over group). */
3912
3913         while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
3914                 SMB_ACL_TAG_T tagtype;
3915                 SMB_ACL_PERMSET_T permset;
3916                 int have_write = -1;
3917
3918                 /* get_next... */
3919                 if (entry_id == SMB_ACL_FIRST_ENTRY)
3920                         entry_id = SMB_ACL_NEXT_ENTRY;
3921
3922                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
3923                         goto check_stat;
3924                 }
3925
3926                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
3927                         goto check_stat;
3928                 }
3929
3930                 have_write = SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE);
3931                 if (have_write == -1) {
3932                         goto check_stat;
3933                 }
3934
3935                 /*
3936                  * Solaris returns 2 for this if write is available.
3937                  * canonicalize to 0 or 1.
3938                  */     
3939                 have_write = (have_write ? 1 : 0);
3940
3941                 switch(tagtype) {
3942                         case SMB_ACL_MASK:
3943                                 if (!have_write) {
3944                                         /* We don't have any group or explicit user write permission. */
3945                                         ret = -1; /* Allow caller to check "other" permissions. */
3946                                         DEBUG(10,("check_posix_acl_group_write: file %s \
3947 refusing write due to mask.\n", fname));
3948                                         goto done;
3949                                 }
3950                                 seen_mask = True;
3951                                 break;
3952                         case SMB_ACL_USER:
3953                         {
3954                                 /* Check against current_user.uid. */
3955                                 uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
3956                                 if (puid == NULL) {
3957                                         goto check_stat;
3958                                 }
3959                                 if (current_user.uid == *puid) {
3960                                         /* We have a uid match but we must ensure we have seen the acl mask. */
3961                                         ret = have_write;
3962                                         DEBUG(10,("check_posix_acl_group_write: file %s \
3963 match on user %u -> %s.\n", fname, (unsigned int)*puid, ret ? "can write" : "cannot write"));
3964                                         if (seen_mask) {
3965                                                 goto done;
3966                                         }
3967                                 }
3968                                 break;
3969                         }
3970                         default:
3971                                 continue;
3972                 }
3973         }
3974
3975         /* If ret is anything other than -1 we matched on a user entry. */
3976         if (ret != -1) {
3977                 goto done;
3978         }
3979
3980         /* Next check all group entries. */
3981         entry_id = SMB_ACL_FIRST_ENTRY;
3982         while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
3983                 SMB_ACL_TAG_T tagtype;
3984                 SMB_ACL_PERMSET_T permset;
3985                 int have_write = -1;
3986
3987                 /* get_next... */
3988                 if (entry_id == SMB_ACL_FIRST_ENTRY)
3989                         entry_id = SMB_ACL_NEXT_ENTRY;
3990
3991                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
3992                         goto check_stat;
3993                 }
3994
3995                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
3996                         goto check_stat;
3997                 }
3998
3999                 have_write = SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE);
4000                 if (have_write == -1) {
4001                         goto check_stat;
4002                 }
4003
4004                 /*
4005                  * Solaris returns 2 for this if write is available.
4006                  * canonicalize to 0 or 1.
4007                  */     
4008                 have_write = (have_write ? 1 : 0);
4009
4010                 switch(tagtype) {
4011                         case SMB_ACL_GROUP:
4012                         {
4013                                 gid_t *pgid = (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
4014                                 if (pgid == NULL) {
4015                                         goto check_stat;
4016                                 }
4017
4018                                 /*
4019                                  * Does it match the current effective group
4020                                  * or supplementary groups ?
4021                                  */
4022                                 for (cu_gid = get_current_user_gid_first(&i); cu_gid != (gid_t)-1;
4023                                                         cu_gid = get_current_user_gid_next(&i)) {
4024                                         if (cu_gid == *pgid) {
4025                                                 ret = have_write;
4026                                                 DEBUG(10,("check_posix_acl_group_write: file %s \
4027 match on group %u -> can write.\n", fname, (unsigned int)cu_gid ));
4028
4029                                                 /* If we don't have write permission this entry doesn't
4030                                                         terminate the enumeration of the entries. */
4031                                                 if (have_write) {
4032                                                         goto done;
4033                                                 }
4034                                                 /* But does terminate the group iteration. */
4035                                                 break;
4036                                         }
4037                                 }
4038                                 break;
4039                         }
4040                         default:
4041                                 continue;
4042                 }
4043         }
4044
4045         /* If ret is -1 here we didn't match on the user entry or
4046            supplemental group entries. */
4047         
4048         DEBUG(10,("check_posix_acl_group_write: ret = %d before check_stat:\n", ret));
4049
4050   check_stat:
4051
4052         /* Do we match on the owning group entry ? */
4053         /*
4054          * Does it match the current effective group
4055          * or supplementary groups ?
4056          */
4057         for (cu_gid = get_current_user_gid_first(&i); cu_gid != (gid_t)-1;
4058                                         cu_gid = get_current_user_gid_next(&i)) {
4059                 if (cu_gid == psbuf->st_gid) {
4060                         ret = (psbuf->st_mode & S_IWGRP) ? 1 : 0;
4061                         DEBUG(10,("check_posix_acl_group_write: file %s \
4062 match on owning group %u -> %s.\n", fname, (unsigned int)psbuf->st_gid, ret ? "can write" : "cannot write"));
4063                         break;
4064                 }
4065         }
4066
4067         if (cu_gid == (gid_t)-1) {
4068                 DEBUG(10,("check_posix_acl_group_write: file %s \
4069 failed to match on user or group in token (ret = %d).\n", fname, ret ));
4070         }
4071
4072   done:
4073
4074         if (posix_acl) {
4075                 SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
4076         }
4077
4078         DEBUG(10,("check_posix_acl_group_write: file %s returning (ret = %d).\n", fname, ret ));
4079         return ret;
4080 }
4081
4082 /****************************************************************************
4083  Actually emulate the in-kernel access checking for delete access. We need
4084  this to successfully return ACCESS_DENIED on a file open for delete access.
4085 ****************************************************************************/
4086
4087 BOOL can_delete_file_in_directory(connection_struct *conn, const char *fname)
4088 {
4089         SMB_STRUCT_STAT sbuf;  
4090         pstring dname;
4091         int ret;
4092
4093         if (!CAN_WRITE(conn)) {
4094                 return False;
4095         }
4096
4097         /* Get the parent directory permission mask and owners. */
4098         pstrcpy(dname, parent_dirname(fname));
4099         if(SMB_VFS_STAT(conn, dname, &sbuf) != 0) {
4100                 return False;
4101         }
4102         if (!S_ISDIR(sbuf.st_mode)) {
4103                 return False;
4104         }
4105         if (current_user.uid == 0 || conn->admin_user) {
4106                 /* I'm sorry sir, I didn't know you were root... */
4107                 return True;
4108         }
4109
4110         /* Check primary owner write access. */
4111         if (current_user.uid == sbuf.st_uid) {
4112                 return (sbuf.st_mode & S_IWUSR) ? True : False;
4113         }
4114
4115 #ifdef S_ISVTX
4116         /* sticky bit means delete only by owner or root. */
4117         if (sbuf.st_mode & S_ISVTX) {
4118                 SMB_STRUCT_STAT sbuf_file;  
4119                 if(SMB_VFS_STAT(conn, fname, &sbuf_file) != 0) {
4120                         return False;
4121                 }
4122                 if (current_user.uid == sbuf_file.st_uid) {
4123                         return True;
4124                 }
4125                 return False;
4126         }
4127 #endif
4128
4129         /* Check group or explicit user acl entry write access. */
4130         ret = check_posix_acl_group_write(conn, dname, &sbuf);
4131         if (ret == 0 || ret == 1) {
4132                 return ret ? True : False;
4133         }
4134
4135         /* Finally check other write access. */
4136         return (sbuf.st_mode & S_IWOTH) ? True : False;
4137 }
4138
4139 /****************************************************************************
4140  Actually emulate the in-kernel access checking for write access. We need
4141  this to successfully check for ability to write for dos filetimes.
4142 ****************************************************************************/
4143
4144 BOOL can_write_to_file(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf)
4145 {
4146         int ret;
4147
4148         if (!CAN_WRITE(conn)) {
4149                 return False;
4150         }
4151
4152         if (current_user.uid == 0 || conn->admin_user) {
4153                 /* I'm sorry sir, I didn't know you were root... */
4154                 return True;
4155         }
4156
4157         if (!VALID_STAT(*psbuf)) {
4158                 /* Get the file permission mask and owners. */
4159                 if(SMB_VFS_STAT(conn, fname, psbuf) != 0) {
4160                         return False;
4161                 }
4162         }
4163
4164         /* Check primary owner write access. */
4165         if (current_user.uid == psbuf->st_uid) {
4166                 return (psbuf->st_mode & S_IWUSR) ? True : False;
4167         }
4168
4169         /* Check group or explicit user acl entry write access. */
4170         ret = check_posix_acl_group_write(conn, fname, psbuf);
4171         if (ret == 0 || ret == 1) {
4172                 return ret ? True : False;
4173         }
4174
4175         /* Finally check other write access. */
4176         return (psbuf->st_mode & S_IWOTH) ? True : False;
4177 }