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