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