r6365: Wow, how much worse does this get. From info provided by
[obnox/samba/samba-obnox.git] / source / smbd / posix_acls.c
1 /*
2    Unix SMB/CIFS implementation.
3    SMB NT Security Descriptor / Unix permission conversion.
4    Copyright (C) Jeremy Allison 1994-2000.
5    Copyright (C) Andreas Gruenbacher 2002.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 extern struct current_user current_user;
25 extern struct generic_mapping file_generic_mapping;
26
27 #undef  DBGC_CLASS
28 #define DBGC_CLASS DBGC_ACLS
29
30 /****************************************************************************
31  Data structures representing the internal ACE format.
32 ****************************************************************************/
33
34 enum ace_owner {UID_ACE, GID_ACE, WORLD_ACE};
35 enum ace_attribute {ALLOW_ACE, DENY_ACE}; /* Used for incoming NT ACLS. */
36
37 typedef union posix_id {
38                 uid_t uid;
39                 gid_t gid;
40                 int world;
41 } posix_id;
42
43 typedef struct canon_ace {
44         struct canon_ace *next, *prev;
45         SMB_ACL_TAG_T type;
46         mode_t perms; /* Only use S_I(R|W|X)USR mode bits here. */
47         DOM_SID trustee;
48         enum ace_owner owner_type;
49         enum ace_attribute attr;
50         posix_id unix_ug; 
51         BOOL inherited;
52 } canon_ace;
53
54 #define ALL_ACE_PERMS (S_IRUSR|S_IWUSR|S_IXUSR)
55
56 /*
57  * EA format of user.SAMBA_PAI (Samba_Posix_Acl_Interitance)
58  * attribute on disk.
59  *
60  * |  1   |  1   |   2         |         2           |  .... 
61  * +------+------+-------------+---------------------+-------------+--------------------+
62  * | vers | flag | num_entries | num_default_entries | ..entries.. | default_entries... |
63  * +------+------+-------------+---------------------+-------------+--------------------+
64  */
65
66 #define PAI_VERSION_OFFSET      0
67 #define PAI_FLAG_OFFSET         1
68 #define PAI_NUM_ENTRIES_OFFSET  2
69 #define PAI_NUM_DEFAULT_ENTRIES_OFFSET  4
70 #define PAI_ENTRIES_BASE        6
71
72 #define PAI_VERSION             1
73 #define PAI_ACL_FLAG_PROTECTED  0x1
74 #define PAI_ENTRY_LENGTH        5
75
76 /*
77  * In memory format of user.SAMBA_PAI attribute.
78  */
79
80 struct pai_entry {
81         struct pai_entry *next, *prev;
82         enum ace_owner owner_type;
83         posix_id unix_ug; 
84 };
85         
86 struct pai_val {
87         BOOL 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                         /* If we only got an "everyone" perm, just use that. */
1101                         if (!got_grp && got_other)
1102                                 pace->perms = pace_other->perms;
1103                         else if (got_grp && uid_entry_in_group(pace, pace_group))
1104                                 pace->perms = pace_group->perms;
1105                         else
1106                                 pace->perms = 0;
1107
1108                         apply_default_perms(fsp, pace, S_IRUSR);
1109                 } else {
1110                         pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRUSR, S_IWUSR, S_IXUSR);
1111                 }
1112
1113                 DLIST_ADD(*pp_ace, pace);
1114         }
1115
1116         if (!got_grp) {
1117                 if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) {
1118                         DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
1119                         return False;
1120                 }
1121
1122                 ZERO_STRUCTP(pace);
1123                 pace->type = SMB_ACL_GROUP_OBJ;
1124                 pace->owner_type = GID_ACE;
1125                 pace->unix_ug.uid = pst->st_gid;
1126                 pace->trustee = *pfile_grp_sid;
1127                 pace->attr = ALLOW_ACE;
1128                 if (setting_acl) {
1129                         /* If we only got an "everyone" perm, just use that. */
1130                         if (got_other)
1131                                 pace->perms = pace_other->perms;
1132                         else
1133                                 pace->perms = 0;
1134                         apply_default_perms(fsp, pace, S_IRGRP);
1135                 } else {
1136                         pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IRGRP, S_IWGRP, S_IXGRP);
1137                 }
1138
1139                 DLIST_ADD(*pp_ace, pace);
1140         }
1141
1142         if (!got_other) {
1143                 if ((pace = SMB_MALLOC_P(canon_ace)) == NULL) {
1144                         DEBUG(0,("ensure_canon_entry_valid: malloc fail.\n"));
1145                         return False;
1146                 }
1147
1148                 ZERO_STRUCTP(pace);
1149                 pace->type = SMB_ACL_OTHER;
1150                 pace->owner_type = WORLD_ACE;
1151                 pace->unix_ug.world = -1;
1152                 pace->trustee = global_sid_World;
1153                 pace->attr = ALLOW_ACE;
1154                 if (setting_acl) {
1155                         pace->perms = 0;
1156                         apply_default_perms(fsp, pace, S_IROTH);
1157                 } else
1158                         pace->perms = unix_perms_to_acl_perms(pst->st_mode, S_IROTH, S_IWOTH, S_IXOTH);
1159
1160                 DLIST_ADD(*pp_ace, pace);
1161         }
1162
1163         return True;
1164 }
1165
1166 /****************************************************************************
1167  Check if a POSIX ACL has the required SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries.
1168  If it does not have them, check if there are any entries where the trustee is the
1169  file owner or the owning group, and map these to SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ.
1170 ****************************************************************************/
1171
1172 static void check_owning_objs(canon_ace *ace, DOM_SID *pfile_owner_sid, DOM_SID *pfile_grp_sid)
1173 {
1174         BOOL got_user_obj, got_group_obj;
1175         canon_ace *current_ace;
1176         int i, entries;
1177
1178         entries = count_canon_ace_list(ace);
1179         got_user_obj = False;
1180         got_group_obj = False;
1181
1182         for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
1183                 if (current_ace->type == SMB_ACL_USER_OBJ)
1184                         got_user_obj = True;
1185                 else if (current_ace->type == SMB_ACL_GROUP_OBJ)
1186                         got_group_obj = True;
1187         }
1188         if (got_user_obj && got_group_obj) {
1189                 DEBUG(10,("check_owning_objs: ACL had owning user/group entries.\n"));
1190                 return;
1191         }
1192
1193         for (i=0, current_ace = ace; i < entries; i++, current_ace = current_ace->next) {
1194                 if (!got_user_obj && current_ace->owner_type == UID_ACE &&
1195                                 sid_equal(&current_ace->trustee, pfile_owner_sid)) {
1196                         current_ace->type = SMB_ACL_USER_OBJ;
1197                         got_user_obj = True;
1198                 }
1199                 if (!got_group_obj && current_ace->owner_type == GID_ACE &&
1200                                 sid_equal(&current_ace->trustee, pfile_grp_sid)) {
1201                         current_ace->type = SMB_ACL_GROUP_OBJ;
1202                         got_group_obj = True;
1203                 }
1204         }
1205         if (!got_user_obj)
1206                 DEBUG(10,("check_owning_objs: ACL is missing an owner entry.\n"));
1207         if (!got_group_obj)
1208                 DEBUG(10,("check_owning_objs: ACL is missing an owning group entry.\n"));
1209 }
1210
1211 /****************************************************************************
1212  Unpack a SEC_DESC into two canonical ace lists.
1213 ****************************************************************************/
1214
1215 static BOOL create_canon_ace_lists(files_struct *fsp, SMB_STRUCT_STAT *pst,
1216                                                         DOM_SID *pfile_owner_sid,
1217                                                         DOM_SID *pfile_grp_sid,
1218                                                         canon_ace **ppfile_ace, canon_ace **ppdir_ace,
1219                                                         SEC_ACL *dacl)
1220 {
1221         BOOL all_aces_are_inherit_only = (fsp->is_directory ? True : False);
1222         canon_ace *file_ace = NULL;
1223         canon_ace *dir_ace = NULL;
1224         canon_ace *tmp_ace = NULL;
1225         canon_ace *current_ace = NULL;
1226         BOOL got_dir_allow = False;
1227         BOOL got_file_allow = False;
1228         int i, j;
1229
1230         *ppfile_ace = NULL;
1231         *ppdir_ace = NULL;
1232
1233         /*
1234          * Convert the incoming ACL into a more regular form.
1235          */
1236
1237         for(i = 0; i < dacl->num_aces; i++) {
1238                 SEC_ACE *psa = &dacl->ace[i];
1239
1240                 if((psa->type != SEC_ACE_TYPE_ACCESS_ALLOWED) && (psa->type != SEC_ACE_TYPE_ACCESS_DENIED)) {
1241                         DEBUG(3,("create_canon_ace_lists: unable to set anything but an ALLOW or DENY ACE.\n"));
1242                         return False;
1243                 }
1244
1245                 if (nt4_compatible_acls()) {
1246                         /*
1247                          * The security mask may be UNIX_ACCESS_NONE which should map into
1248                          * no permissions (we overload the WRITE_OWNER bit for this) or it
1249                          * should be one of the ALL/EXECUTE/READ/WRITE bits. Arrange for this
1250                          * to be so. Any other bits override the UNIX_ACCESS_NONE bit.
1251                          */
1252
1253                         /*
1254                          * Convert GENERIC bits to specific bits.
1255                          */
1256  
1257                         se_map_generic(&psa->info.mask, &file_generic_mapping);
1258
1259                         psa->info.mask &= (UNIX_ACCESS_NONE|FILE_ALL_ACCESS);
1260
1261                         if(psa->info.mask != UNIX_ACCESS_NONE)
1262                                 psa->info.mask &= ~UNIX_ACCESS_NONE;
1263                 }
1264         }
1265
1266         /*
1267          * Deal with the fact that NT 4.x re-writes the canonical format
1268          * that we return for default ACLs. If a directory ACE is identical
1269          * to a inherited directory ACE then NT changes the bits so that the
1270          * first ACE is set to OI|IO and the second ACE for this SID is set
1271          * to CI. We need to repair this. JRA.
1272          */
1273
1274         for(i = 0; i < dacl->num_aces; i++) {
1275                 SEC_ACE *psa1 = &dacl->ace[i];
1276
1277                 for (j = i + 1; j < dacl->num_aces; j++) {
1278                         SEC_ACE *psa2 = &dacl->ace[j];
1279
1280                         if (psa1->info.mask != psa2->info.mask)
1281                                 continue;
1282
1283                         if (!sid_equal(&psa1->trustee, &psa2->trustee))
1284                                 continue;
1285
1286                         /*
1287                          * Ok - permission bits and SIDs are equal.
1288                          * Check if flags were re-written.
1289                          */
1290
1291                         if (psa1->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
1292
1293                                 psa1->flags |= (psa2->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
1294                                 psa2->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
1295                                 
1296                         } else if (psa2->flags & SEC_ACE_FLAG_INHERIT_ONLY) {
1297
1298                                 psa2->flags |= (psa1->flags & (SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT));
1299                                 psa1->flags &= ~(SEC_ACE_FLAG_CONTAINER_INHERIT|SEC_ACE_FLAG_OBJECT_INHERIT);
1300                                 
1301                         }
1302                 }
1303         }
1304
1305         for(i = 0; i < dacl->num_aces; i++) {
1306                 SEC_ACE *psa = &dacl->ace[i];
1307
1308                 /*
1309                  * Ignore non-mappable SIDs (NT Authority, BUILTIN etc).
1310                  */
1311
1312                 if (non_mappable_sid(&psa->trustee)) {
1313                         fstring str;
1314                         DEBUG(10,("create_canon_ace_lists: ignoring non-mappable SID %s\n",
1315                                 sid_to_string(str, &psa->trustee) ));
1316                         continue;
1317                 }
1318
1319                 /*
1320                  * Create a cannon_ace entry representing this NT DACL ACE.
1321                  */
1322
1323                 if ((current_ace = SMB_MALLOC_P(canon_ace)) == NULL) {
1324                         free_canon_ace_list(file_ace);
1325                         free_canon_ace_list(dir_ace);
1326                         DEBUG(0,("create_canon_ace_lists: malloc fail.\n"));
1327                         return False;
1328                 }
1329
1330                 ZERO_STRUCTP(current_ace);
1331
1332                 sid_copy(&current_ace->trustee, &psa->trustee);
1333
1334                 /*
1335                  * Try and work out if the SID is a user or group
1336                  * as we need to flag these differently for POSIX.
1337                  * Note what kind of a POSIX ACL this should map to.
1338                  */
1339
1340                 if( sid_equal(&current_ace->trustee, &global_sid_World)) {
1341                         current_ace->owner_type = WORLD_ACE;
1342                         current_ace->unix_ug.world = -1;
1343                         current_ace->type = SMB_ACL_OTHER;
1344                 } else if (sid_equal(&current_ace->trustee, &global_sid_Creator_Owner)) {
1345                         current_ace->owner_type = UID_ACE;
1346                         current_ace->unix_ug.uid = pst->st_uid;
1347                         current_ace->type = SMB_ACL_USER_OBJ;
1348
1349                         /*
1350                          * The Creator Owner entry only specifies inheritable permissions,
1351                          * never access permissions. WinNT doesn't always set the ACE to
1352                          *INHERIT_ONLY, though.
1353                          */
1354
1355                         if (nt4_compatible_acls())
1356                                 psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
1357                 } else if (sid_equal(&current_ace->trustee, &global_sid_Creator_Group)) {
1358                         current_ace->owner_type = GID_ACE;
1359                         current_ace->unix_ug.gid = pst->st_gid;
1360                         current_ace->type = SMB_ACL_GROUP_OBJ;
1361
1362                         /*
1363                          * The Creator Group entry only specifies inheritable permissions,
1364                          * never access permissions. WinNT doesn't always set the ACE to
1365                          *INHERIT_ONLY, though.
1366                          */
1367                         if (nt4_compatible_acls())
1368                                 psa->flags |= SEC_ACE_FLAG_INHERIT_ONLY;
1369
1370                 } else if (NT_STATUS_IS_OK(sid_to_uid( &current_ace->trustee, &current_ace->unix_ug.uid))) {
1371                         current_ace->owner_type = UID_ACE;
1372                         current_ace->type = SMB_ACL_USER;
1373                 } else if (NT_STATUS_IS_OK(sid_to_gid( &current_ace->trustee, &current_ace->unix_ug.gid))) {
1374                         current_ace->owner_type = GID_ACE;
1375                         current_ace->type = SMB_ACL_GROUP;
1376                 } else {
1377                         fstring str;
1378
1379                         free_canon_ace_list(file_ace);
1380                         free_canon_ace_list(dir_ace);
1381                         DEBUG(0,("create_canon_ace_lists: unable to map SID %s to uid or gid.\n",
1382                                 sid_to_string(str, &current_ace->trustee) ));
1383                         SAFE_FREE(current_ace);
1384                         return False;
1385                 }
1386
1387                 /*
1388                  * Map the given NT permissions into a UNIX mode_t containing only
1389                  * S_I(R|W|X)USR bits.
1390                  */
1391
1392                 current_ace->perms |= map_nt_perms( psa->info, S_IRUSR);
1393                 current_ace->attr = (psa->type == SEC_ACE_TYPE_ACCESS_ALLOWED) ? ALLOW_ACE : DENY_ACE;
1394                 current_ace->inherited = ((psa->flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False);
1395
1396                 /*
1397                  * Now add the created ace to either the file list, the directory
1398                  * list, or both. We *MUST* preserve the order here (hence we use
1399                  * DLIST_ADD_END) as NT ACLs are order dependent.
1400                  */
1401
1402                 if (fsp->is_directory) {
1403
1404                         /*
1405                          * We can only add to the default POSIX ACE list if the ACE is
1406                          * designed to be inherited by both files and directories.
1407                          */
1408
1409                         if ((psa->flags & (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) ==
1410                                 (SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT)) {
1411
1412                                 DLIST_ADD_END(dir_ace, current_ace, tmp_ace);
1413
1414                                 /*
1415                                  * Note if this was an allow ace. We can't process
1416                                  * any further deny ace's after this.
1417                                  */
1418
1419                                 if (current_ace->attr == ALLOW_ACE)
1420                                         got_dir_allow = True;
1421
1422                                 if ((current_ace->attr == DENY_ACE) && got_dir_allow) {
1423                                         DEBUG(0,("create_canon_ace_lists: malformed ACL in inheritable ACL ! \
1424 Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
1425                                         free_canon_ace_list(file_ace);
1426                                         free_canon_ace_list(dir_ace);
1427                                         SAFE_FREE(current_ace);
1428                                         return False;
1429                                 }       
1430
1431                                 if( DEBUGLVL( 10 )) {
1432                                         dbgtext("create_canon_ace_lists: adding dir ACL:\n");
1433                                         print_canon_ace( current_ace, 0);
1434                                 }
1435
1436                                 /*
1437                                  * If this is not an inherit only ACE we need to add a duplicate
1438                                  * to the file acl.
1439                                  */
1440
1441                                 if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
1442                                         canon_ace *dup_ace = dup_canon_ace(current_ace);
1443
1444                                         if (!dup_ace) {
1445                                                 DEBUG(0,("create_canon_ace_lists: malloc fail !\n"));
1446                                                 free_canon_ace_list(file_ace);
1447                                                 free_canon_ace_list(dir_ace);
1448                                                 return False;
1449                                         }
1450
1451                                         /*
1452                                          * We must not free current_ace here as its
1453                                          * pointer is now owned by the dir_ace list.
1454                                          */
1455                                         current_ace = dup_ace;
1456                                 } else {
1457                                         /*
1458                                          * We must not free current_ace here as its
1459                                          * pointer is now owned by the dir_ace list.
1460                                          */
1461                                         current_ace = NULL;
1462                                 }
1463                         }
1464                 }
1465
1466                 /*
1467                  * Only add to the file ACL if not inherit only.
1468                  */
1469
1470                 if (!(psa->flags & SEC_ACE_FLAG_INHERIT_ONLY)) {
1471                         DLIST_ADD_END(file_ace, current_ace, tmp_ace);
1472
1473                         /*
1474                          * Note if this was an allow ace. We can't process
1475                          * any further deny ace's after this.
1476                          */
1477
1478                         if (current_ace->attr == ALLOW_ACE)
1479                                 got_file_allow = True;
1480
1481                         if ((current_ace->attr == DENY_ACE) && got_file_allow) {
1482                                 DEBUG(0,("create_canon_ace_lists: malformed ACL in file ACL ! \
1483 Deny entry after Allow entry. Failing to set on file %s.\n", fsp->fsp_name ));
1484                                 free_canon_ace_list(file_ace);
1485                                 free_canon_ace_list(dir_ace);
1486                                 SAFE_FREE(current_ace);
1487                                 return False;
1488                         }       
1489
1490                         if( DEBUGLVL( 10 )) {
1491                                 dbgtext("create_canon_ace_lists: adding file ACL:\n");
1492                                 print_canon_ace( current_ace, 0);
1493                         }
1494                         all_aces_are_inherit_only = False;
1495                         /*
1496                          * We must not free current_ace here as its
1497                          * pointer is now owned by the file_ace list.
1498                          */
1499                         current_ace = NULL;
1500                 }
1501
1502                 /*
1503                  * Free if ACE was not added.
1504                  */
1505
1506                 SAFE_FREE(current_ace);
1507         }
1508
1509         if (fsp->is_directory && all_aces_are_inherit_only) {
1510                 /*
1511                  * Windows 2000 is doing one of these weird 'inherit acl'
1512                  * traverses to conserve NTFS ACL resources. Just pretend
1513                  * there was no DACL sent. JRA.
1514                  */
1515
1516                 DEBUG(10,("create_canon_ace_lists: Win2k inherit acl traverse. Ignoring DACL.\n"));
1517                 free_canon_ace_list(file_ace);
1518                 free_canon_ace_list(dir_ace);
1519                 file_ace = NULL;
1520                 dir_ace = NULL;
1521         } else {
1522                 /*
1523                  * Check if we have SMB_ACL_USER_OBJ and SMB_ACL_GROUP_OBJ entries in each
1524                  * ACL. If we don't have them, check if any SMB_ACL_USER/SMB_ACL_GROUP
1525                  * entries can be converted to *_OBJ. Usually we will already have these
1526                  * entries in the Default ACL, and the Access ACL will not have them.
1527                  */
1528                 check_owning_objs(file_ace, pfile_owner_sid, pfile_grp_sid);
1529                 check_owning_objs(dir_ace, pfile_owner_sid, pfile_grp_sid);
1530         }
1531
1532         *ppfile_ace = file_ace;
1533         *ppdir_ace = dir_ace;
1534
1535         return True;
1536 }
1537
1538 /****************************************************************************
1539  ASCII art time again... JRA :-).
1540
1541  We have 4 cases to process when moving from an NT ACL to a POSIX ACL. Firstly,
1542  we insist the ACL is in canonical form (ie. all DENY entries preceede ALLOW
1543  entries). Secondly, the merge code has ensured that all duplicate SID entries for
1544  allow or deny have been merged, so the same SID can only appear once in the deny
1545  list or once in the allow list.
1546
1547  We then process as follows :
1548
1549  ---------------------------------------------------------------------------
1550  First pass - look for a Everyone DENY entry.
1551
1552  If it is deny all (rwx) trunate the list at this point.
1553  Else, walk the list from this point and use the deny permissions of this
1554  entry as a mask on all following allow entries. Finally, delete
1555  the Everyone DENY entry (we have applied it to everything possible).
1556
1557  In addition, in this pass we remove any DENY entries that have 
1558  no permissions (ie. they are a DENY nothing).
1559  ---------------------------------------------------------------------------
1560  Second pass - only deal with deny user entries.
1561
1562  DENY user1 (perms XXX)
1563
1564  new_perms = 0
1565  for all following allow group entries where user1 is in group
1566         new_perms |= group_perms;
1567
1568  user1 entry perms = new_perms & ~ XXX;
1569
1570  Convert the deny entry to an allow entry with the new perms and
1571  push to the end of the list. Note if the user was in no groups
1572  this maps to a specific allow nothing entry for this user.
1573
1574  The common case from the NT ACL choser (userX deny all) is
1575  optimised so we don't do the group lookup - we just map to
1576  an allow nothing entry.
1577
1578  What we're doing here is inferring the allow permissions the
1579  person setting the ACE on user1 wanted by looking at the allow
1580  permissions on the groups the user is currently in. This will
1581  be a snapshot, depending on group membership but is the best
1582  we can do and has the advantage of failing closed rather than
1583  open.
1584  ---------------------------------------------------------------------------
1585  Third pass - only deal with deny group entries.
1586
1587  DENY group1 (perms XXX)
1588
1589  for all following allow user entries where user is in group1
1590    user entry perms = user entry perms & ~ XXX;
1591
1592  If there is a group Everyone allow entry with permissions YYY,
1593  convert the group1 entry to an allow entry and modify its
1594  permissions to be :
1595
1596  new_perms = YYY & ~ XXX
1597
1598  and push to the end of the list.
1599
1600  If there is no group Everyone allow entry then convert the
1601  group1 entry to a allow nothing entry and push to the end of the list.
1602
1603  Note that the common case from the NT ACL choser (groupX deny all)
1604  cannot be optimised here as we need to modify user entries who are
1605  in the group to change them to a deny all also.
1606
1607  What we're doing here is modifying the allow permissions of
1608  user entries (which are more specific in POSIX ACLs) to mask
1609  out the explicit deny set on the group they are in. This will
1610  be a snapshot depending on current group membership but is the
1611  best we can do and has the advantage of failing closed rather
1612  than open.
1613  ---------------------------------------------------------------------------
1614  Fourth pass - cope with cumulative permissions.
1615
1616  for all allow user entries, if there exists an allow group entry with
1617  more permissive permissions, and the user is in that group, rewrite the
1618  allow user permissions to contain both sets of permissions.
1619
1620  Currently the code for this is #ifdef'ed out as these semantics make
1621  no sense to me. JRA.
1622  ---------------------------------------------------------------------------
1623
1624  Note we *MUST* do the deny user pass first as this will convert deny user
1625  entries into allow user entries which can then be processed by the deny
1626  group pass.
1627
1628  The above algorithm took a *lot* of thinking about - hence this
1629  explaination :-). JRA.
1630 ****************************************************************************/
1631
1632 /****************************************************************************
1633  Process a canon_ace list entries. This is very complex code. We need
1634  to go through and remove the "deny" permissions from any allow entry that matches
1635  the id of this entry. We have already refused any NT ACL that wasn't in correct
1636  order (DENY followed by ALLOW). If any allow entry ends up with zero permissions,
1637  we just remove it (to fail safe). We have already removed any duplicate ace
1638  entries. Treat an "Everyone" DENY_ACE as a special case - use it to mask all
1639  allow entries.
1640 ****************************************************************************/
1641
1642 static void process_deny_list( canon_ace **pp_ace_list )
1643 {
1644         canon_ace *ace_list = *pp_ace_list;
1645         canon_ace *curr_ace = NULL;
1646         canon_ace *curr_ace_next = NULL;
1647
1648         /* Pass 1 above - look for an Everyone, deny entry. */
1649
1650         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1651                 canon_ace *allow_ace_p;
1652
1653                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1654
1655                 if (curr_ace->attr != DENY_ACE)
1656                         continue;
1657
1658                 if (curr_ace->perms == (mode_t)0) {
1659
1660                         /* Deny nothing entry - delete. */
1661
1662                         DLIST_REMOVE(ace_list, curr_ace);
1663                         continue;
1664                 }
1665
1666                 if (!sid_equal(&curr_ace->trustee, &global_sid_World))
1667                         continue;
1668
1669                 /* JRATEST - assert. */
1670                 SMB_ASSERT(curr_ace->owner_type == WORLD_ACE);
1671
1672                 if (curr_ace->perms == ALL_ACE_PERMS) {
1673
1674                         /*
1675                          * Optimisation. This is a DENY_ALL to Everyone. Truncate the
1676                          * list at this point including this entry.
1677                          */
1678
1679                         canon_ace *prev_entry = curr_ace->prev;
1680
1681                         free_canon_ace_list( curr_ace );
1682                         if (prev_entry)
1683                                 prev_entry->next = NULL;
1684                         else {
1685                                 /* We deleted the entire list. */
1686                                 ace_list = NULL;
1687                         }
1688                         break;
1689                 }
1690
1691                 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1692
1693                         /* 
1694                          * Only mask off allow entries.
1695                          */
1696
1697                         if (allow_ace_p->attr != ALLOW_ACE)
1698                                 continue;
1699
1700                         allow_ace_p->perms &= ~curr_ace->perms;
1701                 }
1702
1703                 /*
1704                  * Now it's been applied, remove it.
1705                  */
1706
1707                 DLIST_REMOVE(ace_list, curr_ace);
1708         }
1709
1710         /* Pass 2 above - deal with deny user entries. */
1711
1712         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1713                 mode_t new_perms = (mode_t)0;
1714                 canon_ace *allow_ace_p;
1715                 canon_ace *tmp_ace;
1716
1717                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1718
1719                 if (curr_ace->attr != DENY_ACE)
1720                         continue;
1721
1722                 if (curr_ace->owner_type != UID_ACE)
1723                         continue;
1724
1725                 if (curr_ace->perms == ALL_ACE_PERMS) {
1726
1727                         /*
1728                          * Optimisation - this is a deny everything to this user.
1729                          * Convert to an allow nothing and push to the end of the list.
1730                          */
1731
1732                         curr_ace->attr = ALLOW_ACE;
1733                         curr_ace->perms = (mode_t)0;
1734                         DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
1735                         continue;
1736                 }
1737
1738                 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1739
1740                         if (allow_ace_p->attr != ALLOW_ACE)
1741                                 continue;
1742
1743                         /* We process GID_ACE and WORLD_ACE entries only. */
1744
1745                         if (allow_ace_p->owner_type == UID_ACE)
1746                                 continue;
1747
1748                         if (uid_entry_in_group( curr_ace, allow_ace_p))
1749                                 new_perms |= allow_ace_p->perms;
1750                 }
1751
1752                 /*
1753                  * Convert to a allow entry, modify the perms and push to the end
1754                  * of the list.
1755                  */
1756
1757                 curr_ace->attr = ALLOW_ACE;
1758                 curr_ace->perms = (new_perms & ~curr_ace->perms);
1759                 DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
1760         }
1761
1762         /* Pass 3 above - deal with deny group entries. */
1763
1764         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1765                 canon_ace *tmp_ace;
1766                 canon_ace *allow_ace_p;
1767                 canon_ace *allow_everyone_p = NULL;
1768
1769                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1770
1771                 if (curr_ace->attr != DENY_ACE)
1772                         continue;
1773
1774                 if (curr_ace->owner_type != GID_ACE)
1775                         continue;
1776
1777                 for (allow_ace_p = curr_ace->next; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1778
1779                         if (allow_ace_p->attr != ALLOW_ACE)
1780                                 continue;
1781
1782                         /* Store a pointer to the Everyone allow, if it exists. */
1783                         if (allow_ace_p->owner_type == WORLD_ACE)
1784                                 allow_everyone_p = allow_ace_p;
1785
1786                         /* We process UID_ACE entries only. */
1787
1788                         if (allow_ace_p->owner_type != UID_ACE)
1789                                 continue;
1790
1791                         /* Mask off the deny group perms. */
1792
1793                         if (uid_entry_in_group( allow_ace_p, curr_ace))
1794                                 allow_ace_p->perms &= ~curr_ace->perms;
1795                 }
1796
1797                 /*
1798                  * Convert the deny to an allow with the correct perms and
1799                  * push to the end of the list.
1800                  */
1801
1802                 curr_ace->attr = ALLOW_ACE;
1803                 if (allow_everyone_p)
1804                         curr_ace->perms = allow_everyone_p->perms & ~curr_ace->perms;
1805                 else
1806                         curr_ace->perms = (mode_t)0;
1807                 DLIST_DEMOTE(ace_list, curr_ace, tmp_ace);
1808
1809         }
1810
1811         /* Doing this fourth pass allows Windows semantics to be layered
1812          * on top of POSIX semantics. I'm not sure if this is desirable.
1813          * For example, in W2K ACLs there is no way to say, "Group X no
1814          * access, user Y full access" if user Y is a member of group X.
1815          * This seems completely broken semantics to me.... JRA.
1816          */
1817
1818 #if 0
1819         /* Pass 4 above - deal with allow entries. */
1820
1821         for (curr_ace = ace_list; curr_ace; curr_ace = curr_ace_next) {
1822                 canon_ace *allow_ace_p;
1823
1824                 curr_ace_next = curr_ace->next; /* So we can't lose the link. */
1825
1826                 if (curr_ace->attr != ALLOW_ACE)
1827                         continue;
1828
1829                 if (curr_ace->owner_type != UID_ACE)
1830                         continue;
1831
1832                 for (allow_ace_p = ace_list; allow_ace_p; allow_ace_p = allow_ace_p->next) {
1833
1834                         if (allow_ace_p->attr != ALLOW_ACE)
1835                                 continue;
1836
1837                         /* We process GID_ACE entries only. */
1838
1839                         if (allow_ace_p->owner_type != GID_ACE)
1840                                 continue;
1841
1842                         /* OR in the group perms. */
1843
1844                         if (uid_entry_in_group( curr_ace, allow_ace_p))
1845                                 curr_ace->perms |= allow_ace_p->perms;
1846                 }
1847         }
1848 #endif
1849
1850         *pp_ace_list = ace_list;
1851 }
1852
1853 /****************************************************************************
1854  Create a default mode that will be used if a security descriptor entry has
1855  no user/group/world entries.
1856 ****************************************************************************/
1857
1858 static mode_t create_default_mode(files_struct *fsp, BOOL interitable_mode)
1859 {
1860         int snum = SNUM(fsp->conn);
1861         mode_t and_bits = (mode_t)0;
1862         mode_t or_bits = (mode_t)0;
1863         mode_t mode = interitable_mode ? unix_mode( fsp->conn, FILE_ATTRIBUTE_ARCHIVE, fsp->fsp_name, False) : S_IRUSR;
1864
1865         if (fsp->is_directory)
1866                 mode |= (S_IWUSR|S_IXUSR);
1867
1868         /*
1869          * Now AND with the create mode/directory mode bits then OR with the
1870          * force create mode/force directory mode bits.
1871          */
1872
1873         if (fsp->is_directory) {
1874                 and_bits = lp_dir_security_mask(snum);
1875                 or_bits = lp_force_dir_security_mode(snum);
1876         } else {
1877                 and_bits = lp_security_mask(snum);
1878                 or_bits = lp_force_security_mode(snum);
1879         }
1880
1881         return ((mode & and_bits)|or_bits);
1882 }
1883
1884 /****************************************************************************
1885  Unpack a SEC_DESC into two canonical ace lists. We don't depend on this
1886  succeeding.
1887 ****************************************************************************/
1888
1889 static BOOL unpack_canon_ace(files_struct *fsp, 
1890                                                         SMB_STRUCT_STAT *pst,
1891                                                         DOM_SID *pfile_owner_sid,
1892                                                         DOM_SID *pfile_grp_sid,
1893                                                         canon_ace **ppfile_ace, canon_ace **ppdir_ace,
1894                                                         uint32 security_info_sent, SEC_DESC *psd)
1895 {
1896         canon_ace *file_ace = NULL;
1897         canon_ace *dir_ace = NULL;
1898
1899         *ppfile_ace = NULL;
1900         *ppdir_ace = NULL;
1901
1902         if(security_info_sent == 0) {
1903                 DEBUG(0,("unpack_canon_ace: no security info sent !\n"));
1904                 return False;
1905         }
1906
1907         /*
1908          * If no DACL then this is a chown only security descriptor.
1909          */
1910
1911         if(!(security_info_sent & DACL_SECURITY_INFORMATION) || !psd->dacl)
1912                 return True;
1913
1914         /*
1915          * Now go through the DACL and create the canon_ace lists.
1916          */
1917
1918         if (!create_canon_ace_lists( fsp, pst, pfile_owner_sid, pfile_grp_sid,
1919                                                                 &file_ace, &dir_ace, psd->dacl))
1920                 return False;
1921
1922         if ((file_ace == NULL) && (dir_ace == NULL)) {
1923                 /* W2K traverse DACL set - ignore. */
1924                 return True;
1925         }
1926
1927         /*
1928          * Go through the canon_ace list and merge entries
1929          * belonging to identical users of identical allow or deny type.
1930          * We can do this as all deny entries come first, followed by
1931          * all allow entries (we have mandated this before accepting this acl).
1932          */
1933
1934         print_canon_ace_list( "file ace - before merge", file_ace);
1935         merge_aces( &file_ace );
1936
1937         print_canon_ace_list( "dir ace - before merge", dir_ace);
1938         merge_aces( &dir_ace );
1939
1940         /*
1941          * NT ACLs are order dependent. Go through the acl lists and
1942          * process DENY entries by masking the allow entries.
1943          */
1944
1945         print_canon_ace_list( "file ace - before deny", file_ace);
1946         process_deny_list( &file_ace);
1947
1948         print_canon_ace_list( "dir ace - before deny", dir_ace);
1949         process_deny_list( &dir_ace);
1950
1951         /*
1952          * A well formed POSIX file or default ACL has at least 3 entries, a 
1953          * SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER_OBJ
1954          * and optionally a mask entry. Ensure this is the case.
1955          */
1956
1957         print_canon_ace_list( "file ace - before valid", file_ace);
1958
1959         /*
1960          * A default 3 element mode entry for a file should be r-- --- ---.
1961          * A default 3 element mode entry for a directory should be rwx --- ---.
1962          */
1963
1964         pst->st_mode = create_default_mode(fsp, False);
1965
1966         if (!ensure_canon_entry_valid(&file_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
1967                 free_canon_ace_list(file_ace);
1968                 free_canon_ace_list(dir_ace);
1969                 return False;
1970         }
1971
1972         print_canon_ace_list( "dir ace - before valid", dir_ace);
1973
1974         /*
1975          * A default inheritable 3 element mode entry for a directory should be the
1976          * mode Samba will use to create a file within. Ensure user rwx bits are set if
1977          * it's a directory.
1978          */
1979
1980         pst->st_mode = create_default_mode(fsp, True);
1981
1982         if (dir_ace && !ensure_canon_entry_valid(&dir_ace, fsp, pfile_owner_sid, pfile_grp_sid, pst, True)) {
1983                 free_canon_ace_list(file_ace);
1984                 free_canon_ace_list(dir_ace);
1985                 return False;
1986         }
1987
1988         print_canon_ace_list( "file ace - return", file_ace);
1989         print_canon_ace_list( "dir ace - return", dir_ace);
1990
1991         *ppfile_ace = file_ace;
1992         *ppdir_ace = dir_ace;
1993         return True;
1994
1995 }
1996
1997 /******************************************************************************
1998  When returning permissions, try and fit NT display
1999  semantics if possible. Note the the canon_entries here must have been malloced.
2000  The list format should be - first entry = owner, followed by group and other user
2001  entries, last entry = other.
2002
2003  Note that this doesn't exactly match the NT semantics for an ACL. As POSIX entries
2004  are not ordered, and match on the most specific entry rather than walking a list,
2005  then a simple POSIX permission of rw-r--r-- should really map to 5 entries,
2006
2007  Entry 0: owner : deny all except read and write.
2008  Entry 1: group : deny all except read.
2009  Entry 2: owner : allow read and write.
2010  Entry 3: group : allow read.
2011  Entry 4: Everyone : allow read.
2012
2013  But NT cannot display this in their ACL editor !
2014 ********************************************************************************/
2015
2016 static void arrange_posix_perms( char *filename, canon_ace **pp_list_head)
2017 {
2018         canon_ace *list_head = *pp_list_head;
2019         canon_ace *owner_ace = NULL;
2020         canon_ace *other_ace = NULL;
2021         canon_ace *ace = NULL;
2022
2023         for (ace = list_head; ace; ace = ace->next) {
2024                 if (ace->type == SMB_ACL_USER_OBJ)
2025                         owner_ace = ace;
2026                 else if (ace->type == SMB_ACL_OTHER) {
2027                         /* Last ace - this is "other" */
2028                         other_ace = ace;
2029                 }
2030         }
2031                 
2032         if (!owner_ace || !other_ace) {
2033                 DEBUG(0,("arrange_posix_perms: Invalid POSIX permissions for file %s, missing owner or other.\n",
2034                         filename ));
2035                 return;
2036         }
2037
2038         /*
2039          * The POSIX algorithm applies to owner first, and other last,
2040          * so ensure they are arranged in this order.
2041          */
2042
2043         if (owner_ace) {
2044                 DLIST_PROMOTE(list_head, owner_ace);
2045         }
2046
2047         if (other_ace) {
2048                 DLIST_DEMOTE(list_head, other_ace, ace);
2049         }
2050
2051         /* We have probably changed the head of the list. */
2052
2053         *pp_list_head = list_head;
2054 }
2055                 
2056 /****************************************************************************
2057  Create a linked list of canonical ACE entries.
2058 ****************************************************************************/
2059
2060 static canon_ace *canonicalise_acl( files_struct *fsp, SMB_ACL_T posix_acl, SMB_STRUCT_STAT *psbuf,
2061                                         const DOM_SID *powner, const DOM_SID *pgroup, struct pai_val *pal, SMB_ACL_TYPE_T the_acl_type)
2062 {
2063         connection_struct *conn = fsp->conn;
2064         mode_t acl_mask = (S_IRUSR|S_IWUSR|S_IXUSR);
2065         canon_ace *list_head = NULL;
2066         canon_ace *ace = NULL;
2067         canon_ace *next_ace = NULL;
2068         int entry_id = SMB_ACL_FIRST_ENTRY;
2069         SMB_ACL_ENTRY_T entry;
2070         size_t ace_count;
2071
2072         while ( posix_acl && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1)) {
2073                 SMB_ACL_TAG_T tagtype;
2074                 SMB_ACL_PERMSET_T permset;
2075                 DOM_SID sid;
2076                 posix_id unix_ug;
2077                 enum ace_owner owner_type;
2078
2079                 /* get_next... */
2080                 if (entry_id == SMB_ACL_FIRST_ENTRY)
2081                         entry_id = SMB_ACL_NEXT_ENTRY;
2082
2083                 /* Is this a MASK entry ? */
2084                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
2085                         continue;
2086
2087                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
2088                         continue;
2089
2090                 /* Decide which SID to use based on the ACL type. */
2091                 switch(tagtype) {
2092                         case SMB_ACL_USER_OBJ:
2093                                 /* Get the SID from the owner. */
2094                                 sid_copy(&sid, powner);
2095                                 unix_ug.uid = psbuf->st_uid;
2096                                 owner_type = UID_ACE;
2097                                 break;
2098                         case SMB_ACL_USER:
2099                                 {
2100                                         uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
2101                                         if (puid == NULL) {
2102                                                 DEBUG(0,("canonicalise_acl: Failed to get uid.\n"));
2103                                                 continue;
2104                                         }
2105                                         /*
2106                                          * A SMB_ACL_USER entry for the owner is shadowed by the
2107                                          * SMB_ACL_USER_OBJ entry and Windows also cannot represent
2108                                          * that entry, so we ignore it. We also don't create such
2109                                          * entries out of the blue when setting ACLs, so a get/set
2110                                          * cycle will drop them.
2111                                          */
2112                                         if (the_acl_type == SMB_ACL_TYPE_ACCESS && *puid == psbuf->st_uid) {
2113                                                 SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
2114                                                 continue;
2115                                         }
2116                                         uid_to_sid( &sid, *puid);
2117                                         unix_ug.uid = *puid;
2118                                         owner_type = UID_ACE;
2119                                         SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
2120                                         break;
2121                                 }
2122                         case SMB_ACL_GROUP_OBJ:
2123                                 /* Get the SID from the owning group. */
2124                                 sid_copy(&sid, pgroup);
2125                                 unix_ug.gid = psbuf->st_gid;
2126                                 owner_type = GID_ACE;
2127                                 break;
2128                         case SMB_ACL_GROUP:
2129                                 {
2130                                         gid_t *pgid = (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
2131                                         if (pgid == NULL) {
2132                                                 DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
2133                                                 continue;
2134                                         }
2135                                         gid_to_sid( &sid, *pgid);
2136                                         unix_ug.gid = *pgid;
2137                                         owner_type = GID_ACE;
2138                                         SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)pgid,tagtype);
2139                                         break;
2140                                 }
2141                         case SMB_ACL_MASK:
2142                                 acl_mask = convert_permset_to_mode_t(conn, permset);
2143                                 continue; /* Don't count the mask as an entry. */
2144                         case SMB_ACL_OTHER:
2145                                 /* Use the Everyone SID */
2146                                 sid = global_sid_World;
2147                                 unix_ug.world = -1;
2148                                 owner_type = WORLD_ACE;
2149                                 break;
2150                         default:
2151                                 DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype));
2152                                 continue;
2153                 }
2154
2155                 /*
2156                  * Add this entry to the list.
2157                  */
2158
2159                 if ((ace = SMB_MALLOC_P(canon_ace)) == NULL)
2160                         goto fail;
2161
2162                 ZERO_STRUCTP(ace);
2163                 ace->type = tagtype;
2164                 ace->perms = convert_permset_to_mode_t(conn, permset);
2165                 ace->attr = ALLOW_ACE;
2166                 ace->trustee = sid;
2167                 ace->unix_ug = unix_ug;
2168                 ace->owner_type = owner_type;
2169                 ace->inherited = get_inherited_flag(pal, ace, (the_acl_type == SMB_ACL_TYPE_DEFAULT));
2170
2171                 DLIST_ADD(list_head, ace);
2172         }
2173
2174         /*
2175          * This next call will ensure we have at least a user/group/world set.
2176          */
2177
2178         if (!ensure_canon_entry_valid(&list_head, fsp, powner, pgroup, psbuf, False))
2179                 goto fail;
2180
2181         /*
2182          * Now go through the list, masking the permissions with the
2183          * acl_mask. Ensure all DENY Entries are at the start of the list.
2184          */
2185
2186         DEBUG(10,("canonicalise_acl: %s ace entries before arrange :\n", the_acl_type == SMB_ACL_TYPE_ACCESS ? "Access" : "Default" ));
2187
2188         for ( ace_count = 0, ace = list_head; ace; ace = next_ace, ace_count++) {
2189                 next_ace = ace->next;
2190
2191                 /* Masks are only applied to entries other than USER_OBJ and OTHER. */
2192                 if (ace->type != SMB_ACL_OTHER && ace->type != SMB_ACL_USER_OBJ)
2193                         ace->perms &= acl_mask;
2194
2195                 if (ace->perms == 0) {
2196                         DLIST_PROMOTE(list_head, ace);
2197                 }
2198
2199                 if( DEBUGLVL( 10 ) ) {
2200                         print_canon_ace(ace, ace_count);
2201                 }
2202         }
2203
2204         arrange_posix_perms(fsp->fsp_name,&list_head );
2205
2206         print_canon_ace_list( "canonicalise_acl: ace entries after arrange", list_head );
2207
2208         return list_head;
2209
2210   fail:
2211
2212         free_canon_ace_list(list_head);
2213         return NULL;
2214 }
2215
2216 /****************************************************************************
2217  Attempt to apply an ACL to a file or directory.
2218 ****************************************************************************/
2219
2220 static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL default_ace, BOOL *pacl_set_support)
2221 {
2222         connection_struct *conn = fsp->conn;
2223         BOOL ret = False;
2224         SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, (int)count_canon_ace_list(the_ace) + 1);
2225         canon_ace *p_ace;
2226         int i;
2227         SMB_ACL_ENTRY_T mask_entry;
2228         BOOL got_mask_entry = False;
2229         SMB_ACL_PERMSET_T mask_permset;
2230         SMB_ACL_TYPE_T the_acl_type = (default_ace ? SMB_ACL_TYPE_DEFAULT : SMB_ACL_TYPE_ACCESS);
2231         BOOL needs_mask = False;
2232         mode_t mask_perms = 0;
2233
2234 #if defined(POSIX_ACL_NEEDS_MASK)
2235         /* HP-UX always wants to have a mask (called "class" there). */
2236         needs_mask = True;
2237 #endif
2238
2239         if (the_acl == NULL) {
2240
2241                 if (!no_acl_syscall_error(errno)) {
2242                         /*
2243                          * Only print this error message if we have some kind of ACL
2244                          * support that's not working. Otherwise we would always get this.
2245                          */
2246                         DEBUG(0,("set_canon_ace_list: Unable to init %s ACL. (%s)\n",
2247                                 default_ace ? "default" : "file", strerror(errno) ));
2248                 }
2249                 *pacl_set_support = False;
2250                 return False;
2251         }
2252
2253         if( DEBUGLVL( 10 )) {
2254                 dbgtext("set_canon_ace_list: setting ACL:\n");
2255                 for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
2256                         print_canon_ace( p_ace, i);
2257                 }
2258         }
2259
2260         for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
2261                 SMB_ACL_ENTRY_T the_entry;
2262                 SMB_ACL_PERMSET_T the_permset;
2263
2264                 /*
2265                  * ACLs only "need" an ACL_MASK entry if there are any named user or
2266                  * named group entries. But if there is an ACL_MASK entry, it applies
2267                  * to ACL_USER, ACL_GROUP, and ACL_GROUP_OBJ entries. Set the mask
2268                  * so that it doesn't deny (i.e., mask off) any permissions.
2269                  */
2270
2271                 if (p_ace->type == SMB_ACL_USER || p_ace->type == SMB_ACL_GROUP) {
2272                         needs_mask = True;
2273                         mask_perms |= p_ace->perms;
2274                 } else if (p_ace->type == SMB_ACL_GROUP_OBJ) {
2275                         mask_perms |= p_ace->perms;
2276                 }
2277
2278                 /*
2279                  * Get the entry for this ACE.
2280                  */
2281
2282                 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) {
2283                         DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n",
2284                                 i, strerror(errno) ));
2285                         goto done;
2286                 }
2287
2288                 if (p_ace->type == SMB_ACL_MASK) {
2289                         mask_entry = the_entry;
2290                         got_mask_entry = True;
2291                 }
2292
2293                 /*
2294                  * Ok - we now know the ACL calls should be working, don't
2295                  * allow fallback to chmod.
2296                  */
2297
2298                 *pacl_set_support = True;
2299
2300                 /*
2301                  * Initialise the entry from the canon_ace.
2302                  */
2303
2304                 /*
2305                  * First tell the entry what type of ACE this is.
2306                  */
2307
2308                 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, p_ace->type) == -1) {
2309                         DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n",
2310                                 i, strerror(errno) ));
2311                         goto done;
2312                 }
2313
2314                 /*
2315                  * Only set the qualifier (user or group id) if the entry is a user
2316                  * or group id ACE.
2317                  */
2318
2319                 if ((p_ace->type == SMB_ACL_USER) || (p_ace->type == SMB_ACL_GROUP)) {
2320                         if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&p_ace->unix_ug.uid) == -1) {
2321                                 DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n",
2322                                         i, strerror(errno) ));
2323                                 goto done;
2324                         }
2325                 }
2326
2327                 /*
2328                  * Convert the mode_t perms in the canon_ace to a POSIX permset.
2329                  */
2330
2331                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) {
2332                         DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n",
2333                                 i, strerror(errno) ));
2334                         goto done;
2335                 }
2336
2337                 if (map_acl_perms_to_permset(conn, p_ace->perms, &the_permset) == -1) {
2338                         DEBUG(0,("set_canon_ace_list: Failed to create permset for mode (%u) on entry %d. (%s)\n",
2339                                 (unsigned int)p_ace->perms, i, strerror(errno) ));
2340                         goto done;
2341                 }
2342
2343                 /*
2344                  * ..and apply them to the entry.
2345                  */
2346
2347                 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) {
2348                         DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n",
2349                                 i, strerror(errno) ));
2350                         goto done;
2351                 }
2352
2353                 if( DEBUGLVL( 10 ))
2354                         print_canon_ace( p_ace, i);
2355
2356         }
2357
2358         if (needs_mask && !got_mask_entry) {
2359                 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &mask_entry) == -1) {
2360                         DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) ));
2361                         goto done;
2362                 }
2363
2364                 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, mask_entry, SMB_ACL_MASK) == -1) {
2365                         DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno) ));
2366                         goto done;
2367                 }
2368
2369                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, mask_entry, &mask_permset) == -1) {
2370                         DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) ));
2371                         goto done;
2372                 }
2373
2374                 if (map_acl_perms_to_permset(conn, S_IRUSR|S_IWUSR|S_IXUSR, &mask_permset) == -1) {
2375                         DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno) ));
2376                         goto done;
2377                 }
2378
2379                 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, mask_entry, mask_permset) == -1) {
2380                         DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) ));
2381                         goto done;
2382                 }
2383         }
2384
2385         /*
2386          * Check if the ACL is valid.
2387          */
2388
2389         if (SMB_VFS_SYS_ACL_VALID(conn, the_acl) == -1) {
2390                 DEBUG(0,("set_canon_ace_list: ACL type (%s) is invalid for set (%s).\n",
2391                                 the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
2392                                 strerror(errno) ));
2393                 goto done;
2394         }
2395
2396         /*
2397          * Finally apply it to the file or directory.
2398          */
2399
2400         if(default_ace || fsp->is_directory || fsp->fd == -1) {
2401                 if (SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name, the_acl_type, the_acl) == -1) {
2402                         /*
2403                          * Some systems allow all the above calls and only fail with no ACL support
2404                          * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
2405                          */
2406                         if (no_acl_syscall_error(errno)) {
2407                                 *pacl_set_support = False;
2408                         }
2409
2410                         DEBUG(2,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n",
2411                                         the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
2412                                         fsp->fsp_name, strerror(errno) ));
2413                         goto done;
2414                 }
2415         } else {
2416                 if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fd, 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 failed for file %s (%s).\n",
2426                                         fsp->fsp_name, strerror(errno) ));
2427                         goto done;
2428                 }
2429         }
2430
2431         ret = True;
2432
2433   done:
2434
2435         if (the_acl != NULL)
2436             SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
2437
2438         return ret;
2439 }
2440
2441 /****************************************************************************
2442  Find a particular canon_ace entry.
2443 ****************************************************************************/
2444
2445 static struct canon_ace *canon_ace_entry_for(struct canon_ace *list, SMB_ACL_TAG_T type, posix_id *id)
2446 {
2447         while (list) {
2448                 if (list->type == type && ((type != SMB_ACL_USER && type != SMB_ACL_GROUP) ||
2449                                 (type == SMB_ACL_USER  && id && id->uid == list->unix_ug.uid) ||
2450                                 (type == SMB_ACL_GROUP && id && id->gid == list->unix_ug.gid)))
2451                         break;
2452                 list = list->next;
2453         }
2454         return list;
2455 }
2456
2457 /****************************************************************************
2458  
2459 ****************************************************************************/
2460
2461 SMB_ACL_T free_empty_sys_acl(connection_struct *conn, SMB_ACL_T the_acl)
2462 {
2463         SMB_ACL_ENTRY_T entry;
2464
2465         if (!the_acl)
2466                 return NULL;
2467         if (SMB_VFS_SYS_ACL_GET_ENTRY(conn, the_acl, SMB_ACL_FIRST_ENTRY, &entry) != 1) {
2468                 SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
2469                 return NULL;
2470         }
2471         return the_acl;
2472 }
2473
2474 /****************************************************************************
2475  Convert a canon_ace to a generic 3 element permission - if possible.
2476 ****************************************************************************/
2477
2478 #define MAP_PERM(p,mask,result) (((p) & (mask)) ? (result) : 0 )
2479
2480 static BOOL convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file_ace_list, mode_t *posix_perms)
2481 {
2482         int snum = SNUM(fsp->conn);
2483         size_t ace_count = count_canon_ace_list(file_ace_list);
2484         canon_ace *ace_p;
2485         canon_ace *owner_ace = NULL;
2486         canon_ace *group_ace = NULL;
2487         canon_ace *other_ace = NULL;
2488         mode_t and_bits;
2489         mode_t or_bits;
2490
2491         if (ace_count != 3) {
2492                 DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE entries for file %s to convert to \
2493 posix perms.\n", fsp->fsp_name ));
2494                 return False;
2495         }
2496
2497         for (ace_p = file_ace_list; ace_p; ace_p = ace_p->next) {
2498                 if (ace_p->owner_type == UID_ACE)
2499                         owner_ace = ace_p;
2500                 else if (ace_p->owner_type == GID_ACE)
2501                         group_ace = ace_p;
2502                 else if (ace_p->owner_type == WORLD_ACE)
2503                         other_ace = ace_p;
2504         }
2505
2506         if (!owner_ace || !group_ace || !other_ace) {
2507                 DEBUG(3,("convert_canon_ace_to_posix_perms: Can't get standard entries for file %s.\n",
2508                                 fsp->fsp_name ));
2509                 return False;
2510         }
2511
2512         *posix_perms = (mode_t)0;
2513
2514         *posix_perms |= owner_ace->perms;
2515         *posix_perms |= MAP_PERM(group_ace->perms, S_IRUSR, S_IRGRP);
2516         *posix_perms |= MAP_PERM(group_ace->perms, S_IWUSR, S_IWGRP);
2517         *posix_perms |= MAP_PERM(group_ace->perms, S_IXUSR, S_IXGRP);
2518         *posix_perms |= MAP_PERM(other_ace->perms, S_IRUSR, S_IROTH);
2519         *posix_perms |= MAP_PERM(other_ace->perms, S_IWUSR, S_IWOTH);
2520         *posix_perms |= MAP_PERM(other_ace->perms, S_IXUSR, S_IXOTH);
2521
2522         /* The owner must have at least read access. */
2523
2524         *posix_perms |= S_IRUSR;
2525         if (fsp->is_directory)
2526                 *posix_perms |= (S_IWUSR|S_IXUSR);
2527
2528         /* If requested apply the masks. */
2529
2530         /* Get the initial bits to apply. */
2531
2532         if (fsp->is_directory) {
2533                 and_bits = lp_dir_security_mask(snum);
2534                 or_bits = lp_force_dir_security_mode(snum);
2535         } else {
2536                 and_bits = lp_security_mask(snum);
2537                 or_bits = lp_force_security_mode(snum);
2538         }
2539
2540         *posix_perms = (((*posix_perms) & and_bits)|or_bits);
2541
2542         DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o to perm=0%o for file %s.\n",
2543                 (int)owner_ace->perms, (int)group_ace->perms, (int)other_ace->perms, (int)*posix_perms,
2544                 fsp->fsp_name ));
2545
2546         return True;
2547 }
2548
2549 /****************************************************************************
2550   Incoming NT ACLs on a directory can be split into a default POSIX acl (CI|OI|IO) and
2551   a normal POSIX acl. Win2k needs these split acls re-merging into one ACL
2552   with CI|OI set so it is inherited and also applies to the directory.
2553   Based on code from "Jim McDonough" <jmcd@us.ibm.com>.
2554 ****************************************************************************/
2555
2556 static size_t merge_default_aces( SEC_ACE *nt_ace_list, size_t num_aces)
2557 {
2558         size_t i, j;
2559
2560         for (i = 0; i < num_aces; i++) {
2561                 for (j = i+1; j < num_aces; j++) {
2562                         uint32 i_flags_ni = (nt_ace_list[i].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
2563                         uint32 j_flags_ni = (nt_ace_list[j].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
2564                         BOOL i_inh = (nt_ace_list[i].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
2565                         BOOL j_inh = (nt_ace_list[j].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
2566
2567                         /* We know the lower number ACE's are file entries. */
2568                         if ((nt_ace_list[i].type == nt_ace_list[j].type) &&
2569                                 (nt_ace_list[i].size == nt_ace_list[j].size) &&
2570                                 (nt_ace_list[i].info.mask == nt_ace_list[j].info.mask) &&
2571                                 sid_equal(&nt_ace_list[i].trustee, &nt_ace_list[j].trustee) &&
2572                                 (i_inh == j_inh) &&
2573                                 (i_flags_ni == 0) &&
2574                                 (j_flags_ni == (SEC_ACE_FLAG_OBJECT_INHERIT|
2575                                                   SEC_ACE_FLAG_CONTAINER_INHERIT|
2576                                                   SEC_ACE_FLAG_INHERIT_ONLY))) {
2577                                 /*
2578                                  * W2K wants to have access allowed zero access ACE's
2579                                  * at the end of the list. If the mask is zero, merge
2580                                  * the non-inherited ACE onto the inherited ACE.
2581                                  */
2582
2583                                 if (nt_ace_list[i].info.mask == 0) {
2584                                         nt_ace_list[j].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2585                                                                 (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2586                                         if (num_aces - i - 1 > 0)
2587                                                 memmove(&nt_ace_list[i], &nt_ace_list[i+1], (num_aces-i-1) *
2588                                                                 sizeof(SEC_ACE));
2589
2590                                         DEBUG(10,("merge_default_aces: Merging zero access ACE %u onto ACE %u.\n",
2591                                                 (unsigned int)i, (unsigned int)j ));
2592                                 } else {
2593                                         /*
2594                                          * These are identical except for the flags.
2595                                          * Merge the inherited ACE onto the non-inherited ACE.
2596                                          */
2597
2598                                         nt_ace_list[i].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2599                                                                 (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2600                                         if (num_aces - j - 1 > 0)
2601                                                 memmove(&nt_ace_list[j], &nt_ace_list[j+1], (num_aces-j-1) *
2602                                                                 sizeof(SEC_ACE));
2603
2604                                         DEBUG(10,("merge_default_aces: Merging ACE %u onto ACE %u.\n",
2605                                                 (unsigned int)j, (unsigned int)i ));
2606                                 }
2607                                 num_aces--;
2608                                 break;
2609                         }
2610                 }
2611         }
2612
2613         return num_aces;
2614 }
2615 /****************************************************************************
2616  Reply to query a security descriptor from an fsp. If it succeeds it allocates
2617  the space for the return elements and returns the size needed to return the
2618  security descriptor. This should be the only external function needed for
2619  the UNIX style get ACL.
2620 ****************************************************************************/
2621
2622 size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc)
2623 {
2624         connection_struct *conn = fsp->conn;
2625         SMB_STRUCT_STAT sbuf;
2626         SEC_ACE *nt_ace_list = NULL;
2627         DOM_SID owner_sid;
2628         DOM_SID group_sid;
2629         size_t sd_size = 0;
2630         SEC_ACL *psa = NULL;
2631         size_t num_acls = 0;
2632         size_t num_def_acls = 0;
2633         size_t num_aces = 0;
2634         SMB_ACL_T posix_acl = NULL;
2635         SMB_ACL_T def_acl = NULL;
2636         canon_ace *file_ace = NULL;
2637         canon_ace *dir_ace = NULL;
2638         size_t num_profile_acls = 0;
2639         struct pai_val *pal = NULL;
2640         SEC_DESC *psd = NULL;
2641
2642         *ppdesc = NULL;
2643
2644         DEBUG(10,("get_nt_acl: called for file %s\n", fsp->fsp_name ));
2645
2646         if(fsp->is_directory || fsp->fd == -1) {
2647
2648                 /* Get the stat struct for the owner info. */
2649                 if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) {
2650                         return 0;
2651                 }
2652                 /*
2653                  * Get the ACL from the path.
2654                  */
2655
2656                 posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_ACCESS);
2657
2658                 /*
2659                  * If it's a directory get the default POSIX ACL.
2660                  */
2661
2662                 if(fsp->is_directory) {
2663                         def_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_DEFAULT);
2664                         def_acl = free_empty_sys_acl(conn, def_acl);
2665                 }
2666
2667         } else {
2668
2669                 /* Get the stat struct for the owner info. */
2670                 if(SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0) {
2671                         return 0;
2672                 }
2673                 /*
2674                  * Get the ACL from the fd.
2675                  */
2676                 posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fd);
2677         }
2678
2679         DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n",
2680                         posix_acl ? "present" :  "absent",
2681                         def_acl ? "present" :  "absent" ));
2682
2683         pal = load_inherited_info(fsp);
2684
2685         /*
2686          * Get the owner, group and world SIDs.
2687          */
2688
2689         if (lp_profile_acls(SNUM(fsp->conn))) {
2690                 /* For WXP SP1 the owner must be administrators. */
2691                 sid_copy(&owner_sid, &global_sid_Builtin_Administrators);
2692                 sid_copy(&group_sid, &global_sid_Builtin_Users);
2693                 num_profile_acls = 2;
2694         } else {
2695                 create_file_sids(&sbuf, &owner_sid, &group_sid);
2696         }
2697
2698         if ((security_info & DACL_SECURITY_INFORMATION) && !(security_info & PROTECTED_DACL_SECURITY_INFORMATION)) {
2699
2700                 /*
2701                  * In the optimum case Creator Owner and Creator Group would be used for
2702                  * the ACL_USER_OBJ and ACL_GROUP_OBJ entries, respectively, but this
2703                  * would lead to usability problems under Windows: The Creator entries
2704                  * are only available in browse lists of directories and not for files;
2705                  * additionally the identity of the owning group couldn't be determined.
2706                  * We therefore use those identities only for Default ACLs. 
2707                  */
2708
2709                 /* Create the canon_ace lists. */
2710                 file_ace = canonicalise_acl( fsp, posix_acl, &sbuf, &owner_sid, &group_sid, pal, SMB_ACL_TYPE_ACCESS );
2711
2712                 /* We must have *some* ACLS. */
2713         
2714                 if (count_canon_ace_list(file_ace) == 0) {
2715                         DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", fsp->fsp_name ));
2716                         return 0;
2717                 }
2718
2719                 if (fsp->is_directory && def_acl) {
2720                         dir_ace = canonicalise_acl(fsp, def_acl, &sbuf,
2721                                         &global_sid_Creator_Owner,
2722                                         &global_sid_Creator_Group, pal, SMB_ACL_TYPE_DEFAULT );
2723                 }
2724
2725                 /*
2726                  * Create the NT ACE list from the canonical ace lists.
2727                  */
2728
2729                 {
2730                         canon_ace *ace;
2731                         int nt_acl_type;
2732                         int i;
2733
2734                         if (nt4_compatible_acls() && dir_ace) {
2735                                 /*
2736                                  * NT 4 chokes if an ACL contains an INHERIT_ONLY entry
2737                                  * but no non-INHERIT_ONLY entry for one SID. So we only
2738                                  * remove entries from the Access ACL if the
2739                                  * corresponding Default ACL entries have also been
2740                                  * removed. ACEs for CREATOR-OWNER and CREATOR-GROUP
2741                                  * are exceptions. We can do nothing
2742                                  * intelligent if the Default ACL contains entries that
2743                                  * are not also contained in the Access ACL, so this
2744                                  * case will still fail under NT 4.
2745                                  */
2746
2747                                 ace = canon_ace_entry_for(dir_ace, SMB_ACL_OTHER, NULL);
2748                                 if (ace && !ace->perms) {
2749                                         DLIST_REMOVE(dir_ace, ace);
2750                                         SAFE_FREE(ace);
2751
2752                                         ace = canon_ace_entry_for(file_ace, SMB_ACL_OTHER, NULL);
2753                                         if (ace && !ace->perms) {
2754                                                 DLIST_REMOVE(file_ace, ace);
2755                                                 SAFE_FREE(ace);
2756                                         }
2757                                 }
2758
2759                                 /*
2760                                  * WinNT doesn't usually have Creator Group
2761                                  * in browse lists, so we send this entry to
2762                                  * WinNT even if it contains no relevant
2763                                  * permissions. Once we can add
2764                                  * Creator Group to browse lists we can
2765                                  * re-enable this.
2766                                  */
2767
2768 #if 0
2769                                 ace = canon_ace_entry_for(dir_ace, SMB_ACL_GROUP_OBJ, NULL);
2770                                 if (ace && !ace->perms) {
2771                                         DLIST_REMOVE(dir_ace, ace);
2772                                         SAFE_FREE(ace);
2773                                 }
2774 #endif
2775
2776                                 ace = canon_ace_entry_for(file_ace, SMB_ACL_GROUP_OBJ, NULL);
2777                                 if (ace && !ace->perms) {
2778                                         DLIST_REMOVE(file_ace, ace);
2779                                         SAFE_FREE(ace);
2780                                 }
2781                         }
2782
2783                         num_acls = count_canon_ace_list(file_ace);
2784                         num_def_acls = count_canon_ace_list(dir_ace);
2785
2786                         /* Allocate the ace list. */
2787                         if ((nt_ace_list = SMB_MALLOC_ARRAY(SEC_ACE,num_acls + num_profile_acls + num_def_acls)) == NULL) {
2788                                 DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
2789                                 goto done;
2790                         }
2791
2792                         memset(nt_ace_list, '\0', (num_acls + num_def_acls) * sizeof(SEC_ACE) );
2793                                                                                                         
2794                         /*
2795                          * Create the NT ACE list from the canonical ace lists.
2796                          */
2797         
2798                         ace = file_ace;
2799
2800                         for (i = 0; i < num_acls; i++, ace = ace->next) {
2801                                 SEC_ACCESS acc;
2802
2803                                 acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
2804                                 init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc, ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2805                         }
2806
2807                         /* The User must have access to a profile share - even if we can't map the SID. */
2808                         if (lp_profile_acls(SNUM(fsp->conn))) {
2809                                 SEC_ACCESS acc;
2810
2811                                 init_sec_access(&acc,FILE_GENERIC_ALL);
2812                                 init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED,
2813                                                 acc, 0);
2814                         }
2815
2816                         ace = dir_ace;
2817
2818                         for (i = 0; i < num_def_acls; i++, ace = ace->next) {
2819                                 SEC_ACCESS acc;
2820         
2821                                 acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
2822                                 init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc,
2823                                                 SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2824                                                 SEC_ACE_FLAG_INHERIT_ONLY|
2825                                                 (ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 0));
2826                         }
2827
2828                         /* The User must have access to a profile share - even if we can't map the SID. */
2829                         if (lp_profile_acls(SNUM(fsp->conn))) {
2830                                 SEC_ACCESS acc;
2831                         
2832                                 init_sec_access(&acc,FILE_GENERIC_ALL);
2833                                 init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, acc,
2834                                                 SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2835                                                 SEC_ACE_FLAG_INHERIT_ONLY|0);
2836                         }
2837
2838                         /*
2839                          * Merge POSIX default ACLs and normal ACLs into one NT ACE.
2840                          * Win2K needs this to get the inheritance correct when replacing ACLs
2841                          * on a directory tree. Based on work by Jim @ IBM.
2842                          */
2843
2844                         num_aces = merge_default_aces(nt_ace_list, num_aces);
2845
2846                 }
2847
2848                 if (num_aces) {
2849                         if((psa = make_sec_acl( main_loop_talloc_get(), NT4_ACL_REVISION, num_aces, nt_ace_list)) == NULL) {
2850                                 DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
2851                                 goto done;
2852                         }
2853                 }
2854         } /* security_info & DACL_SECURITY_INFORMATION */
2855
2856         psd = make_standard_sec_desc( main_loop_talloc_get(),
2857                         (security_info & OWNER_SECURITY_INFORMATION) ? &owner_sid : NULL,
2858                         (security_info & GROUP_SECURITY_INFORMATION) ? &group_sid : NULL,
2859                         psa,
2860                         &sd_size);
2861
2862         if(!psd) {
2863                 DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
2864                 sd_size = 0;
2865         } else {
2866                 /*
2867                  * Windows 2000: The DACL_PROTECTED flag in the security
2868                  * descriptor marks the ACL as non-inheriting, i.e., no
2869                  * ACEs from higher level directories propagate to this
2870                  * ACL. In the POSIX ACL model permissions are only
2871                  * inherited at file create time, so ACLs never contain
2872                  * any ACEs that are inherited dynamically. The DACL_PROTECTED
2873                  * flag doesn't seem to bother Windows NT.
2874                  * Always set this if map acl inherit is turned off.
2875                  */
2876                 if (get_protected_flag(pal) || !lp_map_acl_inherit(SNUM(conn))) {
2877                         psd->type |= SE_DESC_DACL_PROTECTED;
2878                 }
2879         }
2880
2881         if (psd->dacl)
2882                 dacl_sort_into_canonical_order(psd->dacl->ace, (unsigned int)psd->dacl->num_aces);
2883
2884         *ppdesc = psd;
2885
2886  done:
2887
2888         if (posix_acl)
2889                 SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
2890         if (def_acl)
2891                 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
2892         free_canon_ace_list(file_ace);
2893         free_canon_ace_list(dir_ace);
2894         free_inherited_info(pal);
2895         SAFE_FREE(nt_ace_list);
2896
2897         return sd_size;
2898 }
2899
2900 /****************************************************************************
2901  Try to chown a file. We will be able to chown it under the following conditions.
2902
2903   1) If we have root privileges, then it will just work.
2904   2) If we have write permission to the file and dos_filemodes is set
2905      then allow chown to the currently authenticated user.
2906 ****************************************************************************/
2907
2908 static int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid)
2909 {
2910         int ret;
2911         files_struct *fsp;
2912         SMB_STRUCT_STAT st;
2913
2914         /* try the direct way first */
2915         ret = SMB_VFS_CHOWN(conn, fname, uid, gid);
2916         if (ret == 0)
2917                 return 0;
2918
2919         if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
2920                 return -1;
2921
2922         if (SMB_VFS_STAT(conn,fname,&st))
2923                 return -1;
2924
2925         fsp = open_file_fchmod(conn,fname,&st);
2926         if (!fsp)
2927                 return -1;
2928
2929         /* only allow chown to the current user. This is more secure,
2930            and also copes with the case where the SID in a take ownership ACL is
2931            a local SID on the users workstation 
2932         */
2933         uid = current_user.uid;
2934
2935         become_root();
2936         /* Keep the current file gid the same. */
2937         ret = SMB_VFS_FCHOWN(fsp, fsp->fd, uid, (gid_t)-1);
2938         unbecome_root();
2939
2940         close_file_fchmod(fsp);
2941
2942         return ret;
2943 }
2944
2945 /****************************************************************************
2946  Reply to set a security descriptor on an fsp. security_info_sent is the
2947  description of the following NT ACL.
2948  This should be the only external function needed for the UNIX style set ACL.
2949 ****************************************************************************/
2950
2951 BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
2952 {
2953         connection_struct *conn = fsp->conn;
2954         uid_t user = (uid_t)-1;
2955         gid_t grp = (gid_t)-1;
2956         SMB_STRUCT_STAT sbuf;  
2957         DOM_SID file_owner_sid;
2958         DOM_SID file_grp_sid;
2959         canon_ace *file_ace_list = NULL;
2960         canon_ace *dir_ace_list = NULL;
2961         BOOL acl_perms = False;
2962         mode_t orig_mode = (mode_t)0;
2963         uid_t orig_uid;
2964         gid_t orig_gid;
2965         BOOL need_chown = False;
2966
2967         DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name ));
2968
2969         if (!CAN_WRITE(conn)) {
2970                 DEBUG(10,("set acl rejected on read-only share\n"));
2971                 return False;
2972         }
2973
2974         /*
2975          * Get the current state of the file.
2976          */
2977
2978         if(fsp->is_directory || fsp->fd == -1) {
2979                 if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0)
2980                         return False;
2981         } else {
2982                 if(SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0)
2983                         return False;
2984         }
2985
2986         /* Save the original elements we check against. */
2987         orig_mode = sbuf.st_mode;
2988         orig_uid = sbuf.st_uid;
2989         orig_gid = sbuf.st_gid;
2990
2991         /*
2992          * Unpack the user/group/world id's.
2993          */
2994
2995         if (!unpack_nt_owners( SNUM(conn), &sbuf, &user, &grp, security_info_sent, psd))
2996                 return False;
2997
2998         /*
2999          * Do we need to chown ?
3000          */
3001
3002         if (((user != (uid_t)-1) && (orig_uid != user)) || (( grp != (gid_t)-1) && (orig_gid != grp)))
3003                 need_chown = True;
3004
3005         /*
3006          * Chown before setting ACL only if we don't change the user, or
3007          * if we change to the current user, but not if we want to give away
3008          * the file.
3009          */
3010
3011         if (need_chown && (user == (uid_t)-1 || user == current_user.uid)) {
3012
3013                 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
3014                                 fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
3015
3016                 if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
3017                         DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
3018                                 fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
3019                         return False;
3020                 }
3021
3022                 /*
3023                  * Recheck the current state of the file, which may have changed.
3024                  * (suid/sgid bits, for instance)
3025                  */
3026
3027                 if(fsp->is_directory) {
3028                         if(SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf) != 0) {
3029                                 return False;
3030                         }
3031                 } else {
3032
3033                         int ret;
3034     
3035                         if(fsp->fd == -1)
3036                                 ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf);
3037                         else
3038                                 ret = SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf);
3039   
3040                         if(ret != 0)
3041                                 return False;
3042                 }
3043
3044                 /* Save the original elements we check against. */
3045                 orig_mode = sbuf.st_mode;
3046                 orig_uid = sbuf.st_uid;
3047                 orig_gid = sbuf.st_gid;
3048
3049                 /* We did it, don't try again */
3050                 need_chown = False;
3051         }
3052
3053         create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid);
3054
3055         acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid,
3056                                         &file_ace_list, &dir_ace_list, security_info_sent, psd);
3057
3058         /* Ignore W2K traverse DACL set. */
3059         if (file_ace_list || dir_ace_list) {
3060
3061                 if (!acl_perms) {
3062                         DEBUG(3,("set_nt_acl: cannot set permissions\n"));
3063                         free_canon_ace_list(file_ace_list);
3064                         free_canon_ace_list(dir_ace_list); 
3065                         return False;
3066                 }
3067
3068                 /*
3069                  * Only change security if we got a DACL.
3070                  */
3071
3072                 if((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl != NULL)) {
3073
3074                         BOOL acl_set_support = False;
3075                         BOOL ret = False;
3076
3077                         /*
3078                          * Try using the POSIX ACL set first. Fall back to chmod if
3079                          * we have no ACL support on this filesystem.
3080                          */
3081
3082                         if (acl_perms && file_ace_list) {
3083                                 ret = set_canon_ace_list(fsp, file_ace_list, False, &acl_set_support);
3084                                 if (acl_set_support && ret == False) {
3085                                         DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) ));
3086                                         free_canon_ace_list(file_ace_list);
3087                                         free_canon_ace_list(dir_ace_list); 
3088                                         return False;
3089                                 }
3090                         }
3091
3092                         if (acl_perms && acl_set_support && fsp->is_directory) {
3093                                 if (dir_ace_list) {
3094                                         if (!set_canon_ace_list(fsp, dir_ace_list, True, &acl_set_support)) {
3095                                                 DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) ));
3096                                                 free_canon_ace_list(file_ace_list);
3097                                                 free_canon_ace_list(dir_ace_list); 
3098                                                 return False;
3099                                         }
3100                                 } else {
3101
3102                                         /*
3103                                          * No default ACL - delete one if it exists.
3104                                          */
3105
3106                                         if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name) == -1) {
3107                                                 DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno)));
3108                                                 free_canon_ace_list(file_ace_list);
3109                                                 free_canon_ace_list(dir_ace_list);
3110                                                 return False;
3111                                         }
3112                                 }
3113                         }
3114
3115                         if (acl_set_support)
3116                                 store_inheritance_attributes(fsp, file_ace_list, dir_ace_list,
3117                                                 (psd->type & SE_DESC_DACL_PROTECTED) ? True : False);
3118
3119                         /*
3120                          * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
3121                          */
3122
3123                         if(!acl_set_support && acl_perms) {
3124                                 mode_t posix_perms;
3125
3126                                 if (!convert_canon_ace_to_posix_perms( fsp, file_ace_list, &posix_perms)) {
3127                                         free_canon_ace_list(file_ace_list);
3128                                         free_canon_ace_list(dir_ace_list);
3129                                         DEBUG(3,("set_nt_acl: failed to convert file acl to posix permissions for file %s.\n",
3130                                                 fsp->fsp_name ));
3131                                         return False;
3132                                 }
3133
3134                                 if (orig_mode != posix_perms) {
3135
3136                                         DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
3137                                                 fsp->fsp_name, (unsigned int)posix_perms ));
3138
3139                                         if(SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms) == -1) {
3140                                                 DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n",
3141                                                                 fsp->fsp_name, (unsigned int)posix_perms, strerror(errno) ));
3142                                                 free_canon_ace_list(file_ace_list);
3143                                                 free_canon_ace_list(dir_ace_list);
3144                                                 return False;
3145                                         }
3146                                 }
3147                         }
3148                 }
3149
3150                 free_canon_ace_list(file_ace_list);
3151                 free_canon_ace_list(dir_ace_list); 
3152         }
3153
3154         /* Any chown pending? */
3155         if (need_chown) {
3156
3157                 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
3158                         fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
3159
3160                 if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
3161                         DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
3162                                 fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
3163                         return False;
3164                 }
3165         }
3166
3167         return True;
3168 }
3169
3170 /****************************************************************************
3171  Get the actual group bits stored on a file with an ACL. Has no effect if
3172  the file has no ACL. Needed in dosmode code where the stat() will return
3173  the mask bits, not the real group bits, for a file with an ACL.
3174 ****************************************************************************/
3175
3176 int get_acl_group_bits( connection_struct *conn, const char *fname, mode_t *mode )
3177 {
3178         int entry_id = SMB_ACL_FIRST_ENTRY;
3179         SMB_ACL_ENTRY_T entry;
3180         SMB_ACL_T posix_acl;
3181         int result = -1;
3182
3183         posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS);
3184         if (posix_acl == (SMB_ACL_T)NULL)
3185                 return -1;
3186
3187         while (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
3188                 SMB_ACL_TAG_T tagtype;
3189                 SMB_ACL_PERMSET_T permset;
3190
3191                 /* get_next... */
3192                 if (entry_id == SMB_ACL_FIRST_ENTRY)
3193                         entry_id = SMB_ACL_NEXT_ENTRY;
3194
3195                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) ==-1)
3196                         break;
3197
3198                 if (tagtype == SMB_ACL_GROUP_OBJ) {
3199                         if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
3200                                 break;
3201                         } else {
3202                                 *mode &= ~(S_IRGRP|S_IWGRP|S_IXGRP);
3203                                 *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRGRP : 0);
3204                                 *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWGRP : 0);
3205                                 *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXGRP : 0);
3206                                 result = 0;
3207                                 break;
3208                         }
3209                 }
3210         }
3211         SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
3212         return result;
3213 }
3214
3215 /****************************************************************************
3216  Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3217  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3218 ****************************************************************************/
3219
3220 static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mode_t mode)
3221 {
3222         int entry_id = SMB_ACL_FIRST_ENTRY;
3223         SMB_ACL_ENTRY_T entry;
3224         int num_entries = 0;
3225
3226         while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
3227                 SMB_ACL_TAG_T tagtype;
3228                 SMB_ACL_PERMSET_T permset;
3229                 mode_t perms;
3230
3231                 /* get_next... */
3232                 if (entry_id == SMB_ACL_FIRST_ENTRY)
3233                         entry_id = SMB_ACL_NEXT_ENTRY;
3234
3235                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
3236                         return -1;
3237
3238                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
3239                         return -1;
3240
3241                 num_entries++;
3242
3243                 switch(tagtype) {
3244                         case SMB_ACL_USER_OBJ:
3245                                 perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
3246                                 break;
3247                         case SMB_ACL_GROUP_OBJ:
3248                                 perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
3249                                 break;
3250                         case SMB_ACL_MASK:
3251                                 /*
3252                                  * FIXME: The ACL_MASK entry permissions should really be set to
3253                                  * the union of the permissions of all ACL_USER,
3254                                  * ACL_GROUP_OBJ, and ACL_GROUP entries. That's what
3255                                  * acl_calc_mask() does, but Samba ACLs doesn't provide it.
3256                                  */
3257                                 perms = S_IRUSR|S_IWUSR|S_IXUSR;
3258                                 break;
3259                         case SMB_ACL_OTHER:
3260                                 perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
3261                                 break;
3262                         default:
3263                                 continue;
3264                 }
3265
3266                 if (map_acl_perms_to_permset(conn, perms, &permset) == -1)
3267                         return -1;
3268
3269                 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, entry, permset) == -1)
3270                         return -1;
3271         }
3272
3273         /*
3274          * If this is a simple 3 element ACL or no elements then it's a standard
3275          * UNIX permission set. Just use chmod...       
3276          */
3277
3278         if ((num_entries == 3) || (num_entries == 0))
3279                 return -1;
3280
3281         return 0;
3282 }
3283
3284 /****************************************************************************
3285  Get the access ACL of FROM, do a chmod by setting the ACL USER_OBJ,
3286  GROUP_OBJ and OTHER bits in an ACL and set the mask to rwx. Set the
3287  resulting ACL on TO.  Note that name is in UNIX character set.
3288 ****************************************************************************/
3289
3290 static int copy_access_acl(connection_struct *conn, const char *from, const char *to, mode_t mode)
3291 {
3292         SMB_ACL_T posix_acl = NULL;
3293         int ret = -1;
3294
3295         if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, from, SMB_ACL_TYPE_ACCESS)) == NULL)
3296                 return -1;
3297
3298         if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
3299                 goto done;
3300
3301         ret = SMB_VFS_SYS_ACL_SET_FILE(conn, to, SMB_ACL_TYPE_ACCESS, posix_acl);
3302
3303  done:
3304
3305         SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
3306         return ret;
3307 }
3308
3309 /****************************************************************************
3310  Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3311  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3312  Note that name is in UNIX character set.
3313 ****************************************************************************/
3314
3315 int chmod_acl(connection_struct *conn, const char *name, mode_t mode)
3316 {
3317         return copy_access_acl(conn, name, name, mode);
3318 }
3319
3320 /****************************************************************************
3321  If "inherit permissions" is set and the parent directory has no default
3322  ACL but it does have an Access ACL, inherit this Access ACL to file name.
3323 ****************************************************************************/
3324
3325 int inherit_access_acl(connection_struct *conn, const char *name, mode_t mode)
3326 {
3327         pstring dirname;
3328         pstrcpy(dirname, parent_dirname(name));
3329
3330         if (!lp_inherit_perms(SNUM(conn)) || directory_has_default_acl(conn, dirname))
3331                 return 0;
3332
3333         return copy_access_acl(conn, dirname, name, mode);
3334 }
3335
3336 /****************************************************************************
3337  Do an fchmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3338  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3339 ****************************************************************************/
3340
3341 int fchmod_acl(files_struct *fsp, int fd, mode_t mode)
3342 {
3343         connection_struct *conn = fsp->conn;
3344         SMB_ACL_T posix_acl = NULL;
3345         int ret = -1;
3346
3347         if ((posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fd)) == NULL)
3348                 return -1;
3349
3350         if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
3351                 goto done;
3352
3353         ret = SMB_VFS_SYS_ACL_SET_FD(fsp, fd, posix_acl);
3354
3355   done:
3356
3357         SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
3358         return ret;
3359 }
3360
3361 /****************************************************************************
3362  Check for an existing default POSIX ACL on a directory.
3363 ****************************************************************************/
3364
3365 BOOL directory_has_default_acl(connection_struct *conn, const char *fname)
3366 {
3367         SMB_ACL_T def_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_DEFAULT);
3368         BOOL has_acl = False;
3369         SMB_ACL_ENTRY_T entry;
3370
3371         if (def_acl != NULL && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, def_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1)) {
3372                 has_acl = True;
3373         }
3374
3375         if (def_acl) {
3376                 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
3377         }
3378         return has_acl;
3379 }
3380
3381 /****************************************************************************
3382  Map from wire type to permset.
3383 ****************************************************************************/
3384
3385 static BOOL unix_ex_wire_to_permset(connection_struct *conn, unsigned char wire_perm, SMB_ACL_PERMSET_T *p_permset)
3386 {
3387         if (wire_perm & ~(SMB_POSIX_ACL_READ|SMB_POSIX_ACL_WRITE|SMB_POSIX_ACL_EXECUTE)) {
3388                 return False;
3389         }
3390
3391         if (SMB_VFS_SYS_ACL_CLEAR_PERMS(conn, *p_permset) ==  -1) {
3392                 return False;
3393         }
3394
3395         if (wire_perm & SMB_POSIX_ACL_READ) {
3396                 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_READ) == -1) {
3397                         return False;
3398                 }
3399         }
3400         if (wire_perm & SMB_POSIX_ACL_WRITE) {
3401                 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_WRITE) == -1) {
3402                         return False;
3403                 }
3404         }
3405         if (wire_perm & SMB_POSIX_ACL_EXECUTE) {
3406                 if (SMB_VFS_SYS_ACL_ADD_PERM(conn, *p_permset, SMB_ACL_EXECUTE) == -1) {
3407                         return False;
3408                 }
3409         }
3410         return True;
3411 }
3412
3413 /****************************************************************************
3414  Map from wire type to tagtype.
3415 ****************************************************************************/
3416
3417 static BOOL unix_ex_wire_to_tagtype(unsigned char wire_tt, SMB_ACL_TAG_T *p_tt)
3418 {
3419         switch (wire_tt) {
3420                 case SMB_POSIX_ACL_USER_OBJ:
3421                         *p_tt = SMB_ACL_USER_OBJ;
3422                         break;
3423                 case SMB_POSIX_ACL_USER:
3424                         *p_tt = SMB_ACL_USER;
3425                         break;
3426                 case SMB_POSIX_ACL_GROUP_OBJ:
3427                         *p_tt = SMB_ACL_GROUP_OBJ;
3428                         break;
3429                 case SMB_POSIX_ACL_GROUP:
3430                         *p_tt = SMB_ACL_GROUP;
3431                         break;
3432                 case SMB_POSIX_ACL_MASK:
3433                         *p_tt = SMB_ACL_MASK;
3434                         break;
3435                 case SMB_POSIX_ACL_OTHER:
3436                         *p_tt = SMB_ACL_OTHER;
3437                         break;
3438                 default:
3439                         return False;
3440         }
3441         return True;
3442 }
3443
3444 /****************************************************************************
3445  Create a new POSIX acl from wire permissions.
3446  FIXME ! How does the share mask/mode fit into this.... ?
3447 ****************************************************************************/
3448
3449 static SMB_ACL_T create_posix_acl_from_wire(connection_struct *conn, uint16 num_acls, const char *pdata)
3450 {
3451         unsigned int i;
3452         SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, num_acls);
3453
3454         if (the_acl == NULL) {
3455                 return NULL;
3456         }
3457
3458         for (i = 0; i < num_acls; i++) {
3459                 SMB_ACL_ENTRY_T the_entry;
3460                 SMB_ACL_PERMSET_T the_permset;
3461                 SMB_ACL_TAG_T tag_type;
3462
3463                 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) {
3464                         DEBUG(0,("create_posix_acl_from_wire: Failed to create entry %u. (%s)\n",
3465                                 i, strerror(errno) ));
3466                         goto fail;
3467                 }
3468
3469                 if (!unix_ex_wire_to_tagtype(CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)), &tag_type)) {
3470                         DEBUG(0,("create_posix_acl_from_wire: invalid wire tagtype %u on entry %u.\n",
3471                                 CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)), i ));
3472                         goto fail;
3473                 }
3474
3475                 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, tag_type) == -1) {
3476                         DEBUG(0,("create_posix_acl_from_wire: Failed to set tagtype on entry %u. (%s)\n",
3477                                 i, strerror(errno) ));
3478                         goto fail;
3479                 }
3480
3481                 /* Get the permset pointer from the new ACL entry. */
3482                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) {
3483                         DEBUG(0,("create_posix_acl_from_wire: Failed to get permset on entry %u. (%s)\n",
3484                                 i, strerror(errno) ));
3485                         goto fail;
3486                 }
3487
3488                 /* Map from wire to permissions. */
3489                 if (!unix_ex_wire_to_permset(conn, CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+1), &the_permset)) {
3490                         DEBUG(0,("create_posix_acl_from_wire: invalid permset %u on entry %u.\n",
3491                                 CVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE) + 1), i ));
3492                         goto fail;
3493                 }
3494
3495                 /* Now apply to the new ACL entry. */
3496                 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) {
3497                         DEBUG(0,("create_posix_acl_from_wire: Failed to add permset on entry %u. (%s)\n",
3498                                 i, strerror(errno) ));
3499                         goto fail;
3500                 }
3501
3502                 if (tag_type == SMB_ACL_USER) {
3503                         uint32 uidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3504                         uid_t uid = (uid_t)uidval;
3505                         if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&uid) == -1) {
3506                                 DEBUG(0,("create_posix_acl_from_wire: Failed to set uid %u on entry %u. (%s)\n",
3507                                         (unsigned int)uid, i, strerror(errno) ));
3508                                 goto fail;
3509                         }
3510                 }
3511
3512                 if (tag_type == SMB_ACL_GROUP) {
3513                         uint32 gidval = IVAL(pdata,(i*SMB_POSIX_ACL_ENTRY_SIZE)+2);
3514                         gid_t gid = (uid_t)gidval;
3515                         if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&gid) == -1) {
3516                                 DEBUG(0,("create_posix_acl_from_wire: Failed to set gid %u on entry %u. (%s)\n",
3517                                         (unsigned int)gid, i, strerror(errno) ));
3518                                 goto fail;
3519                         }
3520                 }
3521         }
3522
3523         return the_acl;
3524
3525  fail:
3526
3527         if (the_acl != NULL) {
3528                 SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
3529         }
3530         return NULL;
3531 }
3532
3533 /****************************************************************************
3534  Calls from UNIX extensions - Default POSIX ACL set.
3535  If num_def_acls == 0 and not a directory just return. If it is a directory
3536  and num_def_acls == 0 then remove the default acl. Else set the default acl
3537  on the directory.
3538 ****************************************************************************/
3539
3540 BOOL set_unix_posix_default_acl(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf,
3541                                 uint16 num_def_acls, const char *pdata)
3542 {
3543         SMB_ACL_T def_acl = NULL;
3544
3545         if (num_def_acls && !S_ISDIR(psbuf->st_mode)) {
3546                 DEBUG(5,("set_unix_posix_default_acl: Can't set default ACL on non-directory file %s\n", fname ));
3547                 errno = EISDIR;
3548                 return False;
3549         }
3550
3551         if (!num_def_acls) {
3552                 /* Remove the default ACL. */
3553                 if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fname) == -1) {
3554                         DEBUG(5,("set_unix_posix_default_acl: acl_delete_def_file failed on directory %s (%s)\n",
3555                                 fname, strerror(errno) ));
3556                         return False;
3557                 }
3558                 return True;
3559         }
3560
3561         if ((def_acl = create_posix_acl_from_wire(conn, num_def_acls, pdata)) == NULL) {
3562                 return False;
3563         }
3564
3565         if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_DEFAULT, def_acl) == -1) {
3566                 DEBUG(5,("set_unix_posix_default_acl: acl_set_file failed on directory %s (%s)\n",
3567                         fname, strerror(errno) ));
3568                 SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
3569                 return False;
3570         }
3571
3572         DEBUG(10,("set_unix_posix_default_acl: set default acl for file %s\n", fname ));
3573         SMB_VFS_SYS_ACL_FREE_ACL(conn, def_acl);
3574         return True;
3575 }
3576
3577 /****************************************************************************
3578  Remove an ACL from a file. As we don't have acl_delete_entry() available
3579  we must read the current acl and copy all entries except MASK, USER and GROUP
3580  to a new acl, then set that. This (at least on Linux) causes any ACL to be
3581  removed.
3582  FIXME ! How does the share mask/mode fit into this.... ?
3583 ****************************************************************************/
3584
3585 static BOOL remove_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname)
3586 {
3587         SMB_ACL_T file_acl = NULL;
3588         int entry_id = SMB_ACL_FIRST_ENTRY;
3589         SMB_ACL_ENTRY_T entry;
3590         BOOL ret = False;
3591         /* Create a new ACL with only 3 entries, u/g/w. */
3592         SMB_ACL_T new_file_acl = SMB_VFS_SYS_ACL_INIT(conn, 3);
3593         SMB_ACL_ENTRY_T user_ent = NULL;
3594         SMB_ACL_ENTRY_T group_ent = NULL;
3595         SMB_ACL_ENTRY_T other_ent = NULL;
3596
3597         if (new_file_acl == NULL) {
3598                 DEBUG(5,("remove_posix_acl: failed to init new ACL with 3 entries for file %s.\n", fname));
3599                 return False;
3600         }
3601
3602         /* Now create the u/g/w entries. */
3603         if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &user_ent) == -1) {
3604                 DEBUG(5,("remove_posix_acl: Failed to create user entry for file %s. (%s)\n",
3605                         fname, strerror(errno) ));
3606                 goto done;
3607         }
3608         if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, user_ent, SMB_ACL_USER_OBJ) == -1) {
3609                 DEBUG(5,("remove_posix_acl: Failed to set user entry for file %s. (%s)\n",
3610                         fname, strerror(errno) ));
3611                 goto done;
3612         }
3613
3614         if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &group_ent) == -1) {
3615                 DEBUG(5,("remove_posix_acl: Failed to create group entry for file %s. (%s)\n",
3616                         fname, strerror(errno) ));
3617                 goto done;
3618         }
3619         if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, group_ent, SMB_ACL_GROUP_OBJ) == -1) {
3620                 DEBUG(5,("remove_posix_acl: Failed to set group entry for file %s. (%s)\n",
3621                         fname, strerror(errno) ));
3622                 goto done;
3623         }
3624
3625         if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &new_file_acl, &other_ent) == -1) {
3626                 DEBUG(5,("remove_posix_acl: Failed to create other entry for file %s. (%s)\n",
3627                         fname, strerror(errno) ));
3628                 goto done;
3629         }
3630         if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, other_ent, SMB_ACL_OTHER) == -1) {
3631                 DEBUG(5,("remove_posix_acl: Failed to set other entry for file %s. (%s)\n",
3632                         fname, strerror(errno) ));
3633                 goto done;
3634         }
3635
3636         /* Get the current file ACL. */
3637         if (fsp && fsp->fd != -1) {
3638                 file_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fd);
3639         } else {
3640                 file_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_ACCESS);
3641         }
3642
3643         if (file_acl == NULL) {
3644                 /* This is only returned if an error occurred. Even for a file with
3645                    no acl a u/g/w acl should be returned. */
3646                 DEBUG(5,("remove_posix_acl: failed to get ACL from file %s (%s).\n",
3647                         fname, strerror(errno) ));
3648                 goto done;
3649         }
3650
3651         while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, file_acl, entry_id, &entry) == 1) {
3652                 SMB_ACL_TAG_T tagtype;
3653                 SMB_ACL_PERMSET_T permset;
3654
3655                 /* get_next... */
3656                 if (entry_id == SMB_ACL_FIRST_ENTRY)
3657                         entry_id = SMB_ACL_NEXT_ENTRY;
3658
3659                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
3660                         DEBUG(5,("remove_posix_acl: failed to get tagtype from ACL on file %s (%s).\n",
3661                                 fname, strerror(errno) ));
3662                         goto done;
3663                 }
3664
3665                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
3666                         DEBUG(5,("remove_posix_acl: failed to get permset from ACL on file %s (%s).\n",
3667                                 fname, strerror(errno) ));
3668                         goto done;
3669                 }
3670
3671                 if (tagtype == SMB_ACL_USER_OBJ) {
3672                         if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, user_ent, permset) == -1) {
3673                                 DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
3674                                         fname, strerror(errno) ));
3675                         }
3676                 } else if (tagtype == SMB_ACL_GROUP_OBJ) {
3677                         if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, group_ent, permset) == -1) {
3678                                 DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
3679                                         fname, strerror(errno) ));
3680                         }
3681                 } else if (tagtype == SMB_ACL_OTHER) {
3682                         if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, other_ent, permset) == -1) {
3683                                 DEBUG(5,("remove_posix_acl: failed to set permset from ACL on file %s (%s).\n",
3684                                         fname, strerror(errno) ));
3685                         }
3686                 }
3687         }
3688
3689         ret = True;
3690
3691  done:
3692
3693         if (file_acl) {
3694                 SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
3695         }
3696         if (new_file_acl) {
3697                 SMB_VFS_SYS_ACL_FREE_ACL(conn, new_file_acl);
3698         }
3699         return ret;
3700 }
3701
3702 /****************************************************************************
3703  Calls from UNIX extensions - POSIX ACL set.
3704  If num_def_acls == 0 then read/modify/write acl after removing all entries
3705  except SMB_ACL_USER_OBJ, SMB_ACL_GROUP_OBJ, SMB_ACL_OTHER.
3706 ****************************************************************************/
3707
3708 BOOL set_unix_posix_acl(connection_struct *conn, files_struct *fsp, const char *fname, uint16 num_acls, const char *pdata)
3709 {
3710         SMB_ACL_T file_acl = NULL;
3711
3712         if (!num_acls) {
3713                 /* Remove the ACL from the file. */
3714                 return remove_posix_acl(conn, fsp, fname);
3715         }
3716
3717         if ((file_acl = create_posix_acl_from_wire(conn, num_acls, pdata)) == NULL) {
3718                 return False;
3719         }
3720
3721         if (fsp && fsp->fd != -1) {
3722                 /* The preferred way - use an open fd. */
3723                 if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fd, file_acl) == -1) {
3724                         DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n",
3725                                 fname, strerror(errno) ));
3726                         SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
3727                         return False;
3728                 }
3729         } else {
3730                 if (SMB_VFS_SYS_ACL_SET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS, file_acl) == -1) {
3731                         DEBUG(5,("set_unix_posix_acl: acl_set_file failed on %s (%s)\n",
3732                                 fname, strerror(errno) ));
3733                         SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
3734                         return False;
3735                 }
3736         }
3737
3738         DEBUG(10,("set_unix_posix_acl: set acl for file %s\n", fname ));
3739         SMB_VFS_SYS_ACL_FREE_ACL(conn, file_acl);
3740         return True;
3741 }
3742
3743 /****************************************************************************
3744  Check for POSIX group ACLs. If none use stat entry.
3745 ****************************************************************************/
3746
3747 static int check_posix_acl_group_write(connection_struct *conn, const char *fname, SMB_STRUCT_STAT *psbuf)
3748 {
3749         SMB_ACL_T posix_acl = NULL;
3750         int entry_id = SMB_ACL_FIRST_ENTRY;
3751         SMB_ACL_ENTRY_T entry;
3752         int i;
3753         BOOL seen_mask = False;
3754         int ret = -1;
3755
3756         if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS)) == NULL) {
3757                 goto check_stat;
3758         }
3759
3760         /* First ensure the group mask allows group read. */
3761         /* Also check any user entries (these take preference over group). */
3762
3763         while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
3764                 SMB_ACL_TAG_T tagtype;
3765                 SMB_ACL_PERMSET_T permset;
3766                 int have_write = -1;
3767
3768                 /* get_next... */
3769                 if (entry_id == SMB_ACL_FIRST_ENTRY)
3770                         entry_id = SMB_ACL_NEXT_ENTRY;
3771
3772                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
3773                         goto check_stat;
3774                 }
3775
3776                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
3777                         goto check_stat;
3778                 }
3779
3780                 have_write = SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE);
3781                 if (have_write == -1) {
3782                         goto check_stat;
3783                 }
3784
3785                 switch(tagtype) {
3786                         case SMB_ACL_MASK:
3787                                 if (!have_write) {
3788                                         /* We don't have any group or explicit user write permission. */
3789                                         ret = -1; /* Allow caller to check "other" permissions. */
3790                                         DEBUG(10,("check_posix_acl_group_write: file %s \
3791 refusing write due to mask.\n", fname));
3792                                         goto done;
3793                                 }
3794                                 seen_mask = True;
3795                                 break;
3796                         case SMB_ACL_USER:
3797                         {
3798                                 /* Check against current_user.uid. */
3799                                 uid_t *puid = (uid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
3800                                 if (puid == NULL) {
3801                                         goto check_stat;
3802                                 }
3803                                 if (current_user.uid == *puid) {
3804                                         /* We have a uid match but we must ensure we have seen the acl mask. */
3805                                         ret = have_write;
3806                                         DEBUG(10,("check_posix_acl_group_write: file %s \
3807 match on user %u -> %s.\n", fname, (unsigned int)*puid, ret ? "can write" : "cannot write"));
3808                                         if (seen_mask) {
3809                                                 goto done;
3810                                         }
3811                                 }
3812                                 break;
3813                         }
3814                         default:
3815                                 continue;
3816                 }
3817         }
3818
3819         /* If ret is anything other than -1 we matched on a user entry. */
3820         if (ret != -1) {
3821                 goto done;
3822         }
3823
3824         /* Next check all group entries. */
3825         entry_id = SMB_ACL_FIRST_ENTRY;
3826         while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
3827                 SMB_ACL_TAG_T tagtype;
3828                 SMB_ACL_PERMSET_T permset;
3829                 int have_write = -1;
3830
3831                 /* get_next... */
3832                 if (entry_id == SMB_ACL_FIRST_ENTRY)
3833                         entry_id = SMB_ACL_NEXT_ENTRY;
3834
3835                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1) {
3836                         goto check_stat;
3837                 }
3838
3839                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
3840                         goto check_stat;
3841                 }
3842
3843                 have_write = SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE);
3844                 if (have_write == -1) {
3845                         goto check_stat;
3846                 }
3847
3848                 switch(tagtype) {
3849                         case SMB_ACL_GROUP:
3850                         {
3851                                 gid_t *pgid = (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
3852                                 if (pgid == NULL) {
3853                                         goto check_stat;
3854                                 }
3855
3856                                 /* Does it match the current effective group ? */
3857                                 if (current_user.gid == *pgid) {
3858                                         ret = have_write;
3859                                         DEBUG(10,("check_posix_acl_group_write: file %s \
3860 match on group %u -> can write.\n", fname, (unsigned int)*pgid ));
3861
3862                                         /* If we don't have write permission this entry doesn't
3863                                          * prevent the subsequent enumeration of the supplementary
3864                                          * groups.
3865                                          */
3866                                         if (have_write) {
3867                                                 goto done;
3868                                         }
3869                                 }
3870
3871                                 /* Continue with the supplementary groups. */
3872                                 for (i = 0; i < current_user.ngroups; i++) {
3873                                         if (current_user.groups[i] == *pgid) {
3874                                                 ret = have_write;
3875                                                 DEBUG(10,("check_posix_acl_group_write: file %s \
3876 match on group %u -> can write.\n", fname, (unsigned int)*pgid ));
3877
3878                                                 /* If we don't have write permission this entry doesn't
3879                                                         terminate the enumeration of the entries. */
3880                                                 if (have_write) {
3881                                                         goto done;
3882                                                 }
3883                                                 /* But does terminate the group iteration. */
3884                                                 break;
3885                                         }
3886                                 }
3887                                 break;
3888                         }
3889                         default:
3890                                 continue;
3891                 }
3892         }
3893
3894         /* If ret is -1 here we didn't match on the user entry or
3895            supplemental group entries. */
3896         
3897         DEBUG(10,("check_posix_acl_group_write: ret = %d before check_stat:\n", ret));
3898
3899   check_stat:
3900
3901         /* Do we match on the owning group entry ? */
3902
3903         /* First, does it match the current effective group ? */
3904         if (current_user.gid == psbuf->st_gid) {
3905                 ret = (psbuf->st_mode & S_IWGRP) ? 1 : 0;
3906                 DEBUG(10,("check_posix_acl_group_write: file %s \
3907 match on owning group %u -> %s.\n", fname, (unsigned int)psbuf->st_gid, ret ? "can write" : "cannot write"));
3908                 goto done;
3909         }
3910
3911         /* If not look at the supplementary groups. */
3912         for (i = 0; i < current_user.ngroups; i++) {
3913                 if (current_user.groups[i] == psbuf->st_gid) {
3914                         ret = (psbuf->st_mode & S_IWGRP) ? 1 : 0;
3915                         DEBUG(10,("check_posix_acl_group_write: file %s \
3916 match on owning group %u -> %s.\n", fname, (unsigned int)psbuf->st_gid, ret ? "can write" : "cannot write"));
3917                         break;
3918                 }
3919         }
3920
3921         if (i == current_user.ngroups) {
3922                 DEBUG(10,("check_posix_acl_group_write: file %s \
3923 failed to match on user or group in token (ret = %d).\n", fname, ret ));
3924         }
3925
3926   done:
3927
3928         SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
3929
3930         DEBUG(10,("check_posix_acl_group_write: file %s returning (ret = %d).\n", fname, ret ));
3931         return ret;
3932 }
3933
3934 /****************************************************************************
3935  Actually emulate the in-kernel access checking for delete access. We need
3936  this to successfully return ACCESS_DENIED on a file open for delete access.
3937 ****************************************************************************/
3938
3939 BOOL can_delete_file_in_directory(connection_struct *conn, const char *fname)
3940 {
3941         SMB_STRUCT_STAT sbuf;  
3942         pstring dname;
3943         int ret;
3944
3945         if (!CAN_WRITE(conn)) {
3946                 return False;
3947         }
3948
3949         /* Get the parent directory permission mask and owners. */
3950         pstrcpy(dname, parent_dirname(fname));
3951         if(SMB_VFS_STAT(conn, dname, &sbuf) != 0) {
3952                 return False;
3953         }
3954         if (!S_ISDIR(sbuf.st_mode)) {
3955                 return False;
3956         }
3957         if (current_user.uid == 0 || conn->admin_user) {
3958                 /* I'm sorry sir, I didn't know you were root... */
3959                 return True;
3960         }
3961
3962         /* Check primary owner write access. */
3963         if (current_user.uid == sbuf.st_uid) {
3964                 return (sbuf.st_mode & S_IWUSR) ? True : False;
3965         }
3966
3967 #ifdef S_ISVTX
3968         /* sticky bit means delete only by owner or root. */
3969         if (sbuf.st_mode & S_ISVTX) {
3970                 SMB_STRUCT_STAT sbuf_file;  
3971                 if(SMB_VFS_STAT(conn, fname, &sbuf_file) != 0) {
3972                         return False;
3973                 }
3974                 if (current_user.uid == sbuf_file.st_uid) {
3975                         return True;
3976                 }
3977                 return False;
3978         }
3979 #endif
3980
3981         /* Check group or explicit user acl entry write access. */
3982         ret = check_posix_acl_group_write(conn, dname, &sbuf);
3983         if (ret == 0 || ret == 1) {
3984                 return ret ? True : False;
3985         }
3986
3987         /* Finally check other write access. */
3988         return (sbuf.st_mode & S_IWOTH) ? True : False;
3989 }
3990
3991 /****************************************************************************
3992  Actually emulate the in-kernel access checking for write access. We need
3993  this to successfully check for ability to write for dos filetimes.
3994 ****************************************************************************/
3995
3996 BOOL can_write_to_file(connection_struct *conn, const char *fname)
3997 {
3998         SMB_STRUCT_STAT sbuf;  
3999         int ret;
4000
4001         if (!CAN_WRITE(conn)) {
4002                 return False;
4003         }
4004
4005         if (current_user.uid == 0 || conn->admin_user) {
4006                 /* I'm sorry sir, I didn't know you were root... */
4007                 return True;
4008         }
4009
4010         /* Get the file permission mask and owners. */
4011         if(SMB_VFS_STAT(conn, fname, &sbuf) != 0) {
4012                 return False;
4013         }
4014
4015         /* Check primary owner write access. */
4016         if (current_user.uid == sbuf.st_uid) {
4017                 return (sbuf.st_mode & S_IWUSR) ? True : False;
4018         }
4019
4020         /* Check group or explicit user acl entry write access. */
4021         ret = check_posix_acl_group_write(conn, fname, &sbuf);
4022         if (ret == 0 || ret == 1) {
4023                 return ret ? True : False;
4024         }
4025
4026         /* Finally check other write access. */
4027         return (sbuf.st_mode & S_IWOTH) ? True : False;
4028 }