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