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