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