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