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