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