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