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