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