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