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