r428: add acls debug class
[obnox/samba/samba-obnox.git] / source / smbd / posix_acls.c
1 /*
2    Unix SMB/CIFS implementation.
3    SMB NT Security Descriptor / Unix permission conversion.
4    Copyright (C) Jeremy Allison 1994-2000.
5    Copyright (C) Andreas Gruenbacher 2002.
6
7    This program is free software; you can redistribute it and/or modify
8    it under the terms of the GNU General Public License as published by
9    the Free Software Foundation; either version 2 of the License, or
10    (at your option) any later version.
11
12    This program is distributed in the hope that it will be useful,
13    but WITHOUT ANY WARRANTY; without even the implied warranty of
14    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15    GNU General Public License for more details.
16
17    You should have received a copy of the GNU General Public License
18    along with this program; if not, write to the Free Software
19    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 */
21
22 #include "includes.h"
23
24 #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                                                 continue;
2115                                         uid_to_sid( &sid, *puid);
2116                                         unix_ug.uid = *puid;
2117                                         owner_type = UID_ACE;
2118                                         SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)puid,tagtype);
2119                                         break;
2120                                 }
2121                         case SMB_ACL_GROUP_OBJ:
2122                                 /* Get the SID from the owning group. */
2123                                 sid_copy(&sid, pgroup);
2124                                 unix_ug.gid = psbuf->st_gid;
2125                                 owner_type = GID_ACE;
2126                                 break;
2127                         case SMB_ACL_GROUP:
2128                                 {
2129                                         gid_t *pgid = (gid_t *)SMB_VFS_SYS_ACL_GET_QUALIFIER(conn, entry);
2130                                         if (pgid == NULL) {
2131                                                 DEBUG(0,("canonicalise_acl: Failed to get gid.\n"));
2132                                                 continue;
2133                                         }
2134                                         gid_to_sid( &sid, *pgid);
2135                                         unix_ug.gid = *pgid;
2136                                         owner_type = GID_ACE;
2137                                         SMB_VFS_SYS_ACL_FREE_QUALIFIER(conn, (void *)pgid,tagtype);
2138                                         break;
2139                                 }
2140                         case SMB_ACL_MASK:
2141                                 acl_mask = convert_permset_to_mode_t(conn, permset);
2142                                 continue; /* Don't count the mask as an entry. */
2143                         case SMB_ACL_OTHER:
2144                                 /* Use the Everyone SID */
2145                                 sid = global_sid_World;
2146                                 unix_ug.world = -1;
2147                                 owner_type = WORLD_ACE;
2148                                 break;
2149                         default:
2150                                 DEBUG(0,("canonicalise_acl: Unknown tagtype %u\n", (unsigned int)tagtype));
2151                                 continue;
2152                 }
2153
2154                 /*
2155                  * Add this entry to the list.
2156                  */
2157
2158                 if ((ace = (canon_ace *)malloc(sizeof(canon_ace))) == NULL)
2159                         goto fail;
2160
2161                 ZERO_STRUCTP(ace);
2162                 ace->type = tagtype;
2163                 ace->perms = convert_permset_to_mode_t(conn, permset);
2164                 ace->attr = ALLOW_ACE;
2165                 ace->trustee = sid;
2166                 ace->unix_ug = unix_ug;
2167                 ace->owner_type = owner_type;
2168                 ace->inherited = get_inherited_flag(pal, ace, (the_acl_type == SMB_ACL_TYPE_DEFAULT));
2169
2170                 DLIST_ADD(list_head, ace);
2171         }
2172
2173         /*
2174          * This next call will ensure we have at least a user/group/world set.
2175          */
2176
2177         if (!ensure_canon_entry_valid(&list_head, fsp, powner, pgroup, psbuf, False))
2178                 goto fail;
2179
2180         /*
2181          * Now go through the list, masking the permissions with the
2182          * acl_mask. Ensure all DENY Entries are at the start of the list.
2183          */
2184
2185         DEBUG(10,("canonicalise_acl: %s ace entries before arrange :\n", the_acl_type == SMB_ACL_TYPE_ACCESS ? "Access" : "Default" ));
2186
2187         for ( ace_count = 0, ace = list_head; ace; ace = next_ace, ace_count++) {
2188                 next_ace = ace->next;
2189
2190                 /* Masks are only applied to entries other than USER_OBJ and OTHER. */
2191                 if (ace->type != SMB_ACL_OTHER && ace->type != SMB_ACL_USER_OBJ)
2192                         ace->perms &= acl_mask;
2193
2194                 if (ace->perms == 0) {
2195                         DLIST_PROMOTE(list_head, ace);
2196                 }
2197
2198                 if( DEBUGLVL( 10 ) ) {
2199                         print_canon_ace(ace, ace_count);
2200                 }
2201         }
2202
2203         arrange_posix_perms(fsp->fsp_name,&list_head );
2204
2205         print_canon_ace_list( "canonicalise_acl: ace entries after arrange", list_head );
2206
2207         return list_head;
2208
2209   fail:
2210
2211         free_canon_ace_list(list_head);
2212         return NULL;
2213 }
2214
2215 /****************************************************************************
2216  Attempt to apply an ACL to a file or directory.
2217 ****************************************************************************/
2218
2219 static BOOL set_canon_ace_list(files_struct *fsp, canon_ace *the_ace, BOOL default_ace, BOOL *pacl_set_support)
2220 {
2221         connection_struct *conn = fsp->conn;
2222         BOOL ret = False;
2223         SMB_ACL_T the_acl = SMB_VFS_SYS_ACL_INIT(conn, (int)count_canon_ace_list(the_ace) + 1);
2224         canon_ace *p_ace;
2225         int i;
2226         SMB_ACL_ENTRY_T mask_entry;
2227         BOOL got_mask_entry = False;
2228         SMB_ACL_PERMSET_T mask_permset;
2229         SMB_ACL_TYPE_T the_acl_type = (default_ace ? SMB_ACL_TYPE_DEFAULT : SMB_ACL_TYPE_ACCESS);
2230         BOOL needs_mask = False;
2231         mode_t mask_perms = 0;
2232
2233 #if defined(POSIX_ACL_NEEDS_MASK)
2234         /* HP-UX always wants to have a mask (called "class" there). */
2235         needs_mask = True;
2236 #endif
2237
2238         if (the_acl == NULL) {
2239
2240                 if (errno != ENOSYS) {
2241                         /*
2242                          * Only print this error message if we have some kind of ACL
2243                          * support that's not working. Otherwise we would always get this.
2244                          */
2245                         DEBUG(0,("set_canon_ace_list: Unable to init %s ACL. (%s)\n",
2246                                 default_ace ? "default" : "file", strerror(errno) ));
2247                 }
2248                 *pacl_set_support = False;
2249                 return False;
2250         }
2251
2252         if( DEBUGLVL( 10 )) {
2253                 dbgtext("set_canon_ace_list: setting ACL:\n");
2254                 for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
2255                         print_canon_ace( p_ace, i);
2256                 }
2257         }
2258
2259         for (i = 0, p_ace = the_ace; p_ace; p_ace = p_ace->next, i++ ) {
2260                 SMB_ACL_ENTRY_T the_entry;
2261                 SMB_ACL_PERMSET_T the_permset;
2262
2263                 /*
2264                  * ACLs only "need" an ACL_MASK entry if there are any named user or
2265                  * named group entries. But if there is an ACL_MASK entry, it applies
2266                  * to ACL_USER, ACL_GROUP, and ACL_GROUP_OBJ entries. Set the mask
2267                  * so that it doesn't deny (i.e., mask off) any permissions.
2268                  */
2269
2270                 if (p_ace->type == SMB_ACL_USER || p_ace->type == SMB_ACL_GROUP) {
2271                         needs_mask = True;
2272                         mask_perms |= p_ace->perms;
2273                 } else if (p_ace->type == SMB_ACL_GROUP_OBJ) {
2274                         mask_perms |= p_ace->perms;
2275                 }
2276
2277                 /*
2278                  * Get the entry for this ACE.
2279                  */
2280
2281                 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &the_entry) == -1) {
2282                         DEBUG(0,("set_canon_ace_list: Failed to create entry %d. (%s)\n",
2283                                 i, strerror(errno) ));
2284                         goto done;
2285                 }
2286
2287                 if (p_ace->type == SMB_ACL_MASK) {
2288                         mask_entry = the_entry;
2289                         got_mask_entry = True;
2290                 }
2291
2292                 /*
2293                  * Ok - we now know the ACL calls should be working, don't
2294                  * allow fallback to chmod.
2295                  */
2296
2297                 *pacl_set_support = True;
2298
2299                 /*
2300                  * Initialise the entry from the canon_ace.
2301                  */
2302
2303                 /*
2304                  * First tell the entry what type of ACE this is.
2305                  */
2306
2307                 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, the_entry, p_ace->type) == -1) {
2308                         DEBUG(0,("set_canon_ace_list: Failed to set tag type on entry %d. (%s)\n",
2309                                 i, strerror(errno) ));
2310                         goto done;
2311                 }
2312
2313                 /*
2314                  * Only set the qualifier (user or group id) if the entry is a user
2315                  * or group id ACE.
2316                  */
2317
2318                 if ((p_ace->type == SMB_ACL_USER) || (p_ace->type == SMB_ACL_GROUP)) {
2319                         if (SMB_VFS_SYS_ACL_SET_QUALIFIER(conn, the_entry,(void *)&p_ace->unix_ug.uid) == -1) {
2320                                 DEBUG(0,("set_canon_ace_list: Failed to set qualifier on entry %d. (%s)\n",
2321                                         i, strerror(errno) ));
2322                                 goto done;
2323                         }
2324                 }
2325
2326                 /*
2327                  * Convert the mode_t perms in the canon_ace to a POSIX permset.
2328                  */
2329
2330                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, the_entry, &the_permset) == -1) {
2331                         DEBUG(0,("set_canon_ace_list: Failed to get permset on entry %d. (%s)\n",
2332                                 i, strerror(errno) ));
2333                         goto done;
2334                 }
2335
2336                 if (map_acl_perms_to_permset(conn, p_ace->perms, &the_permset) == -1) {
2337                         DEBUG(0,("set_canon_ace_list: Failed to create permset for mode (%u) on entry %d. (%s)\n",
2338                                 (unsigned int)p_ace->perms, i, strerror(errno) ));
2339                         goto done;
2340                 }
2341
2342                 /*
2343                  * ..and apply them to the entry.
2344                  */
2345
2346                 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, the_entry, the_permset) == -1) {
2347                         DEBUG(0,("set_canon_ace_list: Failed to add permset on entry %d. (%s)\n",
2348                                 i, strerror(errno) ));
2349                         goto done;
2350                 }
2351
2352                 if( DEBUGLVL( 10 ))
2353                         print_canon_ace( p_ace, i);
2354
2355         }
2356
2357         if (needs_mask && !got_mask_entry) {
2358                 if (SMB_VFS_SYS_ACL_CREATE_ENTRY(conn, &the_acl, &mask_entry) == -1) {
2359                         DEBUG(0,("set_canon_ace_list: Failed to create mask entry. (%s)\n", strerror(errno) ));
2360                         goto done;
2361                 }
2362
2363                 if (SMB_VFS_SYS_ACL_SET_TAG_TYPE(conn, mask_entry, SMB_ACL_MASK) == -1) {
2364                         DEBUG(0,("set_canon_ace_list: Failed to set tag type on mask entry. (%s)\n",strerror(errno) ));
2365                         goto done;
2366                 }
2367
2368                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, mask_entry, &mask_permset) == -1) {
2369                         DEBUG(0,("set_canon_ace_list: Failed to get mask permset. (%s)\n", strerror(errno) ));
2370                         goto done;
2371                 }
2372
2373                 if (map_acl_perms_to_permset(conn, S_IRUSR|S_IWUSR|S_IXUSR, &mask_permset) == -1) {
2374                         DEBUG(0,("set_canon_ace_list: Failed to create mask permset. (%s)\n", strerror(errno) ));
2375                         goto done;
2376                 }
2377
2378                 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, mask_entry, mask_permset) == -1) {
2379                         DEBUG(0,("set_canon_ace_list: Failed to add mask permset. (%s)\n", strerror(errno) ));
2380                         goto done;
2381                 }
2382         }
2383
2384         /*
2385          * Check if the ACL is valid.
2386          */
2387
2388         if (SMB_VFS_SYS_ACL_VALID(conn, the_acl) == -1) {
2389                 DEBUG(0,("set_canon_ace_list: ACL type (%s) is invalid for set (%s).\n",
2390                                 the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
2391                                 strerror(errno) ));
2392                 goto done;
2393         }
2394
2395         /*
2396          * Finally apply it to the file or directory.
2397          */
2398
2399         if(default_ace || fsp->is_directory || fsp->fd == -1) {
2400                 if (SMB_VFS_SYS_ACL_SET_FILE(conn, fsp->fsp_name, the_acl_type, the_acl) == -1) {
2401                         /*
2402                          * Some systems allow all the above calls and only fail with no ACL support
2403                          * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
2404                          */
2405                         if (errno == ENOSYS)
2406                                 *pacl_set_support = False;
2407
2408 #ifdef ENOTSUP
2409                         if (errno == ENOTSUP)
2410                                 *pacl_set_support = False;
2411 #endif
2412
2413                         DEBUG(2,("set_canon_ace_list: sys_acl_set_file type %s failed for file %s (%s).\n",
2414                                         the_acl_type == SMB_ACL_TYPE_DEFAULT ? "directory default" : "file",
2415                                         fsp->fsp_name, strerror(errno) ));
2416                         goto done;
2417                 }
2418         } else {
2419                 if (SMB_VFS_SYS_ACL_SET_FD(fsp, fsp->fd, the_acl) == -1) {
2420                         /*
2421                          * Some systems allow all the above calls and only fail with no ACL support
2422                          * when attempting to apply the acl. HPUX with HFS is an example of this. JRA.
2423                          */
2424                         if (errno == ENOSYS)
2425                                 *pacl_set_support = False;
2426
2427 #ifdef ENOTSUP
2428                         if (errno == ENOTSUP)
2429                                 *pacl_set_support = False;
2430 #endif
2431
2432                         DEBUG(2,("set_canon_ace_list: sys_acl_set_file failed for file %s (%s).\n",
2433                                         fsp->fsp_name, strerror(errno) ));
2434                         goto done;
2435                 }
2436         }
2437
2438         ret = True;
2439
2440   done:
2441
2442         if (the_acl != NULL)
2443             SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
2444
2445         return ret;
2446 }
2447
2448 /****************************************************************************
2449  Find a particular canon_ace entry.
2450 ****************************************************************************/
2451
2452 static struct canon_ace *canon_ace_entry_for(struct canon_ace *list, SMB_ACL_TAG_T type, posix_id *id)
2453 {
2454         while (list) {
2455                 if (list->type == type && ((type != SMB_ACL_USER && type != SMB_ACL_GROUP) ||
2456                                 (type == SMB_ACL_USER  && id && id->uid == list->unix_ug.uid) ||
2457                                 (type == SMB_ACL_GROUP && id && id->gid == list->unix_ug.gid)))
2458                         break;
2459                 list = list->next;
2460         }
2461         return list;
2462 }
2463
2464 /****************************************************************************
2465  
2466 ****************************************************************************/
2467
2468 SMB_ACL_T free_empty_sys_acl(connection_struct *conn, SMB_ACL_T the_acl)
2469 {
2470         SMB_ACL_ENTRY_T entry;
2471
2472         if (!the_acl)
2473                 return NULL;
2474         if (SMB_VFS_SYS_ACL_GET_ENTRY(conn, the_acl, SMB_ACL_FIRST_ENTRY, &entry) != 1) {
2475                 SMB_VFS_SYS_ACL_FREE_ACL(conn, the_acl);
2476                 return NULL;
2477         }
2478         return the_acl;
2479 }
2480
2481 /****************************************************************************
2482  Convert a canon_ace to a generic 3 element permission - if possible.
2483 ****************************************************************************/
2484
2485 #define MAP_PERM(p,mask,result) (((p) & (mask)) ? (result) : 0 )
2486
2487 static BOOL convert_canon_ace_to_posix_perms( files_struct *fsp, canon_ace *file_ace_list, mode_t *posix_perms)
2488 {
2489         int snum = SNUM(fsp->conn);
2490         size_t ace_count = count_canon_ace_list(file_ace_list);
2491         canon_ace *ace_p;
2492         canon_ace *owner_ace = NULL;
2493         canon_ace *group_ace = NULL;
2494         canon_ace *other_ace = NULL;
2495         mode_t and_bits;
2496         mode_t or_bits;
2497
2498         if (ace_count != 3) {
2499                 DEBUG(3,("convert_canon_ace_to_posix_perms: Too many ACE entries for file %s to convert to \
2500 posix perms.\n", fsp->fsp_name ));
2501                 return False;
2502         }
2503
2504         for (ace_p = file_ace_list; ace_p; ace_p = ace_p->next) {
2505                 if (ace_p->owner_type == UID_ACE)
2506                         owner_ace = ace_p;
2507                 else if (ace_p->owner_type == GID_ACE)
2508                         group_ace = ace_p;
2509                 else if (ace_p->owner_type == WORLD_ACE)
2510                         other_ace = ace_p;
2511         }
2512
2513         if (!owner_ace || !group_ace || !other_ace) {
2514                 DEBUG(3,("convert_canon_ace_to_posix_perms: Can't get standard entries for file %s.\n",
2515                                 fsp->fsp_name ));
2516                 return False;
2517         }
2518
2519         *posix_perms = (mode_t)0;
2520
2521         *posix_perms |= owner_ace->perms;
2522         *posix_perms |= MAP_PERM(group_ace->perms, S_IRUSR, S_IRGRP);
2523         *posix_perms |= MAP_PERM(group_ace->perms, S_IWUSR, S_IWGRP);
2524         *posix_perms |= MAP_PERM(group_ace->perms, S_IXUSR, S_IXGRP);
2525         *posix_perms |= MAP_PERM(other_ace->perms, S_IRUSR, S_IROTH);
2526         *posix_perms |= MAP_PERM(other_ace->perms, S_IWUSR, S_IWOTH);
2527         *posix_perms |= MAP_PERM(other_ace->perms, S_IXUSR, S_IXOTH);
2528
2529         /* The owner must have at least read access. */
2530
2531         *posix_perms |= S_IRUSR;
2532         if (fsp->is_directory)
2533                 *posix_perms |= (S_IWUSR|S_IXUSR);
2534
2535         /* If requested apply the masks. */
2536
2537         /* Get the initial bits to apply. */
2538
2539         if (fsp->is_directory) {
2540                 and_bits = lp_dir_security_mask(snum);
2541                 or_bits = lp_force_dir_security_mode(snum);
2542         } else {
2543                 and_bits = lp_security_mask(snum);
2544                 or_bits = lp_force_security_mode(snum);
2545         }
2546
2547         *posix_perms = (((*posix_perms) & and_bits)|or_bits);
2548
2549         DEBUG(10,("convert_canon_ace_to_posix_perms: converted u=%o,g=%o,w=%o to perm=0%o for file %s.\n",
2550                 (int)owner_ace->perms, (int)group_ace->perms, (int)other_ace->perms, (int)*posix_perms,
2551                 fsp->fsp_name ));
2552
2553         return True;
2554 }
2555
2556 /****************************************************************************
2557   Incoming NT ACLs on a directory can be split into a default POSIX acl (CI|OI|IO) and
2558   a normal POSIX acl. Win2k needs these split acls re-merging into one ACL
2559   with CI|OI set so it is inherited and also applies to the directory.
2560   Based on code from "Jim McDonough" <jmcd@us.ibm.com>.
2561 ****************************************************************************/
2562
2563 static size_t merge_default_aces( SEC_ACE *nt_ace_list, size_t num_aces)
2564 {
2565         size_t i, j;
2566
2567         for (i = 0; i < num_aces; i++) {
2568                 for (j = i+1; j < num_aces; j++) {
2569                         uint32 i_flags_ni = (nt_ace_list[i].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
2570                         uint32 j_flags_ni = (nt_ace_list[j].flags & ~SEC_ACE_FLAG_INHERITED_ACE);
2571                         BOOL i_inh = (nt_ace_list[i].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
2572                         BOOL j_inh = (nt_ace_list[j].flags & SEC_ACE_FLAG_INHERITED_ACE) ? True : False;
2573
2574                         /* We know the lower number ACE's are file entries. */
2575                         if ((nt_ace_list[i].type == nt_ace_list[j].type) &&
2576                                 (nt_ace_list[i].size == nt_ace_list[j].size) &&
2577                                 (nt_ace_list[i].info.mask == nt_ace_list[j].info.mask) &&
2578                                 sid_equal(&nt_ace_list[i].trustee, &nt_ace_list[j].trustee) &&
2579                                 (i_inh == j_inh) &&
2580                                 (i_flags_ni == 0) &&
2581                                 (j_flags_ni == (SEC_ACE_FLAG_OBJECT_INHERIT|
2582                                                   SEC_ACE_FLAG_CONTAINER_INHERIT|
2583                                                   SEC_ACE_FLAG_INHERIT_ONLY))) {
2584                                 /*
2585                                  * W2K wants to have access allowed zero access ACE's
2586                                  * at the end of the list. If the mask is zero, merge
2587                                  * the non-inherited ACE onto the inherited ACE.
2588                                  */
2589
2590                                 if (nt_ace_list[i].info.mask == 0) {
2591                                         nt_ace_list[j].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2592                                                                 (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2593                                         if (num_aces - i - 1 > 0)
2594                                                 memmove(&nt_ace_list[i], &nt_ace_list[i+1], (num_aces-i-1) *
2595                                                                 sizeof(SEC_ACE));
2596
2597                                         DEBUG(10,("merge_default_aces: Merging zero access ACE %u onto ACE %u.\n",
2598                                                 (unsigned int)i, (unsigned int)j ));
2599                                 } else {
2600                                         /*
2601                                          * These are identical except for the flags.
2602                                          * Merge the inherited ACE onto the non-inherited ACE.
2603                                          */
2604
2605                                         nt_ace_list[i].flags = SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2606                                                                 (i_inh ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2607                                         if (num_aces - j - 1 > 0)
2608                                                 memmove(&nt_ace_list[j], &nt_ace_list[j+1], (num_aces-j-1) *
2609                                                                 sizeof(SEC_ACE));
2610
2611                                         DEBUG(10,("merge_default_aces: Merging ACE %u onto ACE %u.\n",
2612                                                 (unsigned int)j, (unsigned int)i ));
2613                                 }
2614                                 num_aces--;
2615                                 break;
2616                         }
2617                 }
2618         }
2619
2620         return num_aces;
2621 }
2622 /****************************************************************************
2623  Reply to query a security descriptor from an fsp. If it succeeds it allocates
2624  the space for the return elements and returns the size needed to return the
2625  security descriptor. This should be the only external function needed for
2626  the UNIX style get ACL.
2627 ****************************************************************************/
2628
2629 size_t get_nt_acl(files_struct *fsp, uint32 security_info, SEC_DESC **ppdesc)
2630 {
2631         extern DOM_SID global_sid_Builtin_Administrators;
2632         extern DOM_SID global_sid_Builtin_Users;
2633         extern DOM_SID global_sid_Creator_Owner;
2634         extern DOM_SID global_sid_Creator_Group;
2635         connection_struct *conn = fsp->conn;
2636         SMB_STRUCT_STAT sbuf;
2637         SEC_ACE *nt_ace_list = NULL;
2638         DOM_SID owner_sid;
2639         DOM_SID group_sid;
2640         size_t sd_size = 0;
2641         SEC_ACL *psa = NULL;
2642         size_t num_acls = 0;
2643         size_t num_dir_acls = 0;
2644         size_t num_aces = 0;
2645         SMB_ACL_T posix_acl = NULL;
2646         SMB_ACL_T dir_acl = NULL;
2647         canon_ace *file_ace = NULL;
2648         canon_ace *dir_ace = NULL;
2649         size_t num_profile_acls = 0;
2650         struct pai_val *pal = NULL;
2651         SEC_DESC *psd = NULL;
2652
2653         *ppdesc = NULL;
2654
2655         DEBUG(10,("get_nt_acl: called for file %s\n", fsp->fsp_name ));
2656
2657         if(fsp->is_directory || fsp->fd == -1) {
2658
2659                 /* Get the stat struct for the owner info. */
2660                 if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0) {
2661                         return 0;
2662                 }
2663                 /*
2664                  * Get the ACL from the path.
2665                  */
2666
2667                 posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_ACCESS);
2668
2669                 /*
2670                  * If it's a directory get the default POSIX ACL.
2671                  */
2672
2673                 if(fsp->is_directory) {
2674                         dir_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fsp->fsp_name, SMB_ACL_TYPE_DEFAULT);
2675                         dir_acl = free_empty_sys_acl(conn, dir_acl);
2676                 }
2677
2678         } else {
2679
2680                 /* Get the stat struct for the owner info. */
2681                 if(SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0) {
2682                         return 0;
2683                 }
2684                 /*
2685                  * Get the ACL from the fd.
2686                  */
2687                 posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fsp->fd);
2688         }
2689
2690         DEBUG(5,("get_nt_acl : file ACL %s, directory ACL %s\n",
2691                         posix_acl ? "present" :  "absent",
2692                         dir_acl ? "present" :  "absent" ));
2693
2694         pal = load_inherited_info(fsp);
2695
2696         /*
2697          * Get the owner, group and world SIDs.
2698          */
2699
2700         if (lp_profile_acls(SNUM(fsp->conn))) {
2701                 /* For WXP SP1 the owner must be administrators. */
2702                 sid_copy(&owner_sid, &global_sid_Builtin_Administrators);
2703                 sid_copy(&group_sid, &global_sid_Builtin_Users);
2704                 num_profile_acls = 2;
2705         } else {
2706                 create_file_sids(&sbuf, &owner_sid, &group_sid);
2707         }
2708
2709         if ((security_info & DACL_SECURITY_INFORMATION) && !(security_info & PROTECTED_DACL_SECURITY_INFORMATION)) {
2710
2711                 /*
2712                  * In the optimum case Creator Owner and Creator Group would be used for
2713                  * the ACL_USER_OBJ and ACL_GROUP_OBJ entries, respectively, but this
2714                  * would lead to usability problems under Windows: The Creator entries
2715                  * are only available in browse lists of directories and not for files;
2716                  * additionally the identity of the owning group couldn't be determined.
2717                  * We therefore use those identities only for Default ACLs. 
2718                  */
2719
2720                 /* Create the canon_ace lists. */
2721                 file_ace = canonicalise_acl( fsp, posix_acl, &sbuf, &owner_sid, &group_sid, pal, SMB_ACL_TYPE_ACCESS );
2722
2723                 /* We must have *some* ACLS. */
2724         
2725                 if (count_canon_ace_list(file_ace) == 0) {
2726                         DEBUG(0,("get_nt_acl : No ACLs on file (%s) !\n", fsp->fsp_name ));
2727                         return 0;
2728                 }
2729
2730                 if (fsp->is_directory && dir_acl) {
2731                         dir_ace = canonicalise_acl(fsp, dir_acl, &sbuf,
2732                                         &global_sid_Creator_Owner,
2733                                         &global_sid_Creator_Group, pal, SMB_ACL_TYPE_DEFAULT );
2734                 }
2735
2736                 /*
2737                  * Create the NT ACE list from the canonical ace lists.
2738                  */
2739
2740                 {
2741                         canon_ace *ace;
2742                         int nt_acl_type;
2743                         int i;
2744
2745                         if (nt4_compatible_acls() && dir_ace) {
2746                                 /*
2747                                  * NT 4 chokes if an ACL contains an INHERIT_ONLY entry
2748                                  * but no non-INHERIT_ONLY entry for one SID. So we only
2749                                  * remove entries from the Access ACL if the
2750                                  * corresponding Default ACL entries have also been
2751                                  * removed. ACEs for CREATOR-OWNER and CREATOR-GROUP
2752                                  * are exceptions. We can do nothing
2753                                  * intelligent if the Default ACL contains entries that
2754                                  * are not also contained in the Access ACL, so this
2755                                  * case will still fail under NT 4.
2756                                  */
2757
2758                                 ace = canon_ace_entry_for(dir_ace, SMB_ACL_OTHER, NULL);
2759                                 if (ace && !ace->perms) {
2760                                         DLIST_REMOVE(dir_ace, ace);
2761                                         SAFE_FREE(ace);
2762
2763                                         ace = canon_ace_entry_for(file_ace, SMB_ACL_OTHER, NULL);
2764                                         if (ace && !ace->perms) {
2765                                                 DLIST_REMOVE(file_ace, ace);
2766                                                 SAFE_FREE(ace);
2767                                         }
2768                                 }
2769
2770                                 /*
2771                                  * WinNT doesn't usually have Creator Group
2772                                  * in browse lists, so we send this entry to
2773                                  * WinNT even if it contains no relevant
2774                                  * permissions. Once we can add
2775                                  * Creator Group to browse lists we can
2776                                  * re-enable this.
2777                                  */
2778
2779 #if 0
2780                                 ace = canon_ace_entry_for(dir_ace, SMB_ACL_GROUP_OBJ, NULL);
2781                                 if (ace && !ace->perms) {
2782                                         DLIST_REMOVE(dir_ace, ace);
2783                                         SAFE_FREE(ace);
2784                                 }
2785 #endif
2786
2787                                 ace = canon_ace_entry_for(file_ace, SMB_ACL_GROUP_OBJ, NULL);
2788                                 if (ace && !ace->perms) {
2789                                         DLIST_REMOVE(file_ace, ace);
2790                                         SAFE_FREE(ace);
2791                                 }
2792                         }
2793
2794                         num_acls = count_canon_ace_list(file_ace);
2795                         num_dir_acls = count_canon_ace_list(dir_ace);
2796
2797                         /* Allocate the ace list. */
2798                         if ((nt_ace_list = (SEC_ACE *)malloc((num_acls + num_profile_acls + num_dir_acls)* sizeof(SEC_ACE))) == NULL) {
2799                                 DEBUG(0,("get_nt_acl: Unable to malloc space for nt_ace_list.\n"));
2800                                 goto done;
2801                         }
2802
2803                         memset(nt_ace_list, '\0', (num_acls + num_dir_acls) * sizeof(SEC_ACE) );
2804                                                                                                         
2805                         /*
2806                          * Create the NT ACE list from the canonical ace lists.
2807                          */
2808         
2809                         ace = file_ace;
2810
2811                         for (i = 0; i < num_acls; i++, ace = ace->next) {
2812                                 SEC_ACCESS acc;
2813
2814                                 acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
2815                                 init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc, ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 0);
2816                         }
2817
2818                         /* The User must have access to a profile share - even if we can't map the SID. */
2819                         if (lp_profile_acls(SNUM(fsp->conn))) {
2820                                 SEC_ACCESS acc;
2821
2822                                 init_sec_access(&acc,FILE_GENERIC_ALL);
2823                                 init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED,
2824                                                 acc, 0);
2825                         }
2826
2827                         ace = dir_ace;
2828
2829                         for (i = 0; i < num_dir_acls; i++, ace = ace->next) {
2830                                 SEC_ACCESS acc;
2831         
2832                                 acc = map_canon_ace_perms(&nt_acl_type, &owner_sid, ace );
2833                                 init_sec_ace(&nt_ace_list[num_aces++], &ace->trustee, nt_acl_type, acc,
2834                                                 SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2835                                                 SEC_ACE_FLAG_INHERIT_ONLY|
2836                                                 (ace->inherited ? SEC_ACE_FLAG_INHERITED_ACE : 0));
2837                         }
2838
2839                         /* The User must have access to a profile share - even if we can't map the SID. */
2840                         if (lp_profile_acls(SNUM(fsp->conn))) {
2841                                 SEC_ACCESS acc;
2842                         
2843                                 init_sec_access(&acc,FILE_GENERIC_ALL);
2844                                 init_sec_ace(&nt_ace_list[num_aces++], &global_sid_Builtin_Users, SEC_ACE_TYPE_ACCESS_ALLOWED, acc,
2845                                                 SEC_ACE_FLAG_OBJECT_INHERIT|SEC_ACE_FLAG_CONTAINER_INHERIT|
2846                                                 SEC_ACE_FLAG_INHERIT_ONLY|0);
2847                         }
2848
2849                         /*
2850                          * Merge POSIX default ACLs and normal ACLs into one NT ACE.
2851                          * Win2K needs this to get the inheritance correct when replacing ACLs
2852                          * on a directory tree. Based on work by Jim @ IBM.
2853                          */
2854
2855                         num_aces = merge_default_aces(nt_ace_list, num_aces);
2856
2857                 }
2858
2859                 if (num_aces) {
2860                         if((psa = make_sec_acl( main_loop_talloc_get(), ACL_REVISION, num_aces, nt_ace_list)) == NULL) {
2861                                 DEBUG(0,("get_nt_acl: Unable to malloc space for acl.\n"));
2862                                 goto done;
2863                         }
2864                 }
2865         } /* security_info & DACL_SECURITY_INFORMATION */
2866
2867         psd = make_standard_sec_desc( main_loop_talloc_get(),
2868                         (security_info & OWNER_SECURITY_INFORMATION) ? &owner_sid : NULL,
2869                         (security_info & GROUP_SECURITY_INFORMATION) ? &group_sid : NULL,
2870                         psa,
2871                         &sd_size);
2872
2873         if(!psd) {
2874                 DEBUG(0,("get_nt_acl: Unable to malloc space for security descriptor.\n"));
2875                 sd_size = 0;
2876         } else {
2877                 /*
2878                  * Windows 2000: The DACL_PROTECTED flag in the security
2879                  * descriptor marks the ACL as non-inheriting, i.e., no
2880                  * ACEs from higher level directories propagate to this
2881                  * ACL. In the POSIX ACL model permissions are only
2882                  * inherited at file create time, so ACLs never contain
2883                  * any ACEs that are inherited dynamically. The DACL_PROTECTED
2884                  * flag doesn't seem to bother Windows NT.
2885                  */
2886                 if (get_protected_flag(pal))
2887                         psd->type |= SE_DESC_DACL_PROTECTED;
2888         }
2889
2890         if (psd->dacl)
2891                 dacl_sort_into_canonical_order(psd->dacl->ace, (unsigned int)psd->dacl->num_aces);
2892
2893         *ppdesc = psd;
2894
2895  done:
2896
2897         if (posix_acl)
2898                 SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
2899         if (dir_acl)
2900                 SMB_VFS_SYS_ACL_FREE_ACL(conn, dir_acl);
2901         free_canon_ace_list(file_ace);
2902         free_canon_ace_list(dir_ace);
2903         free_inherited_info(pal);
2904         SAFE_FREE(nt_ace_list);
2905
2906         return sd_size;
2907 }
2908
2909 /****************************************************************************
2910  Try to chown a file. We will be able to chown it under the following conditions.
2911
2912   1) If we have root privileges, then it will just work.
2913   2) If we have write permission to the file and dos_filemodes is set
2914      then allow chown to the currently authenticated user.
2915 ****************************************************************************/
2916
2917 static int try_chown(connection_struct *conn, const char *fname, uid_t uid, gid_t gid)
2918 {
2919         int ret;
2920         extern struct current_user current_user;
2921         files_struct *fsp;
2922         SMB_STRUCT_STAT st;
2923
2924         /* try the direct way first */
2925         ret = SMB_VFS_CHOWN(conn, fname, uid, gid);
2926         if (ret == 0)
2927                 return 0;
2928
2929         if(!CAN_WRITE(conn) || !lp_dos_filemode(SNUM(conn)))
2930                 return -1;
2931
2932         if (SMB_VFS_STAT(conn,fname,&st))
2933                 return -1;
2934
2935         fsp = open_file_fchmod(conn,fname,&st);
2936         if (!fsp)
2937                 return -1;
2938
2939         /* only allow chown to the current user. This is more secure,
2940            and also copes with the case where the SID in a take ownership ACL is
2941            a local SID on the users workstation 
2942         */
2943         uid = current_user.uid;
2944
2945         become_root();
2946         /* Keep the current file gid the same. */
2947         ret = SMB_VFS_FCHOWN(fsp, fsp->fd, uid, (gid_t)-1);
2948         unbecome_root();
2949
2950         close_file_fchmod(fsp);
2951
2952         return ret;
2953 }
2954
2955 /****************************************************************************
2956  Reply to set a security descriptor on an fsp. security_info_sent is the
2957  description of the following NT ACL.
2958  This should be the only external function needed for the UNIX style set ACL.
2959 ****************************************************************************/
2960
2961 BOOL set_nt_acl(files_struct *fsp, uint32 security_info_sent, SEC_DESC *psd)
2962 {
2963         connection_struct *conn = fsp->conn;
2964         uid_t user = (uid_t)-1;
2965         gid_t grp = (gid_t)-1;
2966         SMB_STRUCT_STAT sbuf;  
2967         DOM_SID file_owner_sid;
2968         DOM_SID file_grp_sid;
2969         canon_ace *file_ace_list = NULL;
2970         canon_ace *dir_ace_list = NULL;
2971         BOOL acl_perms = False;
2972         mode_t orig_mode = (mode_t)0;
2973         uid_t orig_uid;
2974         gid_t orig_gid;
2975         BOOL need_chown = False;
2976         extern struct current_user current_user;
2977
2978         DEBUG(10,("set_nt_acl: called for file %s\n", fsp->fsp_name ));
2979
2980         if (!CAN_WRITE(conn)) {
2981                 DEBUG(10,("set acl rejected on read-only share\n"));
2982                 return False;
2983         }
2984
2985         /*
2986          * Get the current state of the file.
2987          */
2988
2989         if(fsp->is_directory || fsp->fd == -1) {
2990                 if(SMB_VFS_STAT(fsp->conn,fsp->fsp_name, &sbuf) != 0)
2991                         return False;
2992         } else {
2993                 if(SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf) != 0)
2994                         return False;
2995         }
2996
2997         /* Save the original elements we check against. */
2998         orig_mode = sbuf.st_mode;
2999         orig_uid = sbuf.st_uid;
3000         orig_gid = sbuf.st_gid;
3001
3002         /*
3003          * Unpack the user/group/world id's.
3004          */
3005
3006         if (!unpack_nt_owners( &sbuf, &user, &grp, security_info_sent, psd))
3007                 return False;
3008
3009         /*
3010          * Do we need to chown ?
3011          */
3012
3013         if (((user != (uid_t)-1) && (orig_uid != user)) || (( grp != (gid_t)-1) && (orig_gid != grp)))
3014                 need_chown = True;
3015
3016         /*
3017          * Chown before setting ACL only if we don't change the user, or
3018          * if we change to the current user, but not if we want to give away
3019          * the file.
3020          */
3021
3022         if (need_chown && (user == (uid_t)-1 || user == current_user.uid)) {
3023
3024                 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
3025                                 fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
3026
3027                 if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
3028                         DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
3029                                 fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
3030                         return False;
3031                 }
3032
3033                 /*
3034                  * Recheck the current state of the file, which may have changed.
3035                  * (suid/sgid bits, for instance)
3036                  */
3037
3038                 if(fsp->is_directory) {
3039                         if(SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf) != 0) {
3040                                 return False;
3041                         }
3042                 } else {
3043
3044                         int ret;
3045     
3046                         if(fsp->fd == -1)
3047                                 ret = SMB_VFS_STAT(fsp->conn, fsp->fsp_name, &sbuf);
3048                         else
3049                                 ret = SMB_VFS_FSTAT(fsp,fsp->fd,&sbuf);
3050   
3051                         if(ret != 0)
3052                                 return False;
3053                 }
3054
3055                 /* Save the original elements we check against. */
3056                 orig_mode = sbuf.st_mode;
3057                 orig_uid = sbuf.st_uid;
3058                 orig_gid = sbuf.st_gid;
3059
3060                 /* We did it, don't try again */
3061                 need_chown = False;
3062         }
3063
3064         create_file_sids(&sbuf, &file_owner_sid, &file_grp_sid);
3065
3066         acl_perms = unpack_canon_ace( fsp, &sbuf, &file_owner_sid, &file_grp_sid,
3067                                                                         &file_ace_list, &dir_ace_list, security_info_sent, psd);
3068
3069         /* Ignore W2K traverse DACL set. */
3070         if (file_ace_list || dir_ace_list) {
3071
3072                 if (!acl_perms) {
3073                         DEBUG(3,("set_nt_acl: cannot set permissions\n"));
3074                         free_canon_ace_list(file_ace_list);
3075                         free_canon_ace_list(dir_ace_list); 
3076                         return False;
3077                 }
3078
3079                 /*
3080                  * Only change security if we got a DACL.
3081                  */
3082
3083                 if((security_info_sent & DACL_SECURITY_INFORMATION) && (psd->dacl != NULL)) {
3084
3085                         BOOL acl_set_support = False;
3086                         BOOL ret = False;
3087
3088                         /*
3089                          * Try using the POSIX ACL set first. Fall back to chmod if
3090                          * we have no ACL support on this filesystem.
3091                          */
3092
3093                         if (acl_perms && file_ace_list) {
3094                                 ret = set_canon_ace_list(fsp, file_ace_list, False, &acl_set_support);
3095                                 if (acl_set_support && ret == False) {
3096                                         DEBUG(3,("set_nt_acl: failed to set file acl on file %s (%s).\n", fsp->fsp_name, strerror(errno) ));
3097                                         free_canon_ace_list(file_ace_list);
3098                                         free_canon_ace_list(dir_ace_list); 
3099                                         return False;
3100                                 }
3101                         }
3102
3103                         if (acl_perms && acl_set_support && fsp->is_directory) {
3104                                 if (dir_ace_list) {
3105                                         if (!set_canon_ace_list(fsp, dir_ace_list, True, &acl_set_support)) {
3106                                                 DEBUG(3,("set_nt_acl: failed to set default acl on directory %s (%s).\n", fsp->fsp_name, strerror(errno) ));
3107                                                 free_canon_ace_list(file_ace_list);
3108                                                 free_canon_ace_list(dir_ace_list); 
3109                                                 return False;
3110                                         }
3111                                 } else {
3112
3113                                         /*
3114                                          * No default ACL - delete one if it exists.
3115                                          */
3116
3117                                         if (SMB_VFS_SYS_ACL_DELETE_DEF_FILE(conn, fsp->fsp_name) == -1) {
3118                                                 DEBUG(3,("set_nt_acl: sys_acl_delete_def_file failed (%s)\n", strerror(errno)));
3119                                                 free_canon_ace_list(file_ace_list);
3120                                                 free_canon_ace_list(dir_ace_list);
3121                                                 return False;
3122                                         }
3123                                 }
3124                         }
3125
3126                         if (acl_set_support)
3127                                 store_inheritance_attributes(fsp, file_ace_list, dir_ace_list,
3128                                                 (psd->type & SE_DESC_DACL_PROTECTED) ? True : False);
3129
3130                         /*
3131                          * If we cannot set using POSIX ACLs we fall back to checking if we need to chmod.
3132                          */
3133
3134                         if(!acl_set_support && acl_perms) {
3135                                 mode_t posix_perms;
3136
3137                                 if (!convert_canon_ace_to_posix_perms( fsp, file_ace_list, &posix_perms)) {
3138                                         free_canon_ace_list(file_ace_list);
3139                                         free_canon_ace_list(dir_ace_list);
3140                                         DEBUG(3,("set_nt_acl: failed to convert file acl to posix permissions for file %s.\n",
3141                                                 fsp->fsp_name ));
3142                                         return False;
3143                                 }
3144
3145                                 if (orig_mode != posix_perms) {
3146
3147                                         DEBUG(3,("set_nt_acl: chmod %s. perms = 0%o.\n",
3148                                                 fsp->fsp_name, (unsigned int)posix_perms ));
3149
3150                                         if(SMB_VFS_CHMOD(conn,fsp->fsp_name, posix_perms) == -1) {
3151                                                 DEBUG(3,("set_nt_acl: chmod %s, 0%o failed. Error = %s.\n",
3152                                                                 fsp->fsp_name, (unsigned int)posix_perms, strerror(errno) ));
3153                                                 free_canon_ace_list(file_ace_list);
3154                                                 free_canon_ace_list(dir_ace_list);
3155                                                 return False;
3156                                         }
3157                                 }
3158                         }
3159                 }
3160
3161                 free_canon_ace_list(file_ace_list);
3162                 free_canon_ace_list(dir_ace_list); 
3163         }
3164
3165         /* Any chown pending? */
3166         if (need_chown) {
3167
3168                 DEBUG(3,("set_nt_acl: chown %s. uid = %u, gid = %u.\n",
3169                         fsp->fsp_name, (unsigned int)user, (unsigned int)grp ));
3170
3171                 if(try_chown( fsp->conn, fsp->fsp_name, user, grp) == -1) {
3172                         DEBUG(3,("set_nt_acl: chown %s, %u, %u failed. Error = %s.\n",
3173                                 fsp->fsp_name, (unsigned int)user, (unsigned int)grp, strerror(errno) ));
3174                         return False;
3175                 }
3176         }
3177
3178         return True;
3179 }
3180
3181 /****************************************************************************
3182  Get the actual group bits stored on a file with an ACL. Has no effect if
3183  the file has no ACL. Needed in dosmode code where the stat() will return
3184  the mask bits, not the real group bits, for a file with an ACL.
3185 ****************************************************************************/
3186
3187 int get_acl_group_bits( connection_struct *conn, const char *fname, mode_t *mode )
3188 {
3189         int entry_id = SMB_ACL_FIRST_ENTRY;
3190         SMB_ACL_ENTRY_T entry;
3191         SMB_ACL_T posix_acl;
3192
3193         posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, fname, SMB_ACL_TYPE_ACCESS);
3194         if (posix_acl == (SMB_ACL_T)NULL)
3195                 return -1;
3196
3197         while (SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
3198                 SMB_ACL_TAG_T tagtype;
3199                 SMB_ACL_PERMSET_T permset;
3200
3201                 /* get_next... */
3202                 if (entry_id == SMB_ACL_FIRST_ENTRY)
3203                         entry_id = SMB_ACL_NEXT_ENTRY;
3204
3205                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) ==-1)
3206                         return -1;
3207
3208                 if (tagtype == SMB_ACL_GROUP_OBJ) {
3209                         if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1) {
3210                                 return -1;
3211                         } else {
3212                                 *mode &= ~(S_IRGRP|S_IWGRP|S_IXGRP);
3213                                 *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_READ) ? S_IRGRP : 0);
3214                                 *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_WRITE) ? S_IWGRP : 0);
3215                                 *mode |= (SMB_VFS_SYS_ACL_GET_PERM(conn, permset, SMB_ACL_EXECUTE) ? S_IXGRP : 0);
3216                                 return 0;;
3217                         }
3218                 }
3219         }
3220         return -1;
3221 }
3222
3223 /****************************************************************************
3224  Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3225  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3226 ****************************************************************************/
3227
3228 static int chmod_acl_internals( connection_struct *conn, SMB_ACL_T posix_acl, mode_t mode)
3229 {
3230         int entry_id = SMB_ACL_FIRST_ENTRY;
3231         SMB_ACL_ENTRY_T entry;
3232         int num_entries = 0;
3233
3234         while ( SMB_VFS_SYS_ACL_GET_ENTRY(conn, posix_acl, entry_id, &entry) == 1) {
3235                 SMB_ACL_TAG_T tagtype;
3236                 SMB_ACL_PERMSET_T permset;
3237                 mode_t perms;
3238
3239                 /* get_next... */
3240                 if (entry_id == SMB_ACL_FIRST_ENTRY)
3241                         entry_id = SMB_ACL_NEXT_ENTRY;
3242
3243                 if (SMB_VFS_SYS_ACL_GET_TAG_TYPE(conn, entry, &tagtype) == -1)
3244                         return -1;
3245
3246                 if (SMB_VFS_SYS_ACL_GET_PERMSET(conn, entry, &permset) == -1)
3247                         return -1;
3248
3249                 num_entries++;
3250
3251                 switch(tagtype) {
3252                         case SMB_ACL_USER_OBJ:
3253                                 perms = unix_perms_to_acl_perms(mode, S_IRUSR, S_IWUSR, S_IXUSR);
3254                                 break;
3255                         case SMB_ACL_GROUP_OBJ:
3256                                 perms = unix_perms_to_acl_perms(mode, S_IRGRP, S_IWGRP, S_IXGRP);
3257                                 break;
3258                         case SMB_ACL_MASK:
3259                                 /*
3260                                  * FIXME: The ACL_MASK entry permissions should really be set to
3261                                  * the union of the permissions of all ACL_USER,
3262                                  * ACL_GROUP_OBJ, and ACL_GROUP entries. That's what
3263                                  * acl_calc_mask() does, but Samba ACLs doesn't provide it.
3264                                  */
3265                                 perms = S_IRUSR|S_IWUSR|S_IXUSR;
3266                                 break;
3267                         case SMB_ACL_OTHER:
3268                                 perms = unix_perms_to_acl_perms(mode, S_IROTH, S_IWOTH, S_IXOTH);
3269                                 break;
3270                         default:
3271                                 continue;
3272                 }
3273
3274                 if (map_acl_perms_to_permset(conn, perms, &permset) == -1)
3275                         return -1;
3276
3277                 if (SMB_VFS_SYS_ACL_SET_PERMSET(conn, entry, permset) == -1)
3278                         return -1;
3279         }
3280
3281         /*
3282          * If this is a simple 3 element ACL or no elements then it's a standard
3283          * UNIX permission set. Just use chmod...       
3284          */
3285
3286         if ((num_entries == 3) || (num_entries == 0))
3287                 return -1;
3288
3289         return 0;
3290 }
3291
3292 /****************************************************************************
3293  Get the access ACL of FROM, do a chmod by setting the ACL USER_OBJ,
3294  GROUP_OBJ and OTHER bits in an ACL and set the mask to rwx. Set the
3295  resulting ACL on TO.  Note that name is in UNIX character set.
3296 ****************************************************************************/
3297
3298 static int copy_access_acl(connection_struct *conn, const char *from, const char *to, mode_t mode)
3299 {
3300         SMB_ACL_T posix_acl = NULL;
3301         int ret = -1;
3302
3303         if ((posix_acl = SMB_VFS_SYS_ACL_GET_FILE(conn, from, SMB_ACL_TYPE_ACCESS)) == NULL)
3304                 return -1;
3305
3306         if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
3307                 goto done;
3308
3309         ret = SMB_VFS_SYS_ACL_SET_FILE(conn, to, SMB_ACL_TYPE_ACCESS, posix_acl);
3310
3311  done:
3312
3313         SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
3314         return ret;
3315 }
3316
3317 /****************************************************************************
3318  Do a chmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3319  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3320  Note that name is in UNIX character set.
3321 ****************************************************************************/
3322
3323 int chmod_acl(connection_struct *conn, const char *name, mode_t mode)
3324 {
3325         return copy_access_acl(conn, name, name, mode);
3326 }
3327
3328 /****************************************************************************
3329  If "inherit permissions" is set and the parent directory has no default
3330  ACL but it does have an Access ACL, inherit this Access ACL to file name.
3331 ****************************************************************************/
3332
3333 int inherit_access_acl(connection_struct *conn, const char *name, mode_t mode)
3334 {
3335         pstring dirname;
3336         pstrcpy(dirname, parent_dirname(name));
3337
3338         if (!lp_inherit_perms(SNUM(conn)) || directory_has_default_acl(conn, dirname))
3339                 return 0;
3340
3341         return copy_access_acl(conn, dirname, name, mode);
3342 }
3343
3344 /****************************************************************************
3345  Do an fchmod by setting the ACL USER_OBJ, GROUP_OBJ and OTHER bits in an ACL
3346  and set the mask to rwx. Needed to preserve complex ACLs set by NT.
3347 ****************************************************************************/
3348
3349 int fchmod_acl(files_struct *fsp, int fd, mode_t mode)
3350 {
3351         connection_struct *conn = fsp->conn;
3352         SMB_ACL_T posix_acl = NULL;
3353         int ret = -1;
3354
3355         if ((posix_acl = SMB_VFS_SYS_ACL_GET_FD(fsp, fd)) == NULL)
3356                 return -1;
3357
3358         if ((ret = chmod_acl_internals(conn, posix_acl, mode)) == -1)
3359                 goto done;
3360
3361         ret = SMB_VFS_SYS_ACL_SET_FD(fsp, fd, posix_acl);
3362
3363   done:
3364
3365         SMB_VFS_SYS_ACL_FREE_ACL(conn, posix_acl);
3366         return ret;
3367 }
3368
3369 /****************************************************************************
3370  Check for an existing default POSIX ACL on a directory.
3371 ****************************************************************************/
3372
3373 BOOL directory_has_default_acl(connection_struct *conn, const char *fname)
3374 {
3375         SMB_ACL_T dir_acl = SMB_VFS_SYS_ACL_GET_FILE( conn, fname, SMB_ACL_TYPE_DEFAULT);
3376         BOOL has_acl = False;
3377         SMB_ACL_ENTRY_T entry;
3378
3379         if (dir_acl != NULL && (SMB_VFS_SYS_ACL_GET_ENTRY(conn, dir_acl, SMB_ACL_FIRST_ENTRY, &entry) == 1))
3380                 has_acl = True;
3381
3382         if (dir_acl)
3383                 SMB_VFS_SYS_ACL_FREE_ACL(conn, dir_acl);
3384         return has_acl;
3385 }