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