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