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