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