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