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