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